Installation:
composer require dpn/xml-sitemap-bundle
Enable the bundle in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3):
Dpn\XmlSitemapBundle\DpnXmlSitemapBundle::class => ['all' => true],
Configure Routes:
Add the sitemap route to your routes.yaml (Symfony 4+) or routing.yml:
dpn_xml_sitemap:
resource: "@DpnXmlSitemapBundle/Resources/config/routing.xml.yml"
prefix: /
First Use Case:
Visit /sitemap.xml in your browser or via a crawler. The bundle auto-discovers routes annotated with @Route and generates a sitemap from them.
Edit config/packages/dpn_xml_sitemap.yaml (Symfony 4+) or app/config/config.yml:
dpn_xml_sitemap:
default_locale: en # Fallback locale for routes without locale prefixes
priority: 0.8 # Default priority for routes
changefreq: weekly # Default change frequency
exclude_paths: # Regex patterns to exclude routes
- /admin/
- /api/
Auto-Discovery: The bundle scans all routes with @Route annotations. Prioritize routes with:
/**
* @Route("/products/{slug}", name="product_show", defaults={"priority"=0.9, "changefreq"="daily"})
*/
public function show(Product $product) { ... }
Override defaults via defaults in @Route.
Excluding Routes:
Use exclude_paths in config or annotate routes:
/**
* @Route("/login", name="login", exclude_from_sitemap=true)
*/
Extend functionality with custom generators (e.g., for dynamic content like blog posts).
Step 1: Create a generator class:
use Dpn\XmlSitemapBundle\Generator\GeneratorInterface;
class BlogPostGenerator implements GeneratorInterface
{
public function generate(array $options)
{
$posts = Post::all(); // Fetch from DB
return array_map(function ($post) {
return [
'loc' => route('post_show', $post),
'lastmod' => $post->updated_at->format('Y-m-d'),
'changefreq' => 'weekly',
'priority' => 0.7,
];
}, $posts->toArray());
}
}
Step 2: Register the generator in config:
dpn_xml_sitemap:
generators:
blog_posts:
class: App\Generator\BlogPostGenerator
options:
limit: 50 # Optional: Pass to generator
Step 3: Reference in routing:
dpn_xml_sitemap.blog_posts:
path: /blog-sitemap.xml
For locale-aware routes (e.g., /en/products, /fr/products):
dpn_xml_sitemap:
default_locale: en
locales:
- en
- fr
Ensure routes use _locale routing parameter:
/**
* @Route("/products/{slug}", name="product_show", requirements={"_locale"="en|fr"})
*/
Trigger sitemap regeneration via console:
php bin/console dpn:xml-sitemap:generate
Or manually in a controller:
use Dpn\XmlSitemapBundle\Command\GenerateCommand;
public function regenerateSitemap()
{
$command = new GenerateCommand();
$command->run(new ArrayInput([]), new NullOutput());
}
Add a cron entry to regenerate sitemaps nightly (e.g., for dynamic content):
0 3 * * * cd /path/to/project && php bin/console dpn:xml-sitemap:generate --env=prod
Route Exclusion Overrides:
exclude_from_sitemap=true in @Route takes precedence over exclude_paths in config.Locale Mismatches:
_locale, the default_locale is used. Ensure all routes are locale-aware or configure default_locale correctly.Performance with Large Route Sets:
exclude_paths to filter aggressively or implement custom generators for dynamic data.Caching Issues:
php bin/console cache:clear
php bin/console dpn:xml-sitemap:generate
Deprecated Symfony Features:
AppKernel registration step may fail in Symfony 4+. Use config/bundles.php instead.Inspect Generated XML:
curl -s http://your-site.com/sitemap.xml | xmllint --format -
Look for missing/duplicate URLs or incorrect priorities.
Log Route Discovery: Enable debug mode and check logs for skipped routes:
monolog:
handlers:
main:
level: debug
Validate Against Protocol: Use Google’s Sitemap Tester to catch malformed entries.
Custom XML Output:
Extend Dpn\XmlSitemapBundle\Generator\XmlGenerator to modify the XML structure (e.g., add <image:loc> tags for image sitemaps).
Database-Backed Generators:
For large datasets, implement GeneratorInterface with pagination:
public function generate(array $options)
{
$page = $options['page'] ?? 1;
$posts = Post::paginate(100, ['*'], 'page', $page);
// Return paginated URLs
}
Event Listeners:
Hook into dpn_xml_sitemap.generate event to modify URLs dynamically:
use Dpn\XmlSitemapBundle\Event\GenerateEvent;
public function onGenerate(GenerateEvent $event)
{
$urls = $event->getUrls();
foreach ($urls as &$url) {
$url['loc'] = str_replace('http://', 'https://', $url['loc']);
}
}
Register in services.yaml:
services:
App\EventListener\SitemapListener:
tags:
- { name: kernel.event_listener, event: dpn_xml_sitemap.generate, method: onGenerate }
Priority/Changefreq Validation:
The bundle validates priority (0.0–1.0) and changefreq (always, hourly, daily, weekly, monthly, yearly, never). Invalid values default to config defaults.
Lastmod Handling:
lastmod is provided, the bundle uses the current timestamp.lastmod values.Index Sitemaps: To create a sitemap index (for large sites), use multiple routes:
dpn_xml_sitemap.main:
path: /sitemap.xml
dpn_xml_sitemap.blog:
path: /sitemap-blog.xml
Then manually create an index file or use a custom generator to aggregate URLs.
How can I help you explore Laravel packages today?