README.md aktualisiert
This commit is contained in:
parent
d31a4adc0b
commit
e476d71307
1 changed files with 266 additions and 2 deletions
268
README.md
268
README.md
|
|
@ -1,3 +1,267 @@
|
|||
# bavarianrankengine
|
||||
# Bavarian Rank Engine
|
||||
|
||||
All-in-One-Plugin für SEO und GEO
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
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` | — | `<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-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: <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:
|
||||
|
||||
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 `<meta name="description">`-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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue