Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Sitemap Laravel Package

laravelium/sitemap

Framework-agnostic PHP package for generating XML, TXT, HTML, and Google News sitemaps. Works with Laravel, Symfony, or any PHP project, with support for images, videos, translations, alternates, and Google News. Includes extensible adapters and high test coverage.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation (pin the patched release):

    composer require rumendamyanov/php-sitemap "^1.0.4"
    

    v1.0.4 is a security release — it rejects path traversal in Sitemap::store() filenames. Any project that passes user-influenced or config-driven filenames to store() should upgrade from v1.0.3 or earlier before doing anything else. There are no API changes, so composer update is safe.

    For Laravel, publish the config (optional):

    php artisan vendor:publish --provider="Laravelium\Sitemap\SitemapServiceProvider"
    
  2. Basic Usage: Define a route to generate the sitemap:

    use Laravelium\Sitemap\Facades\Sitemap;
    
    Route::get('/sitemap.xml', function () {
        return Sitemap::create()
            ->add(url('/'), 1.0, 'daily')
            ->add(url('/about'), 0.8, 'weekly')
            ->render('xml');
    });
    
  3. First Use Case: Generate a simple XML sitemap for core routes. Test locally by visiting /sitemap.xml.


Implementation Patterns

Core Workflows

  1. Dynamic Sitemap Generation: Use closures to fetch dynamic URLs (e.g., blog posts):

    Sitemap::create()
        ->add(url('/posts'), 0.7, 'monthly')
        ->add(url('/posts/{id}'), 0.9, 'weekly', function ($sitemap) {
            return Post::all()->map(fn ($post) => $post->slug);
        });
    
  2. Multi-Language Support: Add hreflang tags for translated content:

    $sitemap->add(url('/post'), 1.0, 'daily')
        ->setLanguage('en')
        ->addAlternate(url('/post-es'), 'es');
    
  3. Writing to Disk with store() (the code path hardened in v1.0.4):

    // Safe: fixed, developer-controlled filename
    Sitemap::create()
        ->add(url('/'), 1.0, 'daily')
        ->store('sitemap', 'xml');
    
    // Safe: tenant slug validated before it reaches the generator
    $tenant = Tenant::where('slug', $request->route('tenant'))->firstOrFail();
    Sitemap::create()
        ->add(url("/{$tenant->slug}"), 1.0, 'daily')
        ->store("sitemaps/{$tenant->slug}", 'xml');
    

    Since v1.0.4 the library rejects traversal sequences (..), absolute paths, and other escapes in the filename. Treat that rejection as a validation layer, not a substitute for validating the slug yourself — a ValidationException from the generator is much harder to map to a 422 than a Rule::alphaDash() check.

  4. Image/Video Sitemaps: Extend the base class for rich media:

    use Laravelium\Sitemap\SitemapGenerator;
    use Laravelium\Sitemap\Items\Image;
    
    class VideoSitemap extends SitemapGenerator {
        public function addVideo($url, $title, $description) {
            return $this->add($url, 1.0, 'daily')
                ->addVideo($title, $description, url('/video-thumbnail.jpg'));
        }
    }
    
  5. Caching: Cache generated sitemaps for performance:

    Route::get('/sitemap.xml', function () {
        return Cache::remember('sitemap-xml', now()->addHours(6), function () {
            return Sitemap::create()->add(...)->render('xml');
        });
    });
    

Integration Tips

  • Laravel Routes: Use Route::get() for public sitemaps or Route::middleware(['auth']) for private ones.
  • Prefer render() over store() in request handlers. render() returns a string you hand to the response and never touches the filesystem, so the v1.0.4 traversal surface doesn't apply. Reach for store() only when you genuinely need a file on disk (CDN upload, static hosting, cron-generated sitemaps).
  • Queue Jobs: Offload sitemap generation to a queue for large sites:
    dispatch(new GenerateSitemapJob());
    
  • Testing: Mock the Sitemap facade in unit tests:
    $sitemap = Mockery::mock(Laravelium\Sitemap\Facades\Sitemap::class);
    $sitemap->shouldReceive('render')->andReturn('<xml>...</xml>');
    
    Add a regression test for any store() call that receives interpolated input — assert the generated file lands inside the expected directory and that a ../ payload is refused.

Gotchas and Tips

Common Pitfalls

  1. Path Traversal in store() (fixed in v1.0.4):

    • If you are on v1.0.3 or earlier, a filename containing ../ could write outside the intended output directory. Upgrade first, then audit every call site where the filename is built from a route parameter, tenant slug, locale, or DB column.
    • Even on v1.0.4, sanitise upstream:
      $request->validate(['name' => ['required', 'alpha_dash', 'max:100']]);
      
    • Don't wrap the rejection in a try/catch that silently swallows it — a refused filename usually means untrusted input reached the generator, which is worth an alert.
  2. URL Validation:

    • Ensure URLs are absolute (e.g., url('/path') instead of /path). Relative URLs may break validation.
    • Use str()->startsWith('http') to validate URLs before adding them.
  3. Change Frequency:

    • Avoid always for large collections (e.g., product pages). Use weekly or monthly instead.
    • Google ignores changefreq if lastmod is missing.
  4. Memory Limits:

    • Large sitemaps (>50MB) may hit PHP’s memory limit. Split into multiple files:
      Sitemap::create()->setLimit(3000)->render('xml'); // Max 3000 URLs per file
      
  5. Caching Headers:

    • Set Cache-Control headers to prevent proxy caching issues:
      return response(Sitemap::render('xml'))
          ->header('Cache-Control', 'public, max-age=86400');
      

Debugging Tips

  • Validate XML: Use an online validator (e.g., XML Validation) to catch malformed output.
  • Log Errors: Wrap sitemap generation in a try-catch to log issues:
    try {
        return Sitemap::create()->add(...)->render('xml');
    } catch (\Exception $e) {
        Log::error('Sitemap generation failed: ' . $e->getMessage());
        return response('Error generating sitemap.', 500);
    }
    
  • Verify the upgrade landed: composer show rumendamyanov/php-sitemap should report v1.0.4 or later. Security patches are easy to lose behind a stale composer.lock in CI or a Docker layer cache.

Extension Points

  1. Custom Items: Extend Laravelium\Sitemap\Items\Url for custom metadata:

    class CustomUrl extends Url {
        public function setCustomTag($name, $value) {
            $this->customTags[$name] = $value;
        }
    }
    
  2. Adapters: Override the default XmlWriter adapter for custom formats:

    use Laravelium\Sitemap\Adapters\AdapterInterface;
    
    class JsonAdapter implements AdapterInterface {
        public function render(array $items) {
            return json_encode($items);
        }
    }
    
  3. Service Provider: Bind custom sitemap classes in the service provider:

    $this->app->bind('custom.sitemap', function () {
        return new CustomSitemap();
    });
    
  4. Wrapping store(): If you subclass the generator or add your own writer, mirror the v1.0.4 behaviour — resolve the path with realpath()/Path::canonicalize() and assert the result is still inside the target directory before writing.

Config Quirks

  • Default Priority: The package defaults to 0.5 if not specified. Explicitly set priorities for critical pages (e.g., 1.0 for homepages).
  • Timezones: Ensure lastmod timestamps use UTC to avoid timezone-related issues:
    $sitemap->add(url('/post'), 1.0, 'daily', now()->tz('UTC'));
    
  • Version Floor: If your composer.json allows ^1.0, add a conflict rule so nobody installs back below the patch:
    "conflict": { "rumendamyanov/php-sitemap": "<1.0.4" }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style