
Wildcards in Content SDK Part 1: Sitemap
Learn how to extend the Sitecore Content SDK in XM Cloud to publish custom sitemap documents for blogs, products, and other bespoke routes—complete with GraphQL lookups and middleware wiring
The out-of-the-box XM Cloud sitemap endpoint is great for letting the platform manage discovery, but many projects need to blend Sitecore-managed URLs with links that live in other systems. More often than not, a requirement comes along for a Wildcard style setup is needed for your project. Let's say you have a base page for your product details but you want the URL to have the product name in the path for SEO purposes.
In this walkthrough we’ll wire up a custom SitecoreClient, layer in bespoke sitemap helpers, and expose everything through the Content SDK middleware so editors still control the core sitemap experience. The examples below are taken from a recent demo where we shipped product and blog sitemap slices alongside the generated XM entries.
Prerequisites
- XM Cloud project bootstrapped with the Sitecore Content SDK for Next.js.
- A GraphQL endpoint exposed through
sitecore.config. - Basic familiarity with Next.js API routes and middleware.
Extending the Stock Sitecore Client
The Content SDK ships a SitecoreClient implementation that already knows how to query the sitemap service. We subclass it to add three behaviors:
- Build a sitemap index that lists the original XM-generated chunks plus our custom documents.
- Proxy “main” sitemap requests back to the XM GraphQL service safely (including double-digit indexes).
- Delegate any other IDs (e.g.,
Blogs,Products) to our bespoke sitemap builders.
A subtle bug I hit early on: parsing the last character from sitemapMain-10.xml treated it as page 0. The regex guard above fixes that by capturing the full numeric suffix and returning a 404 for anything that doesn’t match the expected pattern.
Finally, make sure the extended client is what your API route imports:
Authoring Sitemap Helpers
With the transport layer in place we can focus on the XML payloads. The helpers file keeps everything composable:
Key points:
BuildCustomSitemapLinksreturnsnullfor unsupported IDs so the client can throw a 404.BuildSitemaptolerates malformed URLs (handy during authoring) but still normalizes known good ones.BuildSitemapIndex(not shown) throws if any entry can’t be parsed, which surfaces configuration issues quickly.
Hydrating Blog Links from Sitecore
Custom sitemaps only help if they reflect live content. The blog sitemap reads from a bucket in XM Cloud via GraphQL:
The corresponding client method is reused elsewhere, so we documented it and ensured it always returns an array:
If the bucket is empty we emit an empty <urlset> so search engines keep the URL but don’t index stale entries.
Stubbing External Product Data
The demo mimics a commerce feed:
callProductApi currently resolves hard-coded data, but centralising it makes it trivial to swap in a real HTTPS call later without touching the sitemap plumbing.
Surfacing the Endpoint
The only change inside the API route is wiring the new client through the Content SDK middleware:
Because IdkSitecoreClient extends the base client, we retain the XM Cloud DX-friendly workflow (editors still manage the core sitemap settings) while gaining full control over extra documents.
Testing the Flow
npm run lintstays green because the comments match the existing Prettier configuration.npm run next:buildvalidates the middleware installs correctly; the sitemap URLs render expected XML.- Try curl http://localhost:3000/sitemap.xml and the generated
sitemapMain-0.xml,sitemapBlogs.xml, andsitemapProducts.xmlendpoints to confirm the routing logic.
Wrapping Up
By subclassing the Content SDK client and isolating sitemap helpers, we extended XM Cloud’s sitemap support without forking the middleware or managing raw Express handlers. You can add more slices (e.g., news, careers) by dropping in new helper functions and registering their IDs. As you move from stubs to production integrations, harden the external calls (timeouts, retries) and consider caching the generated XML for higher-traffic endpoints. As always, you can view the code sample here on my Public GitHub Profile. Happy Coding!