Sylius SEO Suite Pro: SEO-Audit
Der SEO-Audit prüft Produkte und Kategorien auf fehlende, zu lange und doppelte Titel und Beschreibungen, fehlende Bilder und noindex. Start per Dashboard-Button oder Cronjob, mit Snapshot, Lock und Limits.
Sylius SEO Suite Pro: SEO-Audit
Der SEO-Audit prüft die Produkte und Kategorien eines Channels auf SEO-Probleme, die Du im Admin selbst beheben kannst, und listet die Funde mit einem Link zum jeweiligen Produkt oder zur Kategorie. Du startest ihn per Button im Dashboard oder per Console-Command. Erreichbar ist er über den Button "SEO-Audit" oben auf der Seite "SEO Suite Pro".
Der Audit prüft, was der Storefront wirklich ausliefert: Titel und Beschreibung einer Seite nach der Prioritätskette (manueller Text, dann SEO-Template, dann Fallback, siehe SEO-Templates). Ein Produkt, dessen Titel aus einem Template kommt, wird also nicht als "Titel fehlt" gemeldet.
Was geprüft wird
Geprüft wird pro Channel und pro Sprache des Channels, für jedes aktive Produkt und jede aktive Kategorie, die im Channel verfügbar ist. Deaktivierte Produkte und Kategorien sowie die anderer Channels werden nicht angesehen. Fehlt eine Übersetzung in einer Sprache, wird das Produkt in dieser Sprache nicht geprüft.
| Code | Prüft | Schwere | Schwellwert |
|---|---|---|---|
title_missing |
Kein manueller Meta-Titel und kein Titel-Template greift, der Seitentitel ist also nur der Name | warning | keiner |
title_too_long |
Der ausgelieferte Titel ist zu lang (der Detailwert nennt die Länge) | warning | mehr als 60 Zeichen (seo_templates.title_max_length) |
title_duplicate |
Derselbe Titel steht bei mehr als einem Produkt (oder einer Kategorie) des Channels in derselben Sprache (der Detailwert nennt die Anzahl) | warning | ab 2 gleichen Titeln |
description_missing |
Die ausgelieferte Meta-Description ist leer | warning | keiner |
description_too_long |
Die ausgelieferte Meta-Description ist zu lang (der Detailwert nennt die Länge) | info | mehr als 155 Zeichen (seo_templates.description_max_length) |
description_duplicate |
Dieselbe Beschreibung bei mehr als einem Produkt (oder einer Kategorie), wie bei den Titeln | warning | ab 2 gleichen Beschreibungen |
product_without_image |
Ein Produkt ohne jedes Bild (einmal pro Produkt, nicht pro Sprache) | warning | kein Bild |
noindex |
Produkt oder Kategorie steht auf noindex; oft gewollt, wird aber gelistet, damit eine vergessene Einstellung auffällt |
info | keiner |
Es gibt die Schweren error, warning und info. Die acht eingebauten Checks nutzen nur warning und info; error steht Deinen eigenen Checks zur Verfügung. Duplikate ignorieren Groß-/Kleinschreibung und mehrfache Leerzeichen. Ein leerer Text ist nie ein Duplikat, er wird stattdessen als fehlend gemeldet. Die Längen-Schwellwerte sind keine eigenen Audit-Einstellungen: Sie folgen den Grenzen der SEO-Templates, damit der Audit und die Template-Kürzung dieselbe Messlatte nutzen.
Unter den Channels zeigt das Dashboard zusätzlich die zehn meistaufgerufenen 404-Pfade, die kein aktiver Redirect abdeckt, live aus dem 404-Log (siehe Redirects). Jeder Pfad hat einen Link, der das Redirect-Formular vorausgefüllt öffnet. Dieser Block gehört nicht zum Snapshot und funktioniert auch ohne die Audit-Tabellen.
Was nicht geprüft wird
- Alt-Texte von Bildern: Das Sylius-Core hat kein Alt-Text-Feld an Produktbildern, es gibt also nichts zu lesen.
- Bildabmessungen (zum Beispiel "mindestens 800 Pixel"): Bilder hinter einem CDN oder einer externen URL kann der Shop nicht lesen, und jede lokale Bilddatei bei einem Lauf zu dekodieren würde ihn langsam und unzuverlässig machen. Geprüft wird nur, ob ein Bild vorhanden ist.
- Alles außerhalb von Produkten und Kategorien (CMS-Seiten gibt es im Sylius-Core nicht) sowie die inhaltliche Qualität der Texte.
Eigene Prüfungen sind möglich, siehe unten.
So läuft ein Audit ab
Ein Lauf ist ein Snapshot: Er schreibt seine Funde in mmd_sylius_seo_suite_pro_audit_issue und den Lauf selbst in mmd_sylius_seo_suite_pro_audit_run (Status running, done oder failed, dazu die Anzahl der Funde pro Check). Dashboard und Liste lesen nur diese Tabellen, beim Öffnen wird nichts berechnet.
Nur ein erfolgreicher Lauf (done) gilt als aktueller Stand. Liste und Zähler zeigen den neuesten done-Lauf jedes Channels. Ein fehlgeschlagener Lauf (seine Funde sind unvollständig) ersetzt ihn nie: Das Dashboard weist dann darauf hin, dass der letzte Lauf fehlgeschlagen ist, und zeigt weiter den letzten guten Stand.
graph TD
A["Start für einen Channel"] --> B{"Lock des Channels frei?"}
B -->|"nein, Heartbeat frisch"| C["Abbruch: Audit läuft bereits"]
B -->|"ja, oder Heartbeat älter als stale_after_minutes"| D["Lock nehmen, Lauf als running anlegen"]
D --> E["Seite mit page_size Produkten laden und prüfen"]
E --> F["Funde der Seite schreiben, Heartbeat setzen, Speicher leeren"]
F --> G{"Noch Seiten und unter max_subjects?"}
G -->|"ja"| E
G -->|"max_subjects erreicht"| H["Abgeschnitten: Lauf endet als done mit Hinweis max_subjects"]
G -->|"nein"| I["Duplikat-Checks schreiben ihre Funde"]
I --> J["Lauf als done abschließen, Lock lösen"]
H --> J
J --> K["Ältere Läufe über keep_runs hinaus löschen"]
E -->|"Fehler"| L["Lauf als failed abschließen, Lock lösen"]
- Produkte und Kategorien werden in Seiten zu
audit.page_size(200) nach Primärschlüssel gelesen. Nach jeder Seite wird der Entity Manager geleert, der Speicherbedarf wächst also nicht mit dem Katalog. - Es läuft höchstens ein Lauf pro Channel. Der Lock ist die eindeutige Spalte
lock_keyder Lauf-Zeile und gilt deshalb über Prozesse und Server hinweg. Der Lauf schreibt nach jeder Seite einen Heartbeat. Ist der Heartbeat älter alsaudit.stale_after_minutes(10), gilt der Lauf als tot und der nächste Start schließt ihn als fehlgeschlagen. Der Lock wird außerdem freigegeben, wenn das Schließen des Laufs selbst scheitert, und per Shutdown-Funktion, wenn der Prozess stirbt (Fatal Error, Zeit- oder Speicherlimit). - Die letzten
audit.keep_runs(3) Läufe pro Channel bleiben erhalten, ältere werden samt Funden gelöscht, aber erst nachdem ein Lauf erfolgreich endete. Ein fehlschlagender Lauf kostet Dich also nie den letzten guten Snapshot. Einen eigenen Cronjob dafür brauchst Du nicht. - Ein fehlgeschlagener Lauf speichert nur den festen Code
error. Der Grund steht im Log des Shops, nie der Text der Exception in der Datenbank.
Mit
audit.max_subjects(20000) werden Produkte und, getrennt davon, Kategorien pro Channel begrenzt. Ein größerer Channel wird abgeschnitten: Der Lauf endet alsdonemit dem Hinweis "stopped at the subject limit". Die Funde sind echt, decken aber nur einen Teil des Katalogs ab. Der Console-Command meldet das als Fehler (Exit-Code 1), damit Du es im Cronjob bemerkst.
Audit starten
Dashboard
Im Admin: "Run audit now" auf der Karte eines Channels im Audit-Dashboard (ein POST mit CSRF-Token). Die Route liegt hinter der Admin-Firewall wie jeder andere Admin-Bildschirm. Der Request dauert so lange wie der Lauf (das PHP-Zeitlimit wird auf 600 Sekunden gesetzt, die Session wird vor dem Lauf freigegeben, damit andere Admin-Tabs nicht warten). Das Ergebnis erscheint als Flash-Meldung: Erfolg, Warnung bei Abschneiden oder "läuft bereits", Fehler bei fehlenden Tabellen oder unbekanntem Channel.
Der Button läuft synchron und ist auf 600 Sekunden begrenzt. Der Lauf leert außerdem den Entity Manager und löst damit alles ab, was der Request geladen hat, darunter das User-Objekt des Administrators (es wird beim nächsten Request neu geladen). Das ist für kleine Kataloge in Ordnung, für große nimm den Console-Command oder einen Cronjob.
Console
Für jeden Channel oder einen bestimmten:
bin/console mmd:seo-suite-pro:audit:run
bin/console mmd:seo-suite-pro:audit:run --channel=shop
Der Exit-Code ist 0, wenn jeder Lauf abgeschlossen wurde, 1, wenn ein Lauf abgelehnt wurde (läuft bereits), am Limit abgeschnitten wurde oder fehlschlug, und 2 bei einem unbekannten Channel. Ein nächtlicher Cronjob um 03:30 Uhr:
30 3 * * * cd /var/www/shop && bin/console mmd:seo-suite-pro:audit:run --no-interaction
Das Dashboard und die Liste
Das Dashboard zeigt pro Channel den neuesten Lauf mit Zählern pro Check, den Button zum Starten und die 404-Pfade ohne Redirect. Die Funde-Liste ist ein reines Lese-Grid mit dem Stand des neuesten done-Laufs jedes Channels, filterbar nach Code des Produkts oder der Kategorie, Channel, Check, Schwere und Typ.
Eigene Checks
Implementiere Mmd\SyliusSeoSuiteProPlugin\Audit\AuditCheckInterface (oder erweitere AbstractAuditCheck). Jeder Service, der das Interface implementiert, wird automatisch mit mmd_sylius_seo_suite_pro.audit_check getaggt; mit priority am Tag legst Du die Reihenfolge fest. Der Runner ruft start() einmal pro Lauf, inspect() für jedes Produkt und jede Kategorie in jeder Sprache und finish() am Ende auf. Ein vollständiges Beispiel mit den Übersetzungsschlüsseln für die Labels findest Du unter Erweitern.
Einstellungen
Alle Schlüssel sind optional und stehen unter mmd_sylius_seo_suite_pro.audit:
| Einstellung | Standard | Beschreibung |
|---|---|---|
audit.keep_runs |
3 |
Anzahl der Läufe pro Channel, die erhalten bleiben |
audit.max_subjects |
20000 |
Produkte und, getrennt davon, Kategorien, die ein Lauf pro Channel höchstens prüft |
audit.stale_after_minutes |
10 |
Ein Lauf ohne Heartbeat für diese Zeit gilt als tot und blockiert nicht mehr |
audit.page_size |
200 |
Produkte oder Kategorien, die auf einmal geladen werden |
mmd_sylius_seo_suite_pro:
audit:
keep_runs: 3
max_subjects: 20000
stale_after_minutes: 10
page_size: 200
Kosten
Ein Lauf liest jedes aktive Produkt und jede aktive Kategorie des Channels einmal. Ohne SEO-Templates braucht eine Seite mit 200 Produkten eine konstante Zahl an Queries (die IDs, die Produkte mit allen Übersetzungen, die Bildzahlen, der Channel). Mit Templates kommen die Queries der Placeholder-Provider dazu (Attributwerte pro Produkt, {taxon.main} pro Produkt), genau so viel, wie das Rendern der Produktseite kostet. Dann wächst die Zahl der Queries mit der Zahl der Produkte. Das Schreiben der Funde ist ein Bulk-Insert pro Seite. Nichts davon läuft bei einem Shop-Request: Storefront und Shop API berühren die Audit-Tabellen nie.
Schritte im Host-Projekt
Nach jedem Update des Plugins führst Du mmd:seo-suite-pro:setup aus (siehe Installation), es legt die beiden Audit-Tabellen an. Ohne sie zeigt das Dashboard einen Hinweis statt der Zahlen, der Console-Command meldet die fehlende Migration, die Funde-Liste antwortet mit einem Fehler und der 404-Block funktioniert weiter. Storefront und Shop API sind nicht betroffen. Bei Problemen hilft Fehlerbehebung.
Shop API / Headless
Der Audit ist ein Back-Office-Feature: Ein Administrator startet ihn und liest ihn im Admin, kein Besucher und kein Headless-Frontend nutzt ihn. Die Logik liegt in AuditRunnerInterface und wird vom Console-Command und vom Dashboard-Button gemeinsam genutzt. Es gibt deshalb keine API-Resource dafür. Was die Shop API liefert, ist die SEO-Resource der Seiten selbst.