spatie/laravel-sitemap
Generate XML sitemaps for Laravel by crawling your site or building them manually. Add extra URLs, set last-modified dates, and include models via a simple interface. Write sitemaps to disk with a fluent, developer-friendly API.
Installation:
composer require spatie/laravel-sitemap
The package auto-registers.
First Crawl:
use Spatie\Sitemap\SitemapGenerator;
SitemapGenerator::create('https://example.com')
->writeToFile(public_path('sitemap.xml'));
Run via CLI:
php artisan sitemap:generate
First Manual Sitemap:
use Spatie\Sitemap\Sitemap;
use Spatie\Sitemap\Tags\Url;
Sitemap::create()
->add(Url::create('/home'))
->writeToFile(public_path('sitemap.xml'));
php artisan vendor:publish --provider="Spatie\Sitemap\SitemapServiceProvider" --tag=sitemap-configapp/CrawlProfiles/ (create custom profiles here)SitemapGenerator::create('https://example.com')
->getSitemap()
->add(Url::create('/static-page')->setLastModificationDate(now()))
->writeToFile(public_path('sitemap.xml'));
// Post.php
use Spatie\Sitemap\Contracts\Sitemapable;
class Post implements Sitemapable {
public function toSitemapTag(): Url {
return Url::create(route('posts.show', $this))
->setLastModificationDate($this->updated_at);
}
}
// Generate via crawler
SitemapGenerator::create('https://example.com')
->crawlWithModel(Post::class)
->writeToFile(public_path('posts_sitemap.xml'));
// app/Console/Commands/GenerateSitemap.php
SitemapGenerator::create(config('app.url'))
->writeToFile(public_path('sitemap.xml'));
// routes/console.php
Schedule::command('sitemap:generate')->daily();
use Spatie\Sitemap\SitemapIndex;
SitemapIndex::create()
->add('/posts_sitemap.xml')
->add('/pages_sitemap.xml')
->writeToFile(public_path('sitemap-index.xml'));
SitemapGenerator::create('https://example.com')
->hasCrawled(function (Url $url) {
return ! str_contains($url->getAbsoluteUrl(), '/admin');
})
->writeToFile(public_path('sitemap.xml'));
// config/sitemap.php
'execute_javascript' => true,
'chrome_binary_path' => '/path/to/chrome',
// Requires
composer require spatie/browsershot
Crawl Depth Limits:
3. Increase with ->depth(5) if needed.SitemapGenerator or via Crawler callback.Robots.txt Overrides:
robots.txt by default. Disable with:
->configureCrawler(fn($crawler) => $crawler->ignoreRobots())
Memory Issues:
->setConcurrency(2)) or chunk URLs.Dynamic Routes:
execute_javascript or manual Url additions.Sitemap Size Limits:
Sitemap::create()->chunk(1000)->writeToFile(...);
->hasCrawled(function (Url $url) {
\Log::info('Crawled:', [$url->getAbsoluteUrl()]);
return $url;
})
->writeToFile() before deploying to production.Custom Crawl Profiles:
Extend Spatie\Sitemap\Crawler\Profile to modify crawl logic (e.g., exclude auth routes).
URL Tag Customization:
Override Url tags via Sitemapable or hasCrawled callbacks:
->hasCrawled(function (Url $url) {
if ($url->segment(1) === 'blog') {
return $url->setChangeFrequency(Url::CHANGE_FREQUENCY_DAILY);
}
return $url;
})
Event Listeners:
Listen for sitemap.generated events to post-process sitemaps:
// app/Providers/EventServiceProvider.php
protected $listen = [
'sitemap.generated' => [SitemapPostProcessor::class],
];
Headless Chrome:
execute_javascript: false).config/sitemap.php:
'guzzle_options' => [
'timeout' => 30,
'headers' => ['User-Agent' => 'MyBot/1.0'],
],
writeToDisk('s3', 'sitemap.xml') for cloud storage (ensure visibility is set).->setCache(function () {
return Cache::remember('sitemap_crawl', now()->addDays(1), fn() => []);
})
How can I help you explore Laravel packages today?