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

Statamic Xml Sitemap Laravel Package

mitydigital/statamic-xml-sitemap

A Statamic addon that generates XML sitemaps for your site, with support for multiple sitemaps, localization and automatic updates as content changes. Keep search engines informed and improve discoverability with minimal configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

The addon is a Statamic add-on, not a general Laravel package. It bootstraps through Statamic's addon discovery, publishes a config file, and registers a /sitemap.xml route that renders your content tree as XML. You describe what belongs in the sitemap; the package handles the route, the XML, and multi-site resolution.

  1. Require it and let Statamic auto-discover the service provider:
    composer require mitydigital/statamic-xml-sitemap
    
  2. Confirm what Composer actually installed. The repository is named statamic-xml-sitemap but the changelog, PR references, and config paths consistently use the older package name statamic-sitemapamic. Run composer show | grep -i sitemap before you go hunting for a config file — this is the first thing that wastes twenty minutes on this package.
  3. Publish the config:
    php artisan vendor:publish --tag=sitemapamic-config
    
    The published file lands at config/sitemapamic.php. This is the file you will live in — it holds the sitemap path, the collections and taxonomies to include, custom URLs, and priority/changefreq defaults.
  4. Request /sitemap.xml and view source. If you see your entries, the install is complete.

Where to look first: the config file, then the rendered XML. Do not start by reading the package source. The config is the entire public API surface for 90% of use cases, and curl -s https://yoursite.test/sitemap.xml | head -50 will tell you more than the code will.

First real use case: a blog collection whose entries live at /blog/{slug}. Add the collection to the config, verify the generated <loc> matches the Antlers route for one known entry, then re-request the sitemap. The single most common first-day failure is a sitemap full of 404s because the config's assumed route pattern and the actual front-end route have drifted apart. Validate one URL manually before validating a hundred.

Implementation Patterns

Treat the config as the single source of truth. Keep collection and taxonomy inclusion in config/sitemapamic.php so it is versioned, reviewable in a PR, and identical across environments. Resist adding a bespoke /sitemap.xml route for "just one extra section" — that is how you end up with two sitemaps, one of which is stale and neither of which anyone trusts.

Custom URLs for the edges. Landing pages, legacy paths, and externally hosted marketing pages belong in the custom URL set in config, not in a second route. Group them by purpose with comments. This list rots faster than anything else in the file and it is the one most likely to accumulate 404s, because nothing in your content workflow validates it.

Environment-aware config. Read env() inside config/sitemapamic.php for anything that differs per environment — absolute base URLs in particular. Staging sitemaps advertising production URLs (or vice versa) will get crawled and will poison your Search Console data.

Multi-site. Let the package resolve per-site URLs from each entry's site rather than hardcoding absolute hosts. One sitemap per domain is what search engines expect, and the per-site index behaviour is the primary reason to choose this package over a hand-rolled generator. If your multi-site install has different collections per site, scope the config accordingly rather than emitting every collection into every site's sitemap.

Filter by content state, in one place. Drafts, future-dated entries, and expired entries should not appear. Where the package doesn't do this for you, implement the rule once in config or in a single custom filter — not per collection. Equally, be explicit about noindex content: a URL that is noindex in markup but present in the sitemap sends crawlers a contradictory signal.

Priority and changefreq are conventions, not levers. Google ignores both in practice. Set them once to something defensible (homepage 1.0/daily, content entries 0.6/monthly), commit them, and stop thinking about them. Per-collection overrides are useful for diffing intent in PRs, not for ranking.

Cache deliberately. Decide whether the sitemap is generated on request or cached, and wire the corresponding invalidation into your publish workflow. If you cache the response, add a cache-bust to the content publish/unpublish path — otherwise editors will file a bug that a new entry is "missing" and you will spend an hour before remembering the cache. If you generate on request, watch the cost on large collections and eager-load anything you filter on.

Pair it with robots.txt and CI. The package gives you the XML; it does not advertise it. Add the Sitemap: line in the same PR, and add a smoke test that fetches /sitemap.xml, asserts HTTP 200 and an XML content type, and asserts at least one known URL appears. That one test catches route collisions, static-file shadowing, and 5xx regressions from Statamic upgrades.

Migration when a sitemap already exists. Stand the route up on staging, diff the generated URL set against the current sitemap (added, removed, changed), and only then cut over. Do not skip the diff — the removals are the interesting half.

Gotchas and Tips

Package name confusion. The repo is mitydigital/statamic-xml-sitemap; the changelog, config tag, and paths all say sitemapamic. Verify the installed package name with composer show before assuming a publish tag is missing. This trip-up is documented nowhere.

A static public/sitemap.xml silently wins. If a static file exists at that path, it shadows the Laravel route and the install appears inert — no error, no log entry, just an unchanged file. Check public/ first whenever "the sitemap isn't updating." Make removing it an explicit migration step.

3.5.1's empty-result filter is a fix that can hide a bug. The patch suppresses empty entries and empty result sets, which eliminates empty <urlset> output and blank <loc> values. But a collection that is misconfigured and resolves to nothing now looks identical to a collection that is legitimately empty. After upgrading from 3.5.0, re-fetch and diff — disappearing URLs are usually the fix working, but confirm they were genuinely empty and not a config error the filter is masking. Keep a habit of comparing entry counts in the Control Panel against <url> counts in the XML after any config change.

Cache layers stack. Statamic's static caching, a CDN, and Laravel's response cache can each serve a stale sitemap independently. When debugging, bypass all three — hit the origin directly and add a query-string buster — before you touch the package config. Most "sitemap is broken" reports resolve here.

Trailing slashes and host form. Pick one canonical form site-wide and enforce it. A sitemap whose URLs disagree with your actual routing is worse than no sitemap, because it manufactures redirect chains for every crawled URL.

50,000 URLs / 50 MB is a hard protocol ceiling. Confirm before a large import — not after — whether the package emits a sitemap index or requires you to shard by collection manually. The docs describe per-site index files for multi-site; they do not clearly promise sharding at the protocol limit. Plan for it.

hreflang alternates need verification, not assumption. Multi-site URL generation is a stated feature; language-alternate markup in the output is not clearly documented. Publish the view and inspect the raw XML before promising a multilingual client that alternates are handled.

Publish the view before post-processing the response. If you need <lastmod> semantics, image or news extensions, or alternate link elements, publish the package's view and edit the template. Do not regex a response object — that breaks silently on minor upgrades.

Pin explicitly. ^3.5 is right for the line; ^3.5.1 if you were affected by empty results. Update on a branch with --with-dependencies so transitive Statamic bumps land in the same, reviewed diff rather than arriving silently.

Monitor the endpoint as production surface. It is crawled, SEO-critical, and has no user-facing symptom when it breaks. A synthetic uptime check asserting HTTP 200 plus application/xml, and a periodic URL-count assertion to catch silent shrinkage, is cheap insurance for an agency-maintained package with no SLA.

Keep customisations in application code. Config and any custom URL logic live in your repo, not the vendor tree, so that a fork or replacement — at the next Statamic major, say — stays a contained change rather than a rewrite.

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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin