XML-Sitemap: Technische Details
Technische Details der XML-Sitemap für Sylius 2: Ablauf der Generierung, Plugin-Struktur, Speicherlayout mit Sperrdatei, Aufbau des XML, Datenbanktabelle, Admin-Integration und Reader.
XML-Sitemap: Technische Details
Diese Dokumentation bezieht sich immer auf die aktuellste veröffentlichte Version.
Ablauf der Generierung
graph TD
A["Befehl oder Admin-Button"] --> B["SitemapRefresher"]
B --> C{"Einstellungen, Channel und Host in Ordnung?"}
C -->|Nein| D["SitemapGenerationException"]
C -->|Ja| E{"Sperre des Channels frei?"}
E -->|Nein| D
E -->|Ja| F["SitemapGenerator"]
F --> G["Provider: Produkte, Kategorien, Seiten, eigene"]
G --> H["Dateien nach URL-Anzahl und Größe teilen"]
H --> I["Index zuletzt schreiben"]
I --> J["Veraltete Dateien löschen"]
J --> K["Letzte Generierung speichern"]
SitemapRefresherlädt die Einstellungen und den Sylius-Channel, prüft beides und baut einenChannelContext(Hostname, Standardsprache, Sprachen, Menü-Taxon, Einstellungen). Alle Werte werden vorab kopiert, weil die Reader den Entity Manager zwischen den Blöcken leeren.- Die Sperre pro Channel wird nicht blockierend angefordert. Ist sie belegt, endet der Lauf sofort mit einer Meldung.
SitemapGeneratorprüft zuerst die Abschnittsnamen aller Provider, bevor irgendetwas geschrieben wird.- Die Provider laufen in der Reihenfolge ihrer Tag-Priorität. Jede URL wird über einen 60-Bit-Hash ihrer Adresse auf Dopplungen geprüft.
- Jeder Abschnitt wird in eine temporäre Datei gestreamt. Eine neue Datei beginnt, bevor die nächste URL eines der beiden Limits (
max_urls_per_file,max_bytes_per_file) überschreiten würde. Eine einzelne URL, die größer als das ganze Budget ist, bekommt eine eigene Datei. - Ohne jede URL entsteht
sitemap-empty-1.xml. - Der Index wird zuletzt geschrieben, danach werden veraltete Dateien gelöscht, die zum Muster
sitemap-<abschnitt>-<nr>.xmlpassen. Fremde Dateien im Ordner bleiben unberührt. - Jede Ausnahme außer
SitemapGenerationExceptionwird in eine solche umgewandelt, damit ein Fehler nur den betroffenen Channel betrifft. Nach dem Lauf werden Zeitpunkt und URL-Anzahl in der Einstellung gespeichert.
Plugin-Struktur
src/
Catalog/ Reader für Produkte und Kategorien (Doctrine, hinter Interfaces) und ihre Datensätze
Command/ mmd:sitemap:generate, mmd:sitemap:setup
Controller/ Auslieferung der Sitemap, Admin-Aktion Jetzt generieren
DependencyInjection/ Konfiguration und Extension
Entity/ ChannelSettings
Exception/ SitemapGenerationException
Form/Type/ Formular der Channel-Einstellungen
Generator/ Generator, Refresher, Channel-Kontext
Menu/ Eintrag in der Admin-Seitenleiste
Migrations/ Tabelle der Channel-Einstellungen
Provider/ URL-Provider und UrlProviderInterface
Settings/ Repository der Channel-Einstellungen
Sitemap/ Wertobjekte und XML-Writer
Storage/ Dateispeicher und Sperre
Twig/ Funktion sitemap_plugin_version()
Url/ URL-Bau über den Router, Hreflang, Bild-URLs
config/ services.php, Routen, Grid, Twig-Hooks
templates/ Titelblock und Button der Admin-Seite
translations/ Deutsch und Englisch
Speicherlayout
<storage_dir>/
<Channel-Code>.lock Sperrdatei
<Channel-Code>/
index.xml Sitemap-Index, ausgeliefert als /sitemap-index.xml und /sitemap.xml
sitemap-products-1.xml
sitemap-categories-1.xml
sitemap-pages-1.xml
Geschrieben wird über eine temporäre Datei im Zielordner, die an ihren Platz umbenannt wird. Dateinamen müssen auf [A-Za-z0-9_-]+.xml passen, weil der Name aus der URL kommt und den Ordner nicht verlassen darf. Die Sperre ist ein flock() pro Channel, das das Betriebssystem beim Prozessende selbst freigibt.
Aufbau des XML
Jede Datei ist ein urlset mit den Namensräumen für Sitemap, XHTML und Google-Bilder:
<url>
<loc>https://shop.example.com/de/products/beispiel</loc>
<lastmod>2026-10-01T10:00:00+00:00</lastmod>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
<xhtml:link rel="alternate" hreflang="de" href="https://shop.example.com/de/products/beispiel"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://shop.example.com/de/products/beispiel"/>
<image:image>
<image:loc>https://shop.example.com/media/image/ab/cd/bild.jpg</image:loc>
<image:title>Beispielprodukt</image:title>
</image:image>
</url>
Der Index ist ein sitemapindex mit loc und lastmod je Datei. Die URL-Fragmente sind nicht eingerückt, weil Leerraum nur Dateigröße kostet.
Datenbank
Eine Tabelle, mmd_sylius_sitemap_channel_settings, mit höchstens einer Zeile pro Channel. Der Channel wird über seinen Code zugeordnet, nicht über einen Fremdschlüssel, damit keine Tabelle des Sylius-Kerns gemappt werden muss.
| Spalte | Typ | Standard |
|---|---|---|
id |
int, Primärschlüssel | |
channel_code |
varchar(255), eindeutig | |
enabled |
bool | falsch |
include_products, include_taxons, include_static_pages, include_images, include_hreflang |
bool | wahr |
product_change_frequency, taxon_change_frequency |
varchar(16) | weekly |
static_change_frequency |
varchar(16) | monthly |
product_priority |
float | 0.8 |
taxon_priority |
float | 0.6 |
static_priority |
float | 0.5 |
last_generated_at |
datetime, nullable | |
last_url_count |
int, nullable |
Admin-Integration
Das Grid und die Twig-Hooks (Titelblock mit Plugin-Version, Button „Jetzt generieren“) bindet das Bundle ein, indem es die Konfiguration per Prepend vor die der Anwendung stellt, weil eine config/config.yaml des Plugins in einer echten Anwendung nicht geladen wird. Die Admin-Routen nutzen den Parameter %sylius_admin.path_name% statt eines festen Segments admin, damit sie bei einem geänderten Admin-Pfad weiter innerhalb von Firewall und Zugriffsregel liegen. Der Menüeintrag hängt in der gemeinsamen Gruppe „MMKreativ Plugins“.
Reader
Der Produkt-Reader holt zuerst eine Seite von 500 IDs (Schlüsselvergleich statt OFFSET), dann die Entitäten samt Übersetzungen und, falls Bilder gewünscht sind, Bildern, und leert danach den Entity Manager. Der Kategorie-Reader liest alle Taxons ab Ebene 1 in einer Abfrage in Nested-Set-Reihenfolge und überspringt in PHP den Unterbaum jedes deaktivierten Taxons.