From e476d71307f27775c92ab0a9672ccb0b7e281e72 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 22 Feb 2026 10:03:59 +0000 Subject: [PATCH] README.md aktualisiert --- README.md | 268 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 266 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 76f3035..bef157b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,267 @@ -# bavarianrankengine +# Bavarian Rank Engine -All-in-One-Plugin für SEO und GEO \ No newline at end of file +![PHP 8.0+](https://img.shields.io/badge/PHP-8.0%2B-blue) +![WordPress 6.0+](https://img.shields.io/badge/WordPress-6.0%2B-21759b) +![License: GPL-2.0](https://img.shields.io/badge/License-GPL--2.0--or--later-green) +![Version](https://img.shields.io/badge/Version-1.0.0-orange) + +Ein WordPress-Plugin für AI-gestützte Meta-Beschreibungen, GEO-optimierte Strukturdaten, llms.txt und KI-Crawler-Management — entwickelt von [Donau2Space](https://donau2space.de). + +--- + +## 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` | — | `` und `` mit `max-snippet:-1` | + +Die eigenständige ``-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-Match +- `Last-Modified:` basierend auf dem neuesten `post_modified_gmt` in der Datenbank +- `Cache-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: \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:" +``` + +Die Klasse `BavarianRankEngine\Helpers\KeyVault` verschleiert API-Keys vor dem Schreiben in die WordPress-Optionstabelle: + +1. Ein 64-Zeichen-Hex-Salt wird aus den WordPress-Konstanten `AUTH_KEY` und `SECURE_AUTH_KEY` via `hash('sha256', AUTH_KEY . SECURE_AUTH_KEY)` abgeleitet. +2. Der Klartext-Key wird byte-für-byte XOR-verknüpft (Salt wird bei Bedarf wiederholt). +3. 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: + +```php +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 ``-Ausgabe wenn ein kompatibles SEO-Plugin erkannt wird. + +--- + +## Installation für Entwickler + +```bash +# 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): + +```bash +# 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 + +1. Datei `includes/Providers/YourProvider.php` erstellen und `ProviderInterface` implementieren: + +```php +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 + } +} +``` + +2. In `includes/Core.php` in `register_hooks()` registrieren: + +```php +$registry->register( new Providers\YourProvider() ); +``` + +Der Provider erscheint automatisch in allen Admin-Dropdowns. + +### Neues Feature hinzufügen + +1. `includes/Features/YourFeature.php` mit einer `register()`-Methode erstellen, die WordPress-Hooks anhängt. +2. `require_once BRE_DIR . 'includes/Features/YourFeature.php';` in `Core::load_dependencies()` ergänzen. +3. `( new Features\YourFeature() )->register();` in `Core::register_hooks()` ergänzen. + +### Hooks für externe Nutzung + +```php +// 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](https://www.gnu.org/licenses/gpl-2.0.html) + +Copyright (c) 2025 [Donau2Space](https://donau2space.de)