XML Sitemap: Generation and Serving
Generating the sitemap with mmd:sitemap:generate or the admin button, fetching sitemap-index.xml, file splitting, selection rules for products and categories, hreflang, images and the per-channel lock.
XML Sitemap: Generation and Serving
This documentation always describes the latest published version.
Generating the sitemap
Console command
bin/console mmd:sitemap:generate
bin/console mmd:sitemap:generate --channel=WEB
| Option | Short | Description |
|---|---|---|
--channel |
-c |
Generate only this channel (channel code). Without the option, all enabled channels run |
The command prints a table with channel, URLs, files and time. An error in one channel is reported for that channel and does not stop the others. If at least one channel failed, the command exits with a failure status, which matters for cron jobs and monitoring. If no channel has the sitemap enabled, it prints a warning and exits successfully.
Admin button
On the page MMKreativ Plugins → XML sitemap, the Generate now button starts the generation of all enabled channels. The result appears as one message per channel, and the grid then shows the URL count and the time.
The button runs synchronously inside the web request. For a very large catalog, use the console command.
Fetching the sitemap
The sitemap index is served on the host of the respective channel:
| URL | Content |
|---|---|
/sitemap-index.xml |
Sitemap index |
/sitemap.xml |
The same index, under the name crawlers try when nothing else is known |
/sitemap/<name>.xml |
A single sitemap file, for example /sitemap/sitemap-products-1.xml |
The index lists one file per content type, so it is clear what each file contains:
/sitemap/sitemap-products-1.xml products (and their images)
/sitemap/sitemap-categories-1.xml categories
/sitemap/sitemap-pages-1.xml static pages
A content type with more URLs than fit into one file continues as sitemap-products-2.xml and so on. A content type without any URL gets no file. A channel with no URL at all gets one empty file sitemap-empty-1.xml so the index stays valid.
Serving answers with 404 if the host belongs to no channel, no enabled setting exists for the channel, or the sitemap has not been generated yet. Responses carry Content-Type: application/xml; charset=UTF-8 and the header X-Robots-Tag: noindex, so the XML itself never shows up as a search result.
A response is only publicly cacheable (one hour) when no session was started for the request. Files are served uncompressed; let the web server compress them.
What ends up in the sitemap
| Content | Source | Notes |
|---|---|---|
| Products | Enabled products assigned to the channel | One URL per language the product has a slug for. lastmod comes from the product |
| Categories | The channel's menu taxon and everything below it. If no menu taxon is set, all non-root taxons of all trees | lastmod comes from the taxon. If the menu taxon is itself a tree root, only its subtree is included |
| Static pages | The routes from static_routes |
One URL per language of the channel, without lastmod |
| Images | Product images | Per product URL, titled with the product name in that language |
A disabled taxon hides its whole subtree, even if individual subcategories are enabled. The root of a taxon tree is a pure grouping node and does not appear in the sitemap.
Hreflang
Every language of the channel gets its own URL that contains all language versions as alternates, its own included, plus x-default pointing at the default-language URL. Language codes are written with a hyphen (de-DE instead of de_DE).
Hreflang only appears when a page has at least two distinct language URLs. A shop whose routes carry no {_locale} placeholder serves every language from one URL and therefore gets none. Languages the router cannot build a URL for are left out instead of aborting the generation.
Images
An image path that is already an absolute URL with http:// or https:// (CDN) is used as it is. Anything else becomes <scheme>://<channel host>/<image_base_path>/<path>.
Flow and safety
- Only one generation per channel runs at a time. A second start, such as a cron job while someone presses the button, is refused with a message instead of racing the first. The lock is released automatically if a process dies.
- Files are written atomically. The index is written last and stale files are deleted only afterwards. A crawler that fetches the index mid-run therefore never follows a link to a file that does not exist yet or no longer does.
- A URL returned by several providers appears only once in the sitemap, in the file of the first provider.
Twig storefront and headless
The sitemap is a machine-readable XML document for crawlers, not a storefront feature. There is therefore no Twig page, no API Platform resource and no separate Shop API. It is served identically for a Twig storefront and a headless frontend, as long as the channel's host routes /sitemap-index.xml to Sylius. The admin screen is back-office only.
graph TD
A["Request for sitemap-index.xml"] --> B{"Host belongs to a channel?"}
B -->|No| C["404"]
B -->|Yes| D{"Sitemap enabled for the channel?"}
D -->|No| C
D -->|Yes| E{"File exists?"}
E -->|No| C
E -->|Yes| F["Serve XML"]