Skip to content

feat(seo): enumerate CMS routes in sitemap.xml and llms.txt - #348

Merged
arzafran merged 1 commit into
mainfrom
feat/cms-driven-seo-surfaces
Aug 4, 2026
Merged

feat(seo): enumerate CMS routes in sitemap.xml and llms.txt#348
arzafran merged 1 commit into
mainfrom
feat/cms-driven-seo-surfaces

Conversation

@arzafran

@arzafran arzafran commented Aug 4, 2026

Copy link
Copy Markdown
Member

What this does

A fork that keeps Sanity no longer throws away the sitemap and llms.txt and rewrites them: both now enumerate the CMS content automatically, through one shared helper, and a fresh clone with no CMS env still gets the static routes. A configured-but-broken CMS (bad project id, deleted dataset) degrades to static routes instead of 500ing the sitemap — found and reproduced during verification, not in the original issue.

Closes #319.

Summary

  • New `lib/seo/routes.ts`: `STATIC_ROUTES` + `getCmsRoutes()` gated on `isConfigured('sanity')`, URLs resolved through the same `urlForReference` the app uses for internal links, published-perspective + stega off so drafts never leak into crawler surfaces
  • `sitemap.xml` and `/llms.txt` both consume it; `/llms.txt` gains a Content section
  • `BASE_URL` exported once from `lib/seo/site.ts`; robots/sitemap/llms all resolve absolute URLs from it
  • `(examples)/sanity` deliberately excluded from both surfaces (wiring tutorial, not content)

Review order

  1. `lib/seo/routes.ts` — all the logic
  2. `app/sitemap.ts` / `app/llms.txt/route.ts` — consumers
  3. `lib/seo/site.ts` / `app/robots.ts` — the BASE_URL unification

Test Plan

  • `bun run check` → 421 pass
  • Prod build + curl with zero Sanity env: valid XML, absolute URLs, no undefined, no CMS section
  • Broken-CMS path reproduced (fake project id + token): 200 with static routes + logged warning, was a 500 before the try/catch

Copilot AI review requested due to automatic review settings August 4, 2026 18:34
@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
satus Ready Ready Preview Aug 4, 2026 6:34pm

@arzafran
arzafran merged commit 7fb9beb into main Aug 4, 2026
13 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR centralizes SEO route enumeration so sitemap.xml and /llms.txt can list both static routes and (optionally) Sanity-backed CMS content, while also unifying absolute URL construction via a single exported BASE_URL.

Changes:

  • Added lib/seo/routes.ts with STATIC_ROUTES plus getCmsRoutes() to fetch and normalize Sanity documents into routable paths.
  • Updated app/sitemap.ts and app/llms.txt/route.ts to consume the shared route helper so both surfaces enumerate the same URLs.
  • Exported BASE_URL from lib/seo/site.ts and updated app/robots.ts/app/sitemap.ts to use it for absolute URLs.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
lib/seo/site.ts Exports normalized BASE_URL for consistent absolute URL construction.
lib/seo/routes.ts Introduces shared static + Sanity CMS route enumeration logic.
app/sitemap.ts Builds sitemap entries from STATIC_ROUTES and getCmsRoutes() using BASE_URL.
app/robots.ts Switches sitemap URL to use BASE_URL.
app/llms.txt/route.ts Adds CMS-derived Content section via getCmsRoutes().
CHANGELOG.md Documents the new sitemap + /llms.txt behavior and BASE_URL unification.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/seo/routes.ts
Comment on lines +121 to +124
const path = urlForReference({
linkType: 'internal',
internalLink: { _type: doc._type, slug: doc.slug },
})
Comment thread lib/seo/routes.ts
Comment on lines +110 to +112
const parsed = z.array(routableDocumentSchema).safeParse(data)
if (!parsed.success) return []

Comment thread app/llms.txt/route.ts
Comment on lines +48 to +50
const links = cmsRoutes
.map((route) => `- [${route.label}](${SITE.url}${route.path})`)
.join('\n')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sitemap.ts and llms.txt ship as stubs, so every fork rewrites them

2 participants