Generates the sitemaps configured in the Magento admin from the command line, and tells you where each one actually went.
Magento generates sitemaps from Magento\Sitemap\Model\Observer, a cron observer that catches every
exception and reduces it to a line on an e-mail almost nobody has configured. A run that produced
nothing is therefore indistinguishable from a run that worked. This command does the same generation
in the foreground, lets exceptions escape with their class, message and stack trace, and afterwards
verifies that the file it named really was written by this run.
composer require deployecommerce/module-sitemap-generate-cli
bin/magento module:enable DeployEcommerce_SitemapGenerateCli
bin/magento setup:upgrade
bin/magento sitemap:generate
bin/magento sitemap:generate --store-id=1
bin/magento sitemap:generate -v
Store 1: writing /var/www/html/pub/media/sitemap/sitemap.xml
Wrote 284913 bytes, modified 2026-08-07T09:14:02+00:00.
-v additionally prints the system temp directory Magento stages each file in, the filesystem driver
backing the target directory, and the number of URLs the item providers returned — an empty provider
result is the other way a run looks successful and produces nothing useful.
Exit code is 0 only when every sitemap in scope was verified. Any missing or stale file makes the
whole run fail, so this is safe to use as a deployment or monitoring check.
When remote_storage is configured in app/etc/env.php (the aws-s3 driver, for instance), the
media directory is backed by a different filesystem driver. Sitemap paths are stored relative to
pub, and the default path is under media/, so sitemaps are written to the remote bucket and the
local pub/media/sitemap/ copy is never touched. It keeps whatever was last written there before
remote storage was switched on, and its timestamp never changes again — which looks exactly like a
generation that silently stopped working.
This command handles that in two ways:
- A path under
media/is verified through the media directory, not throughpub. Verifying throughpubwould stat the stale local leftover and report success. - When the target directory is not backed by the local driver, it says so and prints the local path that is not being written, so the file you are about to go and check is not mistaken for output.
The closing line changes wording too. The size and timestamp are read back through the remote driver, so what the command reports is the object existing in the bucket, not an assumption that a write was dispatched:
Store 1: writing s3://example-bucket/media/sitemap/sitemap.xml
Remote storage is active (Magento\RemoteStorage\Driver\Adapter\CachedAdapter). The local copy at
/var/www/html/pub/media/sitemap/sitemap.xml is not written and its timestamp will not change.
Confirmed on remote storage (Magento\RemoteStorage\Driver\Adapter\CachedAdapter):
s3://example-bucket/media/sitemap/sitemap.xml, 284913 bytes, modified 2026-08-07T09:14:02+00:00.
The storefront serves the remote copy through pub/get.php.
After generating, the command stats the file and compares its modification time against the moment generation started. A file older than that is a leftover, not this run's output, and the run fails.
Remote drivers report the modification time as a date string rather than a Unix timestamp, and their
clock is not this server's clock, so there is a 60 second allowance either way. A file whose
modification time cannot be read at all is accepted and reported as modified unknown — an
unreadable timestamp is not evidence of a failure.
Sitemap generation reads frontend configuration, so it needs an area. The command claims
crontab — the area Magento's own sitemap cron runs under — but only when nothing has claimed one
already, because setting an area code twice throws.
Each sitemap is generated inside store emulation for its own store, and emulation is unwound in a
finally block so a failed generation still leaves the environment clean before the exception
surfaces.
composer install
composer test
Tests are written with Pest and need no Magento installation. Magento's own
packages are pulled from the public Mage-OS mirror, so no Adobe
credentials are required. That repositories entry only applies when this package is the root
package — Composer ignores it when the module is installed as a dependency.
MIT. See LICENSE.md.