| bavarian-rank-engine | ||
| LICENSE | ||
| README.md | ||
Bavarian Rank Engine
Ein WordPress-Plugin für AI-gestützte Meta-Beschreibungen, GEO-optimierte Strukturdaten, llms.txt und KI-Crawler-Management — entwickelt von Donau2Space.
Was ist das Plugin?
Bavarian Rank Engine (BRE) ist ein All-in-One-Plugin für SEO und GEO (Generative Engine Optimization). Es verbindet WordPress mit führenden KI-Anbietern, um Meta-Beschreibungen vollautomatisch beim Veröffentlichen eines Beitrags zu generieren, reichert Seiten mit schema.org-Strukturdaten an, stellt einen maschinenlesbaren Inhaltsindex unter /llms.txt bereit und ermöglicht die gezielte Steuerung von KI-Crawlern über robots.txt — alles aus einer einheitlichen Admin-Oberfläche heraus.
Das Plugin ist so konzipiert, dass es ohne Reibung neben Rank Math, Yoast SEO, AIOSEO und SEOPress arbeitet, deren native Meta-Felder beschreibt und bestehende Beschreibungen niemals überschreibt.
Features
AI Meta Generator
Generiert beim Veröffentlichen automatisch eine SEO-optimierte Meta-Beschreibung (150–160 Zeichen). Der Prompt ist vollständig anpassbar und unterstützt die Platzhalter {title}, {content}, {excerpt} und {language}. Die Sprache wird automatisch aus Polylang, WPML oder dem WordPress-Locale ermittelt und an die KI weitergegeben.
Generierte Beschreibungen werden sowohl in BREs eigenem Post-Meta-Feld _bre_meta_description als auch direkt im nativen Feld des aktiven SEO-Plugins gespeichert (Rank Math: rank_math_description, Yoast: _yoast_wpseo_metadesc, AIOSEO: _aioseo_description, SEOPress: _seopress_titles_desc).
Zwei Hooks stehen für Entwickler bereit:
bre_prompt(Filter): Erlaubt es, den fertigen Prompt vor dem API-Aufruf zu modifizieren — z. B. um ein Focus-Keyword anzuhängen.bre_meta_saved(Action): Wird nach dem Speichern einer Beschreibung gefeuert — z. B. für Synchronisation mit externen Systemen.
Fallback-Meta (FallbackMeta)
Wenn kein API-Key hinterlegt ist oder ein KI-Aufruf fehlschlägt, extrahiert FallbackMeta::extract() automatisch eine saubere 150–160-Zeichen-Beschreibung aus dem Post-Content. Der Extraktor schneidet bevorzugt an Satzgrenzen (., !, ?) ab und fällt erst dann auf Wortgrenzen und schließlich auf einen harten Schnitt mit Ellipse zurück. Kein HTML im Ergebnis.
Bulk Generator
Batch-Verarbeitung aller veröffentlichten Beiträge ohne Meta-Beschreibung. Der Bulk-Prozess läuft per wiederholtem AJAX-Request im Browser, verarbeitet 1–20 Beiträge pro Batch mit einem fest eingebautem 6-Sekunden-Delay zwischen Batches (Rate-Limiting). Jeder Beitrag wird bis zu dreimal versucht. Ein Live-Progress-Log und eine laufende Kostenabschätzung werden direkt in der Admin-UI angezeigt.
BulkQueue-Lock: Ein Transient-basierter Mutex (bre_bulk_running, TTL 15 Minuten) verhindert gleichzeitige Bulk-Runs — auch über mehrere Browser-Tabs oder Admin-Nutzer hinweg. Das Lock wird beim Start des ersten Batches gesetzt und beim letzten Batch oder manuell über einen Button freigegeben.
Schema.org Enhancer (GEO)
Gibt JSON-LD-Strukturdaten und Meta-Tags in wp_head aus. Jeder Typ ist individuell aktivierbar:
| Typ | Schema.org-Type | Besonderheit |
|---|---|---|
organization |
Organization |
Name, URL, Logo, sameAs-Links (Social) |
article_about |
Article |
Headline, Publish/Modified, Description, Publisher |
author |
Person |
Name, Autor-URL, optionaler Twitter-sameAs |
speakable |
WebPage + SpeakableSpecification |
CSS-Selektoren auf H1 und ersten Absatz |
breadcrumb |
BreadcrumbList |
Übersprungen wenn Rank Math oder Yoast aktiv |
ai_meta_tags |
— | <meta name="robots"> und <meta name="googlebot"> mit max-snippet:-1 |
Die eigenständige <meta name="description">-Ausgabe wird unterdrückt, wenn Rank Math, Yoast oder AIOSEO aktiv sind, um Doppelausgaben zu vermeiden.
llms.txt (mit ETag/Cache)
Bedient /llms.txt (und paginierte Folgedateien /llms-2.txt, /llms-3.txt ...) über einen parse_request-Hook mit Priorität 1. Der Inhalt wird via WordPress-Transients gecacht und beim Speichern der Einstellungen automatisch invalidiert. HTTP-Caching-Header werden korrekt gesetzt:
ETag: "md5(content)"— HTTP 304 bei übereinstimmendem If-None-MatchLast-Modified:basierend auf dem neuestenpost_modified_gmtin der DatenbankCache-Control: public, max-age=3600
Die llms.txt enthält: Titel, Beschreibungs-Block vor dem Inhaltsverzeichnis, Featured-Links-Sektion, Content-Liste mit Datum, More-Sektion für Folgeseiten und optional einen Footer-Block.
Wenn Rank Math ebenfalls eine llms.txt ausliefern will, zeigt BRE einen Admin-Hinweis an, dass BRE Priorität hat.
robots.txt Manager
Hängt User-agent: <Bot>\nDisallow: /\n-Blöcke über den WordPress-Filter robots_txt an. Unterstützte Bots:
GPTBot, ClaudeBot, Google-Extended, PerplexityBot, CCBot, Applebot-Extended, Bytespider, DataForSeoBot, ImagesiftBot, omgili, Diffbot, FacebookBot, Amazonbot.
Jeder Bot kann einzeln über Checkboxen im Admin aktiviert oder deaktiviert werden.
CrawlerLog (Privacy-konform)
Loggt Besuche bekannter KI-Bots in eine eigene Datenbanktabelle ({prefix}bre_crawler_log):
| Spalte | Inhalt |
|---|---|
bot_name |
Name des Bots (z. B. GPTBot) |
ip_hash |
SHA-256-Hash der Besucher-IP — keine Original-IP wird gespeichert |
url |
Aufgerufene URL (max. 512 Zeichen) |
visited_at |
Zeitstempel des Besuchs |
Einträge älter als 90 Tage werden automatisch per Weekly-Cron bereinigt. Das Dashboard zeigt eine 30-Tage-Zusammenfassung pro Bot.
Meta Editor Box
Fügt einen Meta-Box-Block "Meta Description (BRE)" in den Post-Editor ein. Zeigt:
- Eine Quellen-Badge (KI generiert / Fallback / Manuell / Noch nicht generiert)
- Ein Textfeld mit
maxlength="160"und Live-Zeichenzähler - Einen "Mit KI neu generieren"-Button (nur sichtbar wenn ein API-Key hinterlegt ist), der inline eine neue Beschreibung abruft
SEO Analyse Widget
Eine Sidebar-Meta-Box im Post-Editor mit Live-Statistiken:
- Titel-Länge (Ziel: 60 Zeichen)
- Wortanzahl und geschätzte Lesezeit
- Überschriften-Hierarchie (H1–H6)
- Intern- und Externlinks-Zähler
- Inline-Warnungen (z. B. kein H2, keine internen Links)
Stats werden per JavaScript live aktualisiert, während der Redakteur schreibt.
Link-Analyse (Dashboard)
Ein AJAX-Bereich auf dem Dashboard, der identifiziert:
- Beiträge ohne einen einzigen internen Link
- Beiträge mit überdurchschnittlich vielen externen Links (konfigurierbarer Schwellenwert)
- Die Top-5-Pillar-Pages nach Anzahl eingehender interner Links
Ergebnisse werden 1 Stunde im Transient-Cache gehalten.
API-Key-Sicherheit (KeyVault)
Klartextkey → XOR(key, sha256(AUTH_KEY . SECURE_AUTH_KEY)) → base64 → "bre1:<base64>"
Die Klasse BavarianRankEngine\Helpers\KeyVault verschleiert API-Keys vor dem Schreiben in die WordPress-Optionstabelle:
- Ein 64-Zeichen-Hex-Salt wird aus den WordPress-Konstanten
AUTH_KEYundSECURE_AUTH_KEYviahash('sha256', AUTH_KEY . SECURE_AUTH_KEY)abgeleitet. - Der Klartext-Key wird byte-für-byte XOR-verknüpft (Salt wird bei Bedarf wiederholt).
- Das Ergebnis wird base64-kodiert und mit dem Präfix
bre1:gespeichert.
Kein OpenSSL, keine PHP-Extension außer der PHP-Standardbibliothek erforderlich.
Wichtiger Hinweis: XOR mit einem statischen, abgeleiteten Salt ist Verschleierung, keine kryptografische Verschlüsselung. Ein Angreifer mit Zugriff auf sowohl die Datenbank als auch wp-config.php kann den Key rekonstruieren. Für maximale Sicherheit können Keys als Konstanten in wp-config.php definiert werden:
define( 'BRE_OPENAI_KEY', 'sk-...' );
define( 'BRE_ANTHROPIC_KEY', 'sk-ant-...' );
define( 'BRE_GEMINI_KEY', 'AI...' );
define( 'BRE_GROK_KEY', 'xai-...' );
In der Admin-UI werden Keys stets maskiert angezeigt: ••••••Ab3c9 (letzte 5 Zeichen sichtbar).
Technischer Stack
| Komponente | Technologie |
|---|---|
| Backend | PHP 8.0+, WordPress Plugin API |
| Namespace | BavarianRankEngine\ |
| Architektur | Singleton-Core, Registry-Pattern für Provider, Feature-Klassen mit register() |
| Datenbank | WordPress Options API, wpdb (eigene Tabelle für CrawlerLog) |
| Caching | WordPress Transients (llms.txt, Link-Analyse, Bulk-Lock) |
| Frontend | Vanilla JS + jQuery (WordPress-integriert), kein Build-Step |
| I18n | .pot-File, Text-Domain bavarian-rank-engine |
| Tests | PHPUnit via Composer |
| Lizenz | GPL-2.0-or-later |
Besonderheiten
llms.txt mit ETag/Cache-Kontrolle
Vollständige HTTP-Caching-Semantik inklusive 304-Not-Modified-Unterstützung. Der Content-Hash wird per md5() als ETag generiert. Last-Modified basiert auf dem neuesten post_modified_gmt-Timestamp in der Datenbank. Der Transient-Cache wird bei jeder Einstellungsänderung automatisch invalidiert.
Bulk mit Rate-Limiting und Mutex-Lock Der 6-Sekunden-Inter-Batch-Delay und der 15-Minuten-Transient-Lock sind gezielt so implementiert, dass kein Produkt-API-Ratelimit ausgelöst wird und keine Race Conditions zwischen parallelen Admin-Sessions entstehen können.
Fallback-Meta mit Satzgrenzerkennung
FallbackMeta::extract() versucht aktiv, am Ende eines vollständigen Satzes (. , ! , ? ) zu schneiden, bevor es auf Wortgrenzen und schließlich auf einen harten Schnitt zurückfällt. Multibyte-safe via mb_substr / mb_strrpos.
CrawlerLog ohne Personenbezug IP-Adressen werden vor dem Speichern mit SHA-256 gehasht. Die Originale werden nie persistiert, was die Anforderungen der DSGVO an Datenminimierung erfüllt.
Keine Doppel-Ausgaben bei SEO-Plugin-Koexistenz
hasExistingMeta() prüft alle bekannten Meta-Felder (BRE, Rank Math, Yoast, AIOSEO, SEOPress) und überspringt Posts, die in einem davon bereits eine Beschreibung haben. outputMetaDescription() unterdrückt die eigene <meta name="description">-Ausgabe wenn ein kompatibles SEO-Plugin erkannt wird.
Installation für Entwickler
# Repository klonen
git clone https://git.donau2space.de/Michael/bavarianrankengine.git
cd bavarianrankengine
# Dev-Abhängigkeiten installieren (PHPUnit)
composer install
# Testsuite ausführen
php vendor/bin/phpunit --testdox
Für eine lokale WordPress-Instanz (z. B. mit wp-env oder Local by Flywheel):
# Plugin-Verzeichnis verlinken oder kopieren
ln -s $(pwd) /path/to/wordpress/wp-content/plugins/bavarian-rank-engine
# Plugin in WordPress aktivieren
wp plugin activate bavarian-rank-engine
Das Plugin hat keinen JavaScript-Build-Step. Alle Assets unter assets/ sind direkte JS/CSS-Dateien.
Contributing / Extending
Neuen KI-Provider hinzufügen
- Datei
includes/Providers/YourProvider.phperstellen undProviderInterfaceimplementieren:
namespace BavarianRankEngine\Providers;
class YourProvider implements ProviderInterface {
public function getId(): string { return 'yourprovider'; }
public function getName(): string { return 'Your Provider'; }
public function getModels(): array { return [ 'model-id' => 'Model Name' ]; }
public function testConnection( string $api_key ): array {
// Minimaler API-Call, gibt ['success' => bool, 'message' => string] zurück
}
public function generateText( string $prompt, string $api_key, string $model, int $max_tokens = 300 ): string {
// API aufrufen, Text zurückgeben, \RuntimeException bei Fehler werfen
}
}
- In
includes/Core.phpinregister_hooks()registrieren:
$registry->register( new Providers\YourProvider() );
Der Provider erscheint automatisch in allen Admin-Dropdowns.
Neues Feature hinzufügen
includes/Features/YourFeature.phpmit einerregister()-Methode erstellen, die WordPress-Hooks anhängt.require_once BRE_DIR . 'includes/Features/YourFeature.php';inCore::load_dependencies()ergänzen.( new Features\YourFeature() )->register();inCore::register_hooks()ergänzen.
Hooks für externe Nutzung
// Prompt vor dem API-Aufruf anpassen
add_filter( 'bre_prompt', function( string $prompt, \WP_Post $post ): string {
return $prompt . "\nFokus-Keyword: " . get_post_meta( $post->ID, 'focus_keyword', true );
}, 10, 2 );
// Nach dem Speichern einer Meta-Beschreibung reagieren
add_action( 'bre_meta_saved', function( int $post_id, string $description ): void {
my_external_sync( $post_id, $description );
}, 10, 2 );
Lizenz
GPL-2.0-or-later — siehe https://www.gnu.org/licenses/gpl-2.0.html
Copyright (c) 2025 Donau2Space