release: v1.0.0
This commit is contained in:
parent
124504e11e
commit
d29d99c724
9 changed files with 105 additions and 105 deletions
82
README.de.md
82
README.de.md
|
|
@ -3,7 +3,7 @@
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
🇬🇧 [English version → README.md](README.md)
|
🇬🇧 [English version → README.md](README.md)
|
||||||
|
|
@ -56,7 +56,7 @@ Entwickelt in Passau, Bayern — für [Donau2Space](https://donau2space.de), ein
|
||||||
|
|
||||||
```
|
```
|
||||||
brezngeo/
|
brezngeo/
|
||||||
├── brezngeo.php # Plugin-Header, Konstanten (BRE_VERSION, BRE_DIR, BRE_URL)
|
├── brezngeo.php # Plugin-Header, Konstanten (BREZNGEO_VERSION, BREZNGEO_DIR, BREZNGEO_URL)
|
||||||
├── uninstall.php # Aufräumen bei Plugin-Löschung
|
├── uninstall.php # Aufräumen bei Plugin-Löschung
|
||||||
├── assets/
|
├── assets/
|
||||||
│ ├── admin.css # Gemeinsames Admin-Stylesheet
|
│ ├── admin.css # Gemeinsames Admin-Stylesheet
|
||||||
|
|
@ -64,7 +64,7 @@ brezngeo/
|
||||||
│ ├── bulk.js # Bulk-Generator AJAX-Loop + Progress-UI
|
│ ├── bulk.js # Bulk-Generator AJAX-Loop + Progress-UI
|
||||||
│ ├── editor-meta.js # Meta Editor Box: Live-Zähler, KI-Regen-Button
|
│ ├── editor-meta.js # Meta Editor Box: Live-Zähler, KI-Regen-Button
|
||||||
│ ├── geo-editor.js # GEO Block Editor: Generieren / Löschen Button
|
│ ├── geo-editor.js # GEO Block Editor: Generieren / Löschen Button
|
||||||
│ ├── geo-frontend.css # Minimales Stylesheet für .bre-geo auf dem Frontend
|
│ ├── geo-frontend.css # Minimales Stylesheet für .brezngeo-geo auf dem Frontend
|
||||||
│ ├── link-suggest.js # Interne Link-Vorschläge: Trigger, UI, Apply (Gutenberg + Classic)
|
│ ├── link-suggest.js # Interne Link-Vorschläge: Trigger, UI, Apply (Gutenberg + Classic)
|
||||||
│ └── seo-widget.js # SEO Analyse Widget: Live-Auswertung im Editor
|
│ └── seo-widget.js # SEO Analyse Widget: Live-Auswertung im Editor
|
||||||
├── includes/
|
├── includes/
|
||||||
|
|
@ -203,7 +203,7 @@ Batch-Verarbeitung aller veröffentlichten Beiträge ohne Meta-Beschreibung. Lä
|
||||||
|
|
||||||
### Crawler Log
|
### Crawler Log
|
||||||
|
|
||||||
Loggt Besuche bekannter KI-Bots in der Tabelle `{prefix}bre_crawler_log` (bot_name, ip_hash SHA-256, url, visited_at). Einträge älter als 90 Tage werden automatisch bereinigt. Dashboard zeigt 30-Tage-Zusammenfassung.
|
Loggt Besuche bekannter KI-Bots in der Tabelle `{prefix}brezngeo_crawler_log` (bot_name, ip_hash SHA-256, url, visited_at). Einträge älter als 90 Tage werden automatisch bereinigt. Dashboard zeigt 30-Tage-Zusammenfassung.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -213,14 +213,14 @@ Loggt Besuche bekannter KI-Bots in der Tabelle `{prefix}bre_crawler_log` (bot_na
|
||||||
|
|
||||||
| Option-Key | Inhalt |
|
| Option-Key | Inhalt |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `bre_settings` | Aktiver Provider, API-Keys (verschleiert), Modell-Auswahl, Token-Kosten, `ai_enabled`-Flag |
|
| `brezngeo_settings` | Aktiver Provider, API-Keys (verschleiert), Modell-Auswahl, Token-Kosten, `ai_enabled`-Flag |
|
||||||
| `bre_meta_settings` | Meta Generator: Auto-Modus, Post-Types, Token-Modus, Prompt |
|
| `brezngeo_meta_settings` | Meta Generator: Auto-Modus, Post-Types, Token-Modus, Prompt |
|
||||||
| `bre_schema_settings` | Schema.org: aktivierte Typen, Organization sameAs-URLs |
|
| `brezngeo_schema_settings` | Schema.org: aktivierte Typen, Organization sameAs-URLs |
|
||||||
| `bre_geo_settings` | GEO Block: Modus, Position, Labels, CSS, Prompt, Farbschema |
|
| `brezngeo_geo_settings` | GEO Block: Modus, Position, Labels, CSS, Prompt, Farbschema |
|
||||||
| `bre_robots_settings` | robots.txt: blockierte Bots |
|
| `brezngeo_robots_settings` | robots.txt: blockierte Bots |
|
||||||
| `bre_llms_settings` | llms.txt: Titel, Beschreibung, Featured-Links, Footer, Seitenanzahl |
|
| `brezngeo_llms_settings` | llms.txt: Titel, Beschreibung, Featured-Links, Footer, Seitenanzahl |
|
||||||
| `bre_usage_stats` | Akkumulierte Token-Nutzung: `tokens_in`, `tokens_out`, `count` |
|
| `brezngeo_usage_stats` | Akkumulierte Token-Nutzung: `tokens_in`, `tokens_out`, `count` |
|
||||||
| `bre_first_activated` | Unix-Timestamp der Erstaktivierung (für Welcome Notice) |
|
| `brezngeo_first_activated` | Unix-Timestamp der Erstaktivierung (für Welcome Notice) |
|
||||||
|
|
||||||
### Post Meta (wp_postmeta)
|
### Post Meta (wp_postmeta)
|
||||||
|
|
||||||
|
|
@ -237,13 +237,13 @@ Loggt Besuche bekannter KI-Bots in der Tabelle `{prefix}bre_crawler_log` (bot_na
|
||||||
|
|
||||||
| Transient | TTL | Zweck |
|
| Transient | TTL | Zweck |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `bre_llms_cache_{n}` | 1 Stunde | Gecachter llms.txt Inhalt je Seite |
|
| `brezngeo_llms_cache_{n}` | 1 Stunde | Gecachter llms.txt Inhalt je Seite |
|
||||||
| `bre_link_analysis` | 1 Stunde | Dashboard Link-Analyse Ergebnis |
|
| `brezngeo_link_analysis` | 1 Stunde | Dashboard Link-Analyse Ergebnis |
|
||||||
| `bre_bulk_running` | 15 Minuten | Mutex-Lock für den Bulk Generator |
|
| `brezngeo_bulk_running` | 15 Minuten | Mutex-Lock für den Bulk Generator |
|
||||||
| `bre_meta_stats` | 5 Minuten | Dashboard Meta-Coverage-Abfrage |
|
| `brezngeo_meta_stats` | 5 Minuten | Dashboard Meta-Coverage-Abfrage |
|
||||||
| `bre_crawler_summary` | 5 Minuten | Dashboard Crawler-Zusammenfassung (letzte 30 Tage) |
|
| `brezngeo_crawler_summary` | 5 Minuten | Dashboard Crawler-Zusammenfassung (letzte 30 Tage) |
|
||||||
|
|
||||||
> **Uninstall:** `uninstall.php` löscht `bre_settings` und `_bre_meta_description` für alle Posts. Die übrigen Option-Keys und die `bre_crawler_log`-Tabelle müssen manuell gelöscht werden.
|
> **Uninstall:** `uninstall.php` löscht `brezngeo_settings` und `_bre_meta_description` für alle Posts. Die übrigen Option-Keys und die `brezngeo_crawler_log`-Tabelle müssen manuell gelöscht werden.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -260,10 +260,10 @@ Kein `openssl_*` oder externe Extension nötig — läuft auf jeder PHP 8.0+ Ins
|
||||||
**Sicherheitsgrenzen:** XOR mit statischem Salt ist Verschleierung, keine kryptografische Verschlüsselung. Für maximale Sicherheit können Keys als `wp-config.php`-Konstanten definiert werden:
|
**Sicherheitsgrenzen:** XOR mit statischem Salt ist Verschleierung, keine kryptografische Verschlüsselung. Für maximale Sicherheit können Keys als `wp-config.php`-Konstanten definiert werden:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
define( 'BRE_OPENAI_KEY', 'sk-...' );
|
define( 'BREZNGEO_OPENAI_KEY', 'sk-...' );
|
||||||
define( 'BRE_ANTHROPIC_KEY', 'sk-ant-...' );
|
define( 'BREZNGEO_ANTHROPIC_KEY', 'sk-ant-...' );
|
||||||
define( 'BRE_GEMINI_KEY', 'AI...' );
|
define( 'BREZNGEO_GEMINI_KEY', 'AI...' );
|
||||||
define( 'BRE_GROK_KEY', 'xai-...' );
|
define( 'BREZNGEO_GROK_KEY', 'xai-...' );
|
||||||
```
|
```
|
||||||
|
|
||||||
### CSRF-Schutz und Capability Checks
|
### CSRF-Schutz und Capability Checks
|
||||||
|
|
@ -271,7 +271,7 @@ define( 'BRE_GROK_KEY', 'xai-...' );
|
||||||
Jeder AJAX-Handler ohne Ausnahme:
|
Jeder AJAX-Handler ohne Ausnahme:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
check_ajax_referer( 'bre_admin', 'nonce' );
|
check_ajax_referer( 'brezngeo_admin', 'nonce' );
|
||||||
if ( ! current_user_can( 'manage_options' ) ) {
|
if ( ! current_user_can( 'manage_options' ) ) {
|
||||||
wp_send_json_error( 'Unauthorized', 403 );
|
wp_send_json_error( 'Unauthorized', 403 );
|
||||||
}
|
}
|
||||||
|
|
@ -304,19 +304,19 @@ Neuen Provider hinzufügen: `ProviderInterface` implementieren, in `Core.php` vi
|
||||||
|
|
||||||
## Hooks & Erweiterbarkeit
|
## Hooks & Erweiterbarkeit
|
||||||
|
|
||||||
### `bre_prompt` (Filter)
|
### `brezngeo_prompt` (Filter)
|
||||||
|
|
||||||
```php
|
```php
|
||||||
add_filter( 'bre_prompt', function( string $prompt, WP_Post $post ): string {
|
add_filter( 'brezngeo_prompt', function( string $prompt, WP_Post $post ): string {
|
||||||
$keyword = get_post_meta( $post->ID, 'focus_keyword', true );
|
$keyword = get_post_meta( $post->ID, 'focus_keyword', true );
|
||||||
return $keyword ? $prompt . "\nFokus-Keyword: {$keyword}" : $prompt;
|
return $keyword ? $prompt . "\nFokus-Keyword: {$keyword}" : $prompt;
|
||||||
}, 10, 2 );
|
}, 10, 2 );
|
||||||
```
|
```
|
||||||
|
|
||||||
### `bre_meta_saved` (Action)
|
### `brezngeo_meta_saved` (Action)
|
||||||
|
|
||||||
```php
|
```php
|
||||||
add_action( 'bre_meta_saved', function( int $post_id, string $description ): void {
|
add_action( 'brezngeo_meta_saved', function( int $post_id, string $description ): void {
|
||||||
my_cdn_purge( get_permalink( $post_id ) );
|
my_cdn_purge( get_permalink( $post_id ) );
|
||||||
}, 10, 2 );
|
}, 10, 2 );
|
||||||
```
|
```
|
||||||
|
|
@ -329,20 +329,20 @@ Alle Endpunkte erfordern `manage_options` (kein `nopriv`).
|
||||||
|
|
||||||
| Action | Handler | Beschreibung |
|
| Action | Handler | Beschreibung |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `bre_regen_meta` | `MetaEditorBox::ajax_regen` | Meta-Beschreibung für einzelnen Post neu generieren |
|
| `brezngeo_regen_meta` | `MetaEditorBox::ajax_regen` | Meta-Beschreibung für einzelnen Post neu generieren |
|
||||||
| `bre_test_connection` | `ProviderPage::ajax_test_connection` | API-Key und Verbindung testen |
|
| `brezngeo_test_connection` | `ProviderPage::ajax_test_connection` | API-Key und Verbindung testen |
|
||||||
| `bre_get_default_prompt` | `ProviderPage::ajax_get_default_prompt` | Standard-Prompt zurücksetzen |
|
| `brezngeo_get_default_prompt` | `ProviderPage::ajax_get_default_prompt` | Standard-Prompt zurücksetzen |
|
||||||
| `bre_link_analysis` | `LinkAnalysis::ajax_analyse` | Link-Analyse ausführen |
|
| `brezngeo_link_analysis` | `LinkAnalysis::ajax_analyse` | Link-Analyse ausführen |
|
||||||
| `bre_link_suggestions` | `LinkSuggest::ajax_suggest` | Top-10 interne Link-Vorschläge für aktuellen Beitrag zurückgeben |
|
| `brezngeo_link_suggestions` | `LinkSuggest::ajax_suggest` | Top-10 interne Link-Vorschläge für aktuellen Beitrag zurückgeben |
|
||||||
| `bre_geo_generate` | `GeoEditorBox::ajax_generate` | GEO Block generieren |
|
| `brezngeo_geo_generate` | `GeoEditorBox::ajax_generate` | GEO Block generieren |
|
||||||
| `bre_geo_clear` | `GeoEditorBox::ajax_clear` | GEO Block löschen |
|
| `brezngeo_geo_clear` | `GeoEditorBox::ajax_clear` | GEO Block löschen |
|
||||||
| `bre_llms_clear_cache` | `TxtPage::ajax_clear_cache` | llms.txt Cache leeren |
|
| `brezngeo_llms_clear_cache` | `TxtPage::ajax_clear_cache` | llms.txt Cache leeren |
|
||||||
| `bre_dismiss_llms_notice` | `LlmsTxt::ajax_dismiss_notice` | Rank-Math-Hinweis ausblenden |
|
| `brezngeo_dismiss_llms_notice` | `LlmsTxt::ajax_dismiss_notice` | Rank-Math-Hinweis ausblenden |
|
||||||
| `bre_dismiss_welcome` | `AdminMenu::ajax_dismiss_welcome` | Welcome Notice per User ausblenden |
|
| `brezngeo_dismiss_welcome` | `AdminMenu::ajax_dismiss_welcome` | Welcome Notice per User ausblenden |
|
||||||
| `bre_bulk_generate` | `MetaGenerator::ajaxBulkGenerate` | Nächsten Batch verarbeiten |
|
| `brezngeo_bulk_generate` | `MetaGenerator::ajaxBulkGenerate` | Nächsten Batch verarbeiten |
|
||||||
| `bre_bulk_stats` | `MetaGenerator::ajaxBulkStats` | Fortschritt abrufen |
|
| `brezngeo_bulk_stats` | `MetaGenerator::ajaxBulkStats` | Fortschritt abrufen |
|
||||||
| `bre_bulk_release` | `MetaGenerator::ajaxBulkRelease` | Mutex-Lock manuell freigeben |
|
| `brezngeo_bulk_release` | `MetaGenerator::ajaxBulkRelease` | Mutex-Lock manuell freigeben |
|
||||||
| `bre_bulk_status` | `MetaGenerator::ajaxBulkStatus` | Lock-Status prüfen |
|
| `brezngeo_bulk_status` | `MetaGenerator::ajaxBulkStatus` | Lock-Status prüfen |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
96
README.md
96
README.md
|
|
@ -3,7 +3,7 @@
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
🇩🇪 [Deutsche Version → README.de.md](README.de.md)
|
🇩🇪 [Deutsche Version → README.de.md](README.de.md)
|
||||||
|
|
@ -56,7 +56,7 @@ Built in Passau, Bavaria — for [Donau2Space](https://donau2space.de), a person
|
||||||
|
|
||||||
```
|
```
|
||||||
brezngeo/
|
brezngeo/
|
||||||
├── brezngeo.php # Plugin header, constants (BRE_VERSION, BRE_DIR, BRE_URL)
|
├── brezngeo.php # Plugin header, constants (BREZNGEO_VERSION, BREZNGEO_DIR, BREZNGEO_URL)
|
||||||
├── uninstall.php # Cleanup on plugin deletion
|
├── uninstall.php # Cleanup on plugin deletion
|
||||||
├── assets/
|
├── assets/
|
||||||
│ ├── admin.css # Shared admin stylesheet
|
│ ├── admin.css # Shared admin stylesheet
|
||||||
|
|
@ -64,7 +64,7 @@ brezngeo/
|
||||||
│ ├── bulk.js # Bulk generator AJAX loop + progress UI
|
│ ├── bulk.js # Bulk generator AJAX loop + progress UI
|
||||||
│ ├── editor-meta.js # Meta editor box: live counter, AI regen button
|
│ ├── editor-meta.js # Meta editor box: live counter, AI regen button
|
||||||
│ ├── geo-editor.js # GEO block editor: generate / clear button
|
│ ├── geo-editor.js # GEO block editor: generate / clear button
|
||||||
│ ├── geo-frontend.css # Minimal stylesheet for .bre-geo on frontend
|
│ ├── geo-frontend.css # Minimal stylesheet for .brezngeo-geo on frontend
|
||||||
│ ├── link-suggest.js # Internal link suggestions: trigger, UI, apply (Gutenberg + Classic)
|
│ ├── link-suggest.js # Internal link suggestions: trigger, UI, apply (Gutenberg + Classic)
|
||||||
│ └── seo-widget.js # SEO analysis widget: live evaluation in editor
|
│ └── seo-widget.js # SEO analysis widget: live evaluation in editor
|
||||||
├── includes/
|
├── includes/
|
||||||
|
|
@ -244,13 +244,13 @@ Batch processing of all published posts without a meta description. The process
|
||||||
- 6-second delay between batches (rate limiting against API limits)
|
- 6-second delay between batches (rate limiting against API limits)
|
||||||
- Up to 3 attempts per post
|
- Up to 3 attempts per post
|
||||||
- Live progress log and running cost estimate in the admin UI
|
- Live progress log and running cost estimate in the admin UI
|
||||||
- **Mutex lock via transient** (`bre_bulk_running`, TTL 15 minutes): prevents parallel runs across multiple browser tabs or admin users. The lock is set at start, automatically released after the last batch — or manually via button.
|
- **Mutex lock via transient** (`brezngeo_bulk_running`, TTL 15 minutes): prevents parallel runs across multiple browser tabs or admin users. The lock is set at start, automatically released after the last batch — or manually via button.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Crawler Log
|
### Crawler Log
|
||||||
|
|
||||||
Logs visits from known AI bots in the dedicated database table `{prefix}bre_crawler_log`:
|
Logs visits from known AI bots in the dedicated database table `{prefix}brezngeo_crawler_log`:
|
||||||
|
|
||||||
| Column | Type | Content |
|
| Column | Type | Content |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
|
@ -261,7 +261,7 @@ Logs visits from known AI bots in the dedicated database table `{prefix}bre_craw
|
||||||
|
|
||||||
**Why SHA-256 instead of plain-text IP?** The original IP is never stored. The hash satisfies the GDPR requirement of data minimization: bot patterns are identifiable (same hash = same IP), but tracing back to a person without the plain-text value is practically impossible.
|
**Why SHA-256 instead of plain-text IP?** The original IP is never stored. The hash satisfies the GDPR requirement of data minimization: bot patterns are identifiable (same hash = same IP), but tracing back to a person without the plain-text value is practically impossible.
|
||||||
|
|
||||||
Entries older than 90 days are automatically cleaned up via weekly cron (`bre_cleanup_crawler_log`). The dashboard shows a 30-day summary per bot.
|
Entries older than 90 days are automatically cleaned up via weekly cron (`brezngeo_cleanup_crawler_log`). The dashboard shows a 30-day summary per bot.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -294,7 +294,7 @@ AJAX widget on the plugin dashboard:
|
||||||
- Posts with an above-average number of external links
|
- Posts with an above-average number of external links
|
||||||
- Top-5 pillar pages by number of incoming internal links
|
- Top-5 pillar pages by number of incoming internal links
|
||||||
|
|
||||||
Results are cached for 1 hour in the transient cache (`bre_link_analysis`).
|
Results are cached for 1 hour in the transient cache (`brezngeo_link_analysis`).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -304,14 +304,14 @@ Results are cached for 1 hour in the transient cache (`bre_link_analysis`).
|
||||||
|
|
||||||
| Option Key | Content |
|
| Option Key | Content |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `bre_settings` | Active provider, API keys (obfuscated), model selection, token costs, `ai_enabled` flag |
|
| `brezngeo_settings` | Active provider, API keys (obfuscated), model selection, token costs, `ai_enabled` flag |
|
||||||
| `bre_meta_settings` | Meta generator: auto mode, post types, token mode, prompt |
|
| `brezngeo_meta_settings` | Meta generator: auto mode, post types, token mode, prompt |
|
||||||
| `bre_schema_settings` | Schema.org: enabled types, organization sameAs URLs |
|
| `brezngeo_schema_settings` | Schema.org: enabled types, organization sameAs URLs |
|
||||||
| `bre_geo_settings` | GEO block: mode, position, labels, CSS, prompt, color scheme |
|
| `brezngeo_geo_settings` | GEO block: mode, position, labels, CSS, prompt, color scheme |
|
||||||
| `bre_robots_settings` | robots.txt: blocked bots |
|
| `brezngeo_robots_settings` | robots.txt: blocked bots |
|
||||||
| `bre_llms_settings` | llms.txt: title, description, featured links, footer, page count |
|
| `brezngeo_llms_settings` | llms.txt: title, description, featured links, footer, page count |
|
||||||
| `bre_usage_stats` | Accumulated token usage: `tokens_in`, `tokens_out`, `count` |
|
| `brezngeo_usage_stats` | Accumulated token usage: `tokens_in`, `tokens_out`, `count` |
|
||||||
| `bre_first_activated` | Unix timestamp of first activation (used by welcome notice) |
|
| `brezngeo_first_activated` | Unix timestamp of first activation (used by welcome notice) |
|
||||||
|
|
||||||
### Post Meta (wp_postmeta)
|
### Post Meta (wp_postmeta)
|
||||||
|
|
||||||
|
|
@ -328,25 +328,25 @@ Results are cached for 1 hour in the transient cache (`bre_link_analysis`).
|
||||||
|
|
||||||
| Table | Purpose |
|
| Table | Purpose |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `{prefix}bre_crawler_log` | AI bot visits (bot_name, ip_hash, url, visited_at) |
|
| `{prefix}brezngeo_crawler_log` | AI bot visits (bot_name, ip_hash, url, visited_at) |
|
||||||
|
|
||||||
### Transients
|
### Transients
|
||||||
|
|
||||||
| Transient | TTL | Purpose |
|
| Transient | TTL | Purpose |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `bre_llms_cache_{n}` | 1 hour | Cached llms.txt content per page |
|
| `brezngeo_llms_cache_{n}` | 1 hour | Cached llms.txt content per page |
|
||||||
| `bre_link_analysis` | 1 hour | Dashboard link analysis result |
|
| `brezngeo_link_analysis` | 1 hour | Dashboard link analysis result |
|
||||||
| `bre_bulk_running` | 15 minutes | Mutex lock for bulk generator |
|
| `brezngeo_bulk_running` | 15 minutes | Mutex lock for bulk generator |
|
||||||
| `bre_meta_stats` | 5 minutes | Dashboard meta coverage query result |
|
| `brezngeo_meta_stats` | 5 minutes | Dashboard meta coverage query result |
|
||||||
| `bre_crawler_summary` | 5 minutes | Dashboard crawler summary (last 30 days) |
|
| `brezngeo_crawler_summary` | 5 minutes | Dashboard crawler summary (last 30 days) |
|
||||||
|
|
||||||
### Uninstall cleanup
|
### Uninstall cleanup
|
||||||
|
|
||||||
`uninstall.php` removes on plugin deletion:
|
`uninstall.php` removes on plugin deletion:
|
||||||
- Option `bre_settings`
|
- Option `brezngeo_settings`
|
||||||
- Post meta `_bre_meta_description` for all posts
|
- Post meta `_bre_meta_description` for all posts
|
||||||
|
|
||||||
> Note: The remaining option keys and the `bre_crawler_log` table are not automatically removed. For full cleanup, delete these manually.
|
> Note: The remaining option keys and the `brezngeo_crawler_log` table are not automatically removed. For full cleanup, delete these manually.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -369,10 +369,10 @@ Plaintext key → XOR(key, sha256(AUTH_KEY . SECURE_AUTH_KEY)) → base64
|
||||||
**Security boundary:** XOR with a static salt is obfuscation, not cryptographic encryption. An attacker with access to **both** the database **and** `wp-config.php` can reconstruct the key. For maximum security, keys can be defined as `wp-config.php` constants — these take precedence over the database version:
|
**Security boundary:** XOR with a static salt is obfuscation, not cryptographic encryption. An attacker with access to **both** the database **and** `wp-config.php` can reconstruct the key. For maximum security, keys can be defined as `wp-config.php` constants — these take precedence over the database version:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
define( 'BRE_OPENAI_KEY', 'sk-...' );
|
define( 'BREZNGEO_OPENAI_KEY', 'sk-...' );
|
||||||
define( 'BRE_ANTHROPIC_KEY', 'sk-ant-...' );
|
define( 'BREZNGEO_ANTHROPIC_KEY', 'sk-ant-...' );
|
||||||
define( 'BRE_GEMINI_KEY', 'AI...' );
|
define( 'BREZNGEO_GEMINI_KEY', 'AI...' );
|
||||||
define( 'BRE_GROK_KEY', 'xai-...' );
|
define( 'BREZNGEO_GROK_KEY', 'xai-...' );
|
||||||
```
|
```
|
||||||
|
|
||||||
In the admin UI, keys are always displayed masked: `••••••Ab3c9` (only the last 5 characters visible).
|
In the admin UI, keys are always displayed masked: `••••••Ab3c9` (only the last 5 characters visible).
|
||||||
|
|
@ -382,13 +382,13 @@ In the admin UI, keys are always displayed masked: `••••••Ab3c9` (on
|
||||||
Every AJAX handler follows the same pattern — without exception:
|
Every AJAX handler follows the same pattern — without exception:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
check_ajax_referer( 'bre_admin', 'nonce' ); // CSRF
|
check_ajax_referer( 'brezngeo_admin', 'nonce' ); // CSRF
|
||||||
if ( ! current_user_can( 'manage_options' ) ) { // Authorization
|
if ( ! current_user_can( 'manage_options' ) ) { // Authorization
|
||||||
wp_send_json_error( 'Unauthorized', 403 );
|
wp_send_json_error( 'Unauthorized', 403 );
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The nonce `bre_admin` is passed to the frontend via `wp_localize_script` and validated server-side on every request. There are no `wp_ajax_nopriv_` handlers — all AJAX endpoints are exclusively accessible to logged-in users with `manage_options` capability.
|
The nonce `brezngeo_admin` is passed to the frontend via `wp_localize_script` and validated server-side on every request. There are no `wp_ajax_nopriv_` handlers — all AJAX endpoints are exclusively accessible to logged-in users with `manage_options` capability.
|
||||||
|
|
||||||
### Input Validation and Output Escaping
|
### Input Validation and Output Escaping
|
||||||
|
|
||||||
|
|
@ -447,23 +447,23 @@ The provider automatically appears in all admin dropdowns, the provider settings
|
||||||
|
|
||||||
## Hooks & Extensibility
|
## Hooks & Extensibility
|
||||||
|
|
||||||
### `bre_prompt` (Filter)
|
### `brezngeo_prompt` (Filter)
|
||||||
|
|
||||||
Allows modifying the final prompt immediately before the API call.
|
Allows modifying the final prompt immediately before the API call.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
add_filter( 'bre_prompt', function( string $prompt, WP_Post $post ): string {
|
add_filter( 'brezngeo_prompt', function( string $prompt, WP_Post $post ): string {
|
||||||
$keyword = get_post_meta( $post->ID, 'focus_keyword', true );
|
$keyword = get_post_meta( $post->ID, 'focus_keyword', true );
|
||||||
return $keyword ? $prompt . "\nFocus keyword: {$keyword}" : $prompt;
|
return $keyword ? $prompt . "\nFocus keyword: {$keyword}" : $prompt;
|
||||||
}, 10, 2 );
|
}, 10, 2 );
|
||||||
```
|
```
|
||||||
|
|
||||||
### `bre_meta_saved` (Action)
|
### `brezngeo_meta_saved` (Action)
|
||||||
|
|
||||||
Fired after a meta description is successfully saved — both on automatic generation at publish and on manual regen in the editor.
|
Fired after a meta description is successfully saved — both on automatic generation at publish and on manual regen in the editor.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
add_action( 'bre_meta_saved', function( int $post_id, string $description ): void {
|
add_action( 'brezngeo_meta_saved', function( int $post_id, string $description ): void {
|
||||||
// e.g. sync with external system or cache invalidation
|
// e.g. sync with external system or cache invalidation
|
||||||
my_cdn_purge( get_permalink( $post_id ) );
|
my_cdn_purge( get_permalink( $post_id ) );
|
||||||
}, 10, 2 );
|
}, 10, 2 );
|
||||||
|
|
@ -472,7 +472,7 @@ add_action( 'bre_meta_saved', function( int $post_id, string $description ): voi
|
||||||
### Adding a New Feature
|
### Adding a New Feature
|
||||||
|
|
||||||
1. Create `includes/Features/YourFeature.php` with a `register()` method that registers WordPress hooks.
|
1. Create `includes/Features/YourFeature.php` with a `register()` method that registers WordPress hooks.
|
||||||
2. In `includes/Core.php` → `load_dependencies()`: `require_once BRE_DIR . 'includes/Features/YourFeature.php';`
|
2. In `includes/Core.php` → `load_dependencies()`: `require_once BREZNGEO_DIR . 'includes/Features/YourFeature.php';`
|
||||||
3. In `includes/Core.php` → `register_hooks()`: `( new Features\YourFeature() )->register();`
|
3. In `includes/Core.php` → `register_hooks()`: `( new Features\YourFeature() )->register();`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -483,20 +483,20 @@ All endpoints are exclusively accessible to logged-in users with `manage_options
|
||||||
|
|
||||||
| Action | Handler | Description |
|
| Action | Handler | Description |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `bre_regen_meta` | `MetaEditorBox::ajax_regen` | Regenerate meta description for a single post |
|
| `brezngeo_regen_meta` | `MetaEditorBox::ajax_regen` | Regenerate meta description for a single post |
|
||||||
| `bre_test_connection` | `ProviderPage::ajax_test_connection` | Test API key and connection |
|
| `brezngeo_test_connection` | `ProviderPage::ajax_test_connection` | Test API key and connection |
|
||||||
| `bre_get_default_prompt` | `ProviderPage::ajax_get_default_prompt` | Reset to default prompt |
|
| `brezngeo_get_default_prompt` | `ProviderPage::ajax_get_default_prompt` | Reset to default prompt |
|
||||||
| `bre_link_analysis` | `LinkAnalysis::ajax_analyse` | Run link analysis for the dashboard |
|
| `brezngeo_link_analysis` | `LinkAnalysis::ajax_analyse` | Run link analysis for the dashboard |
|
||||||
| `bre_link_suggestions` | `LinkSuggest::ajax_suggest` | Return top-10 internal link suggestions for current post |
|
| `brezngeo_link_suggestions` | `LinkSuggest::ajax_suggest` | Return top-10 internal link suggestions for current post |
|
||||||
| `bre_geo_generate` | `GeoEditorBox::ajax_generate` | Generate GEO block for a single post |
|
| `brezngeo_geo_generate` | `GeoEditorBox::ajax_generate` | Generate GEO block for a single post |
|
||||||
| `bre_geo_clear` | `GeoEditorBox::ajax_clear` | Clear GEO block data for a single post |
|
| `brezngeo_geo_clear` | `GeoEditorBox::ajax_clear` | Clear GEO block data for a single post |
|
||||||
| `bre_llms_clear_cache` | `TxtPage::ajax_clear_cache` | Clear llms.txt transient cache |
|
| `brezngeo_llms_clear_cache` | `TxtPage::ajax_clear_cache` | Clear llms.txt transient cache |
|
||||||
| `bre_dismiss_llms_notice` | `LlmsTxt::ajax_dismiss_notice` | Dismiss Rank Math conflict admin notice |
|
| `brezngeo_dismiss_llms_notice` | `LlmsTxt::ajax_dismiss_notice` | Dismiss Rank Math conflict admin notice |
|
||||||
| `bre_dismiss_welcome` | `AdminMenu::ajax_dismiss_welcome` | Dismiss the welcome notice per user |
|
| `brezngeo_dismiss_welcome` | `AdminMenu::ajax_dismiss_welcome` | Dismiss the welcome notice per user |
|
||||||
| `bre_bulk_generate` | `MetaGenerator::ajaxBulkGenerate` | Process next batch in bulk generator |
|
| `brezngeo_bulk_generate` | `MetaGenerator::ajaxBulkGenerate` | Process next batch in bulk generator |
|
||||||
| `bre_bulk_stats` | `MetaGenerator::ajaxBulkStats` | Retrieve progress and stats of running bulk |
|
| `brezngeo_bulk_stats` | `MetaGenerator::ajaxBulkStats` | Retrieve progress and stats of running bulk |
|
||||||
| `bre_bulk_release` | `MetaGenerator::ajaxBulkRelease` | Manually release bulk mutex lock |
|
| `brezngeo_bulk_release` | `MetaGenerator::ajaxBulkRelease` | Manually release bulk mutex lock |
|
||||||
| `bre_bulk_status` | `MetaGenerator::ajaxBulkStatus` | Check bulk lock status |
|
| `brezngeo_bulk_status` | `MetaGenerator::ajaxBulkStatus` | Check bulk lock status |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* Plugin Name: BreznGEO
|
* Plugin Name: BreznGEO
|
||||||
* Plugin URI: https://brezngeo.com/
|
* Plugin URI: https://brezngeo.com/
|
||||||
* Description: AI-powered meta descriptions, GEO structured data, and llms.txt for WordPress.
|
* Description: AI-powered meta descriptions, GEO structured data, and llms.txt for WordPress.
|
||||||
* Version: 1.3.5
|
* Version: 1.0.0
|
||||||
* Requires at least: 6.0
|
* Requires at least: 6.0
|
||||||
* Requires PHP: 8.0
|
* Requires PHP: 8.0
|
||||||
* Author: NoSchmarrn.dev
|
* Author: NoSchmarrn.dev
|
||||||
|
|
@ -18,7 +18,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
define( 'BREZNGEO_VERSION', '1.3.5' );
|
define( 'BREZNGEO_VERSION', '1.0.0' );
|
||||||
define( 'BREZNGEO_FILE', __FILE__ );
|
define( 'BREZNGEO_FILE', __FILE__ );
|
||||||
define( 'BREZNGEO_DIR', plugin_dir_path( __FILE__ ) );
|
define( 'BREZNGEO_DIR', plugin_dir_path( __FILE__ ) );
|
||||||
define( 'BREZNGEO_URL', plugin_dir_url( __FILE__ ) );
|
define( 'BREZNGEO_URL', plugin_dir_url( __FILE__ ) );
|
||||||
|
|
|
||||||
|
|
@ -198,9 +198,9 @@ class AdminMenu {
|
||||||
|
|
||||||
$post_types = $settings['meta_post_types'] ?? array( 'post', 'page' );
|
$post_types = $settings['meta_post_types'] ?? array( 'post', 'page' );
|
||||||
$meta_stats = $this->get_meta_stats( $post_types );
|
$meta_stats = $this->get_meta_stats( $post_types );
|
||||||
$bre_compat = $this->get_compat_info();
|
$brezngeo_compat = $this->get_compat_info();
|
||||||
|
|
||||||
$bre_show_welcome = $this->should_show_welcome();
|
$brezngeo_show_welcome = $this->should_show_welcome();
|
||||||
|
|
||||||
$usage_stats = get_option(
|
$usage_stats = get_option(
|
||||||
'brezngeo_usage_stats',
|
'brezngeo_usage_stats',
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ class SettingsPage {
|
||||||
$saved_meta = get_option( self::OPTION_KEY_META, array() );
|
$saved_meta = get_option( self::OPTION_KEY_META, array() );
|
||||||
$saved_meta = is_array( $saved_meta ) ? $saved_meta : array();
|
$saved_meta = is_array( $saved_meta ) ? $saved_meta : array();
|
||||||
|
|
||||||
// Schema has its own option key since v1.3.0; falls back to bre_meta_settings for existing installs.
|
// Schema has its own option key since v1.3.0; falls back to brezngeo_meta_settings for existing installs.
|
||||||
$saved_schema = get_option( self::OPTION_KEY_SCHEMA, array() );
|
$saved_schema = get_option( self::OPTION_KEY_SCHEMA, array() );
|
||||||
$saved_schema = is_array( $saved_schema ) ? $saved_schema : array();
|
$saved_schema = is_array( $saved_schema ) ? $saved_schema : array();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="wrap brezngeo-settings">
|
<div class="wrap brezngeo-settings">
|
||||||
<h1><?php esc_html_e( 'BreznGEO — Dashboard', 'brezngeo' ); ?></h1>
|
<h1><?php esc_html_e( 'BreznGEO — Dashboard', 'brezngeo' ); ?></h1>
|
||||||
|
|
||||||
<?php if ( $bre_show_welcome ) : ?>
|
<?php if ( $brezngeo_show_welcome ) : ?>
|
||||||
<div class="brezngeo-welcome-notice" id="brezngeo-welcome-notice">
|
<div class="brezngeo-welcome-notice" id="brezngeo-welcome-notice">
|
||||||
<button type="button" class="brezngeo-dismiss" id="brezngeo-dismiss-welcome"
|
<button type="button" class="brezngeo-dismiss" id="brezngeo-dismiss-welcome"
|
||||||
aria-label="<?php esc_attr_e( 'Dismiss', 'brezngeo' ); ?>">×</button>
|
aria-label="<?php esc_attr_e( 'Dismiss', 'brezngeo' ); ?>">×</button>
|
||||||
|
|
@ -165,12 +165,12 @@
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if ( ! empty( $bre_compat ) ) : ?>
|
<?php if ( ! empty( $brezngeo_compat ) ) : ?>
|
||||||
<div class="postbox">
|
<div class="postbox">
|
||||||
<div class="postbox-header"><h2><?php esc_html_e( 'Plugin Compatibility', 'brezngeo' ); ?></h2></div>
|
<div class="postbox-header"><h2><?php esc_html_e( 'Plugin Compatibility', 'brezngeo' ); ?></h2></div>
|
||||||
<div class="inside">
|
<div class="inside">
|
||||||
<p style="color:#666;margin-top:0;"><?php esc_html_e( 'The following SEO plugins were detected. BreznGEO adapts automatically.', 'brezngeo' ); ?></p>
|
<p style="color:#666;margin-top:0;"><?php esc_html_e( 'The following SEO plugins were detected. BreznGEO adapts automatically.', 'brezngeo' ); ?></p>
|
||||||
<?php foreach ( $bre_compat as $plugin ) : ?>
|
<?php foreach ( $brezngeo_compat as $plugin ) : ?>
|
||||||
<p style="margin-bottom:4px;"><strong><?php echo esc_html( $plugin['name'] ); ?></strong></p>
|
<p style="margin-bottom:4px;"><strong><?php echo esc_html( $plugin['name'] ); ?></strong></p>
|
||||||
<ul style="margin:0 0 12px 20px;">
|
<ul style="margin:0 0 12px 20px;">
|
||||||
<?php foreach ( $plugin['notes'] as $note ) : // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound ?>
|
<?php foreach ( $plugin['notes'] as $note ) : // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound ?>
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,10 @@
|
||||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=brezngeo-txt&tab=robots' ) ); ?>"
|
<a href="<?php echo esc_url( admin_url( 'admin.php?page=brezngeo-txt&tab=robots' ) ); ?>"
|
||||||
class="nav-tab <?php echo esc_attr( $active_tab === 'robots' ? 'nav-tab-active' : '' ); ?>">
|
class="nav-tab <?php echo esc_attr( $active_tab === 'robots' ? 'nav-tab-active' : '' ); ?>">
|
||||||
robots.txt
|
robots.txt
|
||||||
<?php $bre_blocked_count = count( $robots_settings['blocked_bots'] ?? array() ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound ?>
|
<?php $brezngeo_blocked_count = count( $robots_settings['blocked_bots'] ?? array() ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound ?>
|
||||||
<?php if ( $bre_blocked_count > 0 ) : ?>
|
<?php if ( $brezngeo_blocked_count > 0 ) : ?>
|
||||||
<span style="display:inline-block;background:#2271b1;color:#fff;border-radius:10px;font-size:11px;padding:1px 7px;margin-left:6px;vertical-align:middle;line-height:1.6;">
|
<span style="display:inline-block;background:#2271b1;color:#fff;border-radius:10px;font-size:11px;padding:1px 7px;margin-left:6px;vertical-align:middle;line-height:1.6;">
|
||||||
<?php echo esc_html( $bre_blocked_count ); ?>
|
<?php echo esc_html( $brezngeo_blocked_count ); ?>
|
||||||
</span>
|
</span>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -443,7 +443,7 @@ class GeoBlock {
|
||||||
$style_attr = ' style="--brezngeo-accent:' . esc_attr( $accent ) . ';"';
|
$style_attr = ' style="--brezngeo-accent:' . esc_attr( $accent ) . ';"';
|
||||||
}
|
}
|
||||||
|
|
||||||
return '<details class="brezngeo-geo" data-bre="geo"' . $open_attr . $theme_attr . $style_attr . '>'
|
return '<details class="brezngeo-geo" data-brezngeo="geo"' . $open_attr . $theme_attr . $style_attr . '>'
|
||||||
. '<summary><span class="brezngeo-geo__title">' . $title . '</span></summary>'
|
. '<summary><span class="brezngeo-geo__title">' . $title . '</span></summary>'
|
||||||
. $inner
|
. $inner
|
||||||
. '</details>';
|
. '</details>';
|
||||||
|
|
|
||||||
|
|
@ -709,12 +709,12 @@ msgid "Load minimal CSS"
|
||||||
msgstr "Minimal-CSS laden"
|
msgstr "Minimal-CSS laden"
|
||||||
|
|
||||||
#: includes/Admin/views/geo.php
|
#: includes/Admin/views/geo.php
|
||||||
msgid "Load base stylesheet for .bre-geo on the frontend"
|
msgid "Load base stylesheet for .brezngeo-geo on the frontend"
|
||||||
msgstr "Basis-Stylesheet für .bre-geo auf dem Frontend laden"
|
msgstr "Basis-Stylesheet für .brezngeo-geo auf dem Frontend laden"
|
||||||
|
|
||||||
#: includes/Admin/views/geo.php
|
#: includes/Admin/views/geo.php
|
||||||
msgid "Automatically scoped to .bre-geo{...}. Enter CSS property:value pairs only — selectors, at-rules (@media, @import etc.) and url() are blocked for security."
|
msgid "Automatically scoped to .brezngeo-geo{...}. Enter CSS property:value pairs only — selectors, at-rules (@media, @import etc.) and url() are blocked for security."
|
||||||
msgstr "Wird automatisch auf .bre-geo{...} begrenzt. Nur CSS-Eigenschaft:Wert-Paare eingeben — Selektoren, At-Regeln (@media, @import usw.) und url() werden aus Sicherheitsgründen blockiert."
|
msgstr "Wird automatisch auf .brezngeo-geo{...} begrenzt. Nur CSS-Eigenschaft:Wert-Paare eingeben — Selektoren, At-Regeln (@media, @import usw.) und url() werden aus Sicherheitsgründen blockiert."
|
||||||
|
|
||||||
#: includes/Admin/views/geo.php
|
#: includes/Admin/views/geo.php
|
||||||
msgid "AI Prompt"
|
msgid "AI Prompt"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue