Files
claude-regelwerk/AI/Regelwerk/seo.md
T
Pascal MichelandClaude Opus 5 2c9a4475fc Regelwerk, Agenten, Skills und Werkzeuge veröffentlichen
Erster Stand des öffentlichen Ausschnitts aus dem Vault. Die .gitignore
arbeitet als Positivliste: ausgeschlossen ist alles, eingeschlossen nur,
was ausdrücklich wieder aufgenommen wird. Notizen, Projekte, Finanzen,
das Sitzungsgedächtnis und settings.local.json bleiben damit außen vor.

Der Kundenname in AI/Regelwerk/seo.md ist durch eine neutrale
Bezeichnung ersetzt; die Regeln selbst sind unverändert.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 22:38:15 +02:00

14 KiB
Raw Blame History

type, status, title, summary, tags, created, updated
type status title summary tags created updated
resource pending-review SEO-Arbeit an WordPress-Kundensites über WPVibe Regeln für SEO-Audits und deren Umsetzung auf WordPress-Sites (Rank Math, Salient/WPBakery, WP Super Cache, WPCode) über den WPVibe-Connector — Arbeitsweise, Werkzeugwege, Messregeln, bekannte Fallen. Nur laden, wenn eine Website auditiert oder nach einem Audit umgebaut wird.
regelwerk
seo
wordpress
wpvibe
rank-math
2026-09-07 2026-09-17

SEO-Arbeit an WordPress-Kundensites über WPVibe

Angeordnet am 2026-09-07. Laden, wenn eine Website auditiert (/seo, /seo-audit) oder ein Audit-Befund auf einer WordPress-Site umgesetzt wird. Nicht bei Code-Projekten, nicht bei Dokumenten, nicht beim Depot.

Alles hier stammt aus der Arbeit an einer Kundensite zwischen dem 02.09. und dem 07.09.2026 (Audits 26 → 82 technisch, Vollaudit 67 → 70). Die Fallgeschichten und Belege liegen im Harness-Gedächtnis; hier steht nur die Regel. Wo eine Regel nur für eine bestimmte Version oder einen bestimmten Hoster belegt ist, steht das dabei.

1 Arbeitsweise

  1. Audit-Befunde sind Behauptungen, keine Fakten. Jeden Befund vor der Umsetzung live nachmessen (curl ohne Cache, Browser bei 375 und 1366 px). Am 07.09. waren von zehn Befunden eines Nach-Fix-Audits drei falsch: IndexNow lief, das Kachel-Clipping war nicht reproduzierbar, das „ungeplant aktivierte" Schema hatte Pascal selbst eingeschaltet. Audit-Subagenten zitieren außerdem Altbefunde aus findings/*.md früherer Läufe, die längst behoben sind.
  2. Eigene Erfolgsmeldungen sind auch Behauptungen. Die Mittagssitzung vom 07.09. meldete „Team-Verlinkung live" und „Angebote gefixt"; beides stimmte nicht. Ein Nach-Fix-Audit läuft unabhängig und übernimmt nichts aus der Fix-Liste.
  3. Drei Sorten von Punkten sauber trennen: was über den Connector geht (Inhalte, Optionen, Cache); was nur Pascal kann (.htaccess, Snippet-Freigabe und -Aktivierung, WebFTP, Google-Konten); was nur der Betreiber kann (echte Angebote, Firmenname, GBP-Pin). Die zweite und dritte Sorte landen in einer FUER-PASCAL.md mit fertigen Blöcken und Kontrollbefehl je Block.
  4. Nichts erfinden. Keine Rabatte, Lieferkosten, Lieferzeiten, Bewertungszahlen oder Praktiken, die nicht auf der Website, in der Preisliste oder beim Betreiber belegt sind. Was fehlt, wird als Lücke benannt („braucht Betreiberdaten"). Stammpreise sind keine Angebote.
  5. Ablage je Audit-Lauf unter IT Workspace/SEO & Websitehosting/<domain>-audit/<TTMMJJJJ>/: ABSCHLUSSBERICHT.md, UMSETZUNGSPLAN.md mit Ergebnistabelle (Befund, Maßnahme, Beleg), FUER-PASCAL.md, bei Textarbeit TEXTE-QA.md mit dem Wortlaut. Nach-Fix-Läufe in <TTMMJJJJ>-nachher/. Nach jedem Lauf bekommt der Seed IT Workspace/SEO & Websitehosting/_MOC-seo-websitehosting.md einen Eintrag für diesen Lauf: Datum, Art des Laufs, gemessener Score, Link auf ABSCHLUSSBERICHT.md, darunter eingerückt die Links auf die übrigen Dokumente desselben Laufordners (UMSETZUNGSPLAN.md, FUER-PASCAL.md, TEXTE-QA.md und so weiter) ohne eigene Zusammenfassung. Den neuesten Lauf stellst du nach oben. findings/, Rohdaten und die Preisliste bekommen keinen Seed-Eintrag. Befunde früherer Läufe sind oft längst behoben (Punkt 1) und sollen nicht prominent verlinkt sein.
  6. /seo audit-Subagenten laufen in ihr 15-Turn-Limit (Schema, Content, Visual, SXO am 07.09.). Per SendMessage an die Task-ID fortsetzen lassen, das Teilergebnis nicht als Endstand nehmen.

2 WPVibe-Connector

  • Vor jeder Arbeit list_sites für das Kontingent: Free-Plan seit 2026-09-14 nur noch 100 Aufrufe je rollende 24 Stunden (vorher 300), die Zahl steht in der Antwort von list_sites. Massenänderungen als eine Anweisung, nicht als Schleife. Lesen bündeln (db query mit SUBSTRING über mehrere IDs), Live-Prüfung per curl und App-Browser statt über den Connector.
  • Barrierefreiheit messen mit axe-core im App-Browser (per <script> von cdnjs nachladen, vorher einmal ganz scrollen, sonst verstecken Einblendanimationen Elemente) und einem Tab-Test von Hand; axe sieht Fokus und Tastaturbedienung nicht zuverlässig. Keine Overlay-Plugins. Den Fokusrahmen von WP Accessibility (wpa_focus, Standard #233c7f) nicht nehmen, wenn die Site grüne Flächen hat: 2,8:1 auf #009755.
  • Freigaben: Link erst erzeugen, wenn der Klick sofort kommt; sie können ablaufen, bevor der Klick ankommt. Nach jeder Freigabe check_approval_status und eine Zählabfrage am Datenbestand. „executed" heißt nicht „wirkt" (Beispiel: Option gelöscht, Sitemap trotzdem alt, siehe Abschnitt 4).
  • Klassifikator-Ablehnung (Blocked by classifier) ist nicht deterministisch. Einmal über den anderen Weg versuchen: REST statt WP-CLI (PUT /wp/v2/pages/{id} statt post update), code_snippet update statt create. Nicht mehrfach denselben Aufruf wiederholen.
  • Inhaltsänderungen über POST /wpvibe/v1/content/edit (match-once str_replace auf post_content, der Inhalt kommt nicht in den Kontext). Den old_content aus dem rohen post_content nehmen (post get <id> --fields=post_content), nicht aus dem gerenderten HTML; Entities und wpautop verändern den Text. Dieser Weg löst keine WordPress-Hooks aus: kein save_post, keine Rank-Math-Invalidierung, aber post_modified wird gesetzt.
  • Emulator statt WP-CLI: help und help <familie> lesen, nicht raten. plugin delete heißt plugin uninstall, menu delete fehlt (REST DELETE /wp/v2/menus/{id} mit force), Semikolons in db query sind verboten, post meta update auf rank_math_* braucht ab dem zweiten Mal --force. option patch insert|update <option> <key> <wert> schreibt einzelne Schlüssel in serialisierte Optionen, ohne die Option ganz zu laden.
  • content/edit meldet bei einem Ausschnitt, der mitten in einem Gutenberg-Block beginnt, „parser found 0 blocks". Das prüft nur den Ausschnitt; belegt ist erst die Zählung von Öffnungs- und Schlusskommentaren der ganzen Seite per db query.
  • Theme-Dateien sind über search_files und read_file lesbar (aktives Theme, read-only), Plugin-Dateien nicht, auch nicht mit scope=wp-content (HTTP 404, WPVibe 1.16.5). Ein unbekanntes Shortcode-Attribut erst auf einer Seite setzen und am gerenderten HTML prüfen. Wer Rank-Math-Verhalten wissen will, liest den Quelltext aus dem WordPress.org-SVN.

3 WPCode-Snippets

  • Jedes PHP-Snippet braucht Freigabe und wird deaktiviert geschrieben; auch jedes update schaltet es aus. Pascal schaltet im Backend ein. Danach post_status des Snippet-Posts (post_type = wpcode) abfragen: publish heißt an, draft heißt aus. Am 07.09. war das erste Einschalten nicht angekommen; die Aussage „ist an" war falsch, die Datenbank nicht.
  • Deshalb Snippet-Änderungen bündeln: eine Freigabe-plus-Einschalten-Runde je Sitzung, nicht je Einzeiler.
  • style_loader_tag bekommt den Handle ohne -css (wpa-style, nicht wpa-style-css); das Suffix hängt WordPress erst im id-Attribut an. Rohinhalt einer Seite immer über get_post($id)->post_content, nie über get_post_field(), das Anzeigefilter durchläuft und Shortcodes verliert.
  • Salient setzt skip-lazy auf jedes Bild und schaltet natives Lazy Loading in class-nectar-lazy.php fest ab. Ein Lazy-Loading-Snippet, das skip-lazy respektiert, tut nichts.
  • Sicherheits-Header nie per PHP-Hook setzen: WP Super Cache liefert vor WordPress aus. Sie gehören in die .htaccess, oberhalb des WordPress- und des Super-Cache-Blocks, sonst überschreibt WordPress sie.

4 Rank Math (belegt mit 1.0.277.2)

  • Ohne verbundenes Konto oder rank_math_registration_skip = 1 liefert Rank Math nichts (kein Titel, keine Sitemap, kein Schema), obwohl das Plugin aktiv ist. Nach dem Setzen rewrite flush.
  • Optionen: rank-math-options-titles (nicht rank_math_titles), rank-math-options-sitemap, rank-math-options-instant-indexing; Module in rank_math_modules; Local SEO braucht local-seo.
  • Auf normalen Seiten lässt Rank Math bei „Schema-Typ: off" den ganzen JSON-LD-Graph weg. Filter rank_math/schema/add_global_entities auf __return_true gibt Organization/Store, WebSite und WebPage auf allen Seiten aus.
  • Der Sitemap-Cache sind Dateien, nicht die Option: wp-content/uploads/rank-math/rank_math_<hash>.xml, Liste in rank_math_sitemap_cache_files. Rank Math prüft die Datei. Option löschen reicht nicht, content/edit und REST-PUT invalidieren nicht. Dateien per WebFTP löschen oder Sitemap-Einstellungen im Backend speichern.
  • Rank Math escaped nach dem Filter rank_math/json_ld: ein html_entity_decode auf hasMap im Filter kommt als &amp; wieder heraus. Ein FAQPage-Objekt aus dem Filter mergt Rank Math in das WebPage-Objekt (@type: FAQPage, @id …#webpage); das ist gültig und gewollt.
  • opening_hours_format steuert nur den Shortcode, nicht das Schema. openingHoursSpecification kommt über einen Filter.
  • IndexNow: Modul instant-indexing plus Schlüsseldatei /<key>.txt mit HTTP 200. Vor dem Befund „nicht implementiert" die Datei abrufen.

5 Salient / WPBakery

  • Custom CSS liegt in salient_redux['custom-css'] (Key laut nectar/redux-framework/options-config.php) und wird bei jedem Aufruf inline ausgegeben; option patch update salient_redux custom-css "…" reicht, kein Regenerieren. Header-Icons brauchen !important, Salient setzt #header-outer[data-lhe] #top nav > ul > #social-in-menu > a { padding: 0 }.
  • Seiten haben oft zwei Überschriftenreihen (Desktop vc_hidden-xs vc_hidden-sm vc_hidden-md, Mobil vc_hidden-lg). Ein Befund „H1 0×0 auf Mobil" heißt: die Mobilreihe trägt ein H2. Wer eine H1 ändert, ändert zwei Stellen.
  • Horizontaler Scroll kam von column_margin_custom="7vw" einer Reihe (7vw/2 = 67 px bei 1920), nicht von der Leaflet-Karte. scrollWidth gegen clientWidth messen, nicht raten.
  • maximum-scale=5 im Viewport: die einzige Theme-Alternative ist maximum-scale=1, user-scalable=0, schlechter. Lassen.
  • Google-Karte ([nectar_gmap], belegt mit Salient 18.2.1 / Salient Core 3.1.5): Marker stehen im Shortcode-Attribut map_markers="lat|lng|Info"; ohne es rendert map.js einen leeren .map-marker. marker_style="nectar" zeigte keinen Pin, default schon. map.js (Handle nectarMap) lädt die Maps API sofort beim Seitenaufruf, ohne Salients Lazy-Script-Mechanik. Datenschutzkonform nur mit Klick-Lösung: das Klick-Snippet der Kundensite als Vorlage (Snippet-ID steht im Harness-Gedächtnis) (script_loader_tag → type="text/plain", Overlay mit Button, Klick bindet das Skript ein). Messen mit Playwright: Anfragen an Google-Hosts vor dem Klick müssen 0 sein.
  • Wer eine Einbindung tauscht (Karte, Schriften, Tracking), fasst im selben Schritt Datenschutzerklärung und CSP an. Am 15.09.2026 ersetzte eine Google-Karte die OSM-Karte, die Datenschutzerklärung beschrieb weiter OSM und „keine Daten an Google".
  • Mobile Touch-Ziele unter 44 px im Header sind die Telefon-/E-Mail-Icons (.button_social_group a) und der Menü-Toggle (.slide-out-widget-area-toggle a); Padding plus negativer Margin hält das Layout.

6 Hoster und Cache

  • All-Inkl: exec() aus. EWWW findet „0 Bilder", obwohl Optionen und Cron korrekt sind; Imsanity plus Converter for Media brauchen kein exec(). Vor der Plugin-Wahl fragen, ob es Binärdateien braucht.
  • WP Super Cache: nach jeder Änderung cache purge; Optionsschreibungen über den Emulator purgen automatisch. Cache-Buster ist ein langer erfundener Parameter (?agentcheck=1), nie ein einbuchstabiger: w ist die Kalenderwoche, m das Datum, s die Suche, p die Post-ID, alle liefern eine 404-Seite mit HTTP 200. Wenn nach einer Änderung alle Seiten gleich groß sind, zuerst <title> und body class lesen.
  • Cache-Header und CSP gehören in die .htaccess (siehe Abschnitt 3). CSP erst Report-Only, eine Woche beobachten, dann scharf.

7 Messregeln

  • Wortzahlen nur aus <p> und <li> mit striktem Muster <p(?:\s[^>]*)?>, vorher <svg>, <script>, <style> entfernen. <p[^>]*> trifft <path> und zählt SVG-Icons als Absätze. Navigations-Kurzlabels sind kein Inhalt.
  • Eine Zahl, die vom Audit oder einer zweiten Messung um mehr als ein paar Prozent abweicht, ist ein Messfehler, bis das Gegenteil belegt ist.
  • JSON-LD prüfen: Skripte extrahieren, json.loads, dann je Seite Typen, hasMap, address und FAQ-Antwortlängen ausgeben. Rich Results Test läuft ohne Login im App-Browser; die PageSpeed-API ist nach wenigen Läufen für den Tag erschöpft (HTTP 429), Lab-Werte deshalb datieren.
  • Shortcode-Lecks nach Inhaltsänderungen: \[/?(?:toggle|vc_|nectar)[^\]]*\] auf dem gerenderten HTML muss leer sein.
  • Browser-Messung im App-Pane: getBoundingClientRect und die Elternkette bis zum ersten display: none, nicht der Screenshot; der Screenshot-Kanal rendert nicht immer.

8 Inhalte

  • Frage-Antwort-Toggles ([toggle title="…"]) werden serverseitig gerendert und sind crawlbar; das FAQPage-Schema liest sie aus dem Rohinhalt. Zielkorridor je Antwort für KI-Zitierbarkeit 134–167 Wörter; 120–150 ist erreichbar, ohne zu schwafeln.
  • Jede Antwort: Faustregel mit Rechenbeispiel, Preisbeispiel mit Datum und „freibleibend, inklusive Mehrwertsteuer", zuständige Person mit Link auf /team/. Preise nur aus der Preisliste des Betreibers, mit Stand.
  • Team-Verlinkung heißt Link im Inhalt, nicht im Menü.
  • Schreibstil nach AI/Regelwerk/schreibstil: Sie-Form wie die Site, ganze Sätze, keine Marketingfloskeln.

Verwandt