octave/sitemap-bundle
Octave SitemapBundle generates XML sitemaps for Symfony applications, letting you register URL providers, set priorities and change frequencies, and output sitemap indexes with automatic caching and ping support for search engines.
This is a Symfony bundle (Octave CMS ecosystem), not a Laravel package. Before writing any code, confirm the framework fit — it will not autoload as a Laravel package and has no ServiceProvider. If your target is Laravel, treat it as a reference implementation or a standalone CLI generator, not a runtime dependency.
Minimal steps (Symfony/Octave target):
Install and pin
composer require octave/sitemap-bundle:"x.y.*"
Pin explicitly — see Gotchas for why floats are dangerous here.
Register the bundle in config/bundles.php:
return [
// ...
Octave\SitemapBundle\OctaveSitemapBundle::class => ['all' => true],
];
Import routes in config/routes.yaml (verify the file path against the bundle — it ships routing config, not attributes):
octave_sitemap:
resource: '@OctaveSitemapBundle/Resources/config/routing.xml'
Look here first, in this order:
README for the exact route prefix and config tree.DependencyInjection/Configuration.php — the authoritative list of options (base URL, include/exclude, cache TTL, file names, index settings)./sitemap.xml — the read path you'll override or extend.SitemapGenerator / UrlProvider service — where dynamic entries are assembled.First use case — confirm end-to-end:
curl -i http://localhost:8000/sitemap.xml
Expect 200, application/xml, root <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> with your configured URLs. 404 = route import wrong. HTML = a catch-all route shadowing the bundle route.
Laravel-specific first step: run a one-day spike in a scratch service (or a minimal Symfony kernel) that emits XML for your actual URL shapes, and diff that output against the sitemap XSD. Do not attempt to wire the bundle into a Laravel ServiceProvider — a bundle's container/configuration semantics don't translate, and you'll burn the day on shims instead of validating output.
Static/config-driven sitemap. Day-one pattern: define the URL list (or route names) in the bundle config, let the bundle render. Fine for marketing pages and a handful of fixed routes. Do not grow this into dynamic content — it becomes an unmaintainable config file.
Dynamic generation from Doctrine. For products/CMS content, inject the bundle's generator service and feed entities:
$sitemap
->add($router->generate('product_show', ['id' => $product->getId()], UrlGeneratorInterface::ABSOLUTE_URL))
->setLastMod($product->getUpdatedAt())
->setChangeFreq('weekly')
->setPriority(0.8);
Filter to published/visible entities. Draft leakage into a public sitemap is the classic mistake.
Sitemap index for scale. Past ~50,000 URLs or 50 MB uncompressed, emit multiple files (sitemap-products-1.xml, sitemap-posts.xml, …) and expose a <sitemapindex> at /sitemap.xml. A single monolithic file is a scalability trap and often trips a timeout before it trips the 50k limit.
Caching + warm-up. Sitemaps are read-heavy, write-light. Enable the bundle's cache, then warm it from a console command scheduled outside request time. Cron-driven generation to object storage/CDN is the pattern real sites use; generating on-request is acceptable only for very small sites.
Offline/CLI generation. Run generation as a job/sidecar that writes to object storage, not in the request path. This is the only viable pattern for Laravel consumers: the bundle runs in its own Symfony process and outputs XML that Laravel serves as a static asset.
Adapter behind a contract (for Laravel). If adopting, wrap the output behind an internal interface such as SitemapGenerator::generate(): string so the app depends on XML, not on Octave\SitemapBundle\* classes. That keeps a swap to a Laravel-native generator or a managed sitemap service to a one-afternoon change.
Locale and content-type sharding. If you have locales, shard by locale (sitemap-en.xml, sitemap-de.xml) with hreflang annotations at the index level. This keeps memory bounded and makes incremental regeneration possible.
Framework mismatch is a hard stop, not a trade-off. -bundle means Symfony Kernel + DI + routing assumptions. Installing into a Laravel app via Composer may pull Symfony components that conflict with Illuminate. Treat it as reference-only for Laravel unless you're running it out-of-process.
Zero adoption signals = you own it. 0 stars, 0 dependents, no external bug reports, no compatibility pressure. Pin the version, vendor/fork if needed, and track upstream changes manually. Budget for PHP/Symfony upgrades as an ongoing tax.
Verify license and version matrix before the spike. License, supported PHP/Symfony versions, and whether the bundle has Octave-specific coupling are unknown from the description — confirm in the composer.json and by attempting a clean install in an empty Symfony skeleton.
Unverified feature coverage. Confirm explicitly whether the bundle supports: gzip, 50k-URL sharding, sitemap index, lastmod propagation, locale/hreflang, image/video/news sitemaps, cache invalidation on content change. A package at this maturity likely lacks several. Assume not, then verify.
Debugging order for a "not working" sitemap:
bin/console debug:router | grep sitemap — is the route registered?bin/console debug:config octave_sitemap — is the config actually applied (correct bundle key)?curl -i and inspect headers — HTML response means a catch-all route is shadowing.<urlset> usually means the config or provider list is empty, not a rendering bug.var/log/ — the bundle's generator service may be swallowing exceptions during URL assembly.Stale sitemaps are the silent failure mode. Content changes won't invalidate the cache automatically unless the bundle wires that. Add a freshness assertion (generation timestamp embedded or monitored) and re-generate on content publish via a queued job or scheduled command.
Route leakage risk. If URL discovery enumerates routes, it can expose admin/private paths. Use explicit include lists or a deny list for anything not intended for crawl. Verify the output against production URL samples before deployment.
Do not mix Symfony and Laravel containers in one process. If you must run the bundle adjacent to a Laravel app, isolate it as a separate container/CLI — attempting to bootstrap both in the same request cycle invites subtle DI failures that are expensive to debug.
Extension points you'll likely need: a custom UrlProvider-style service to feed domain entities, a custom controller to override the output path/headers, and config overrides from config/services.yaml. Confirm these exist by inspecting the bundle's DI extension before assuming you can hook them.
Rollback plan. Keep the previous sitemap served alongside the new one (e.g., /sitemap-old.xml) and canary through Search Console coverage comparison before cutting over. Sitemap problems are cheap to fix with a rollback and expensive to diagnose after crawlers have re-indexed.
Time-box the evaluation. One day: generate a real sitemap for representative URL shapes, diff against the XSD and against a mature alternative (e.g., spatie/laravel-sitemap for Laravel or prestaconcept/sitemap-bundle historically for Symfony), and decide on maintainability, not feature count.
How can I help you explore Laravel packages today?