Skip to content

feat(sitemap): add SEO image to per-collection sitemaps (<image:image>) - #1504

Merged
ascorbic merged 2 commits into
emdash-cms:mainfrom
swissky:feat/sitemap-image-support
Jun 16, 2026
Merged

ascorbic merged 2 commits into
emdash-cms:mainfrom
swissky:feat/sitemap-image-support

Conversation

@swissky

@swissky swissky commented Jun 16, 2026 •

Copy link
Copy Markdown
Member

What does this PR do?

Adds the entry's SEO image to EmDash's native per-collection sitemaps using the Google image-sitemap extension, so page images can be discovered and indexed for Google Images.

Today the sitemap (/sitemap-{collection}.xml) emits <loc> + <lastmod> (+ hreflang) but no images. Google's image SEO guidance recommends advertising a page's images (and a representative/"preferred" image) in the sitemap. This wires the existing _emdash_seo.seo_image — the same "preferred image" already used for og:image — into the sitemap:

<url>
  <loc>https://example.com/blog/my-post</loc>
  <lastmod>2026-06-15T09:35:41.837Z</lastmod>
  <image:image>
    <image:loc>https://example.com/_emdash/api/media/file/01ABC.webp</image:loc>
  </image:image>
</url>

Why only the SEO image (for now): it is the only image core knows generically across all collections and that is already a resolvable URL. Other images live in collection-specific media fields and in Portable Text bodies, and resolving those to correct (storage-key-based) URLs needs either per-image lookups or a usage index. That broader "all used images per page" work — plus a media "Used in" view and safe deletes — is proposed in a dedicated discussion as the natural follow-up.

Related discussion: #1503

Implementation

  • seo/media-url.ts (new): extracts the existing og:image URL-resolution logic into a shared buildSeoImageUrl() (no behaviour change; removes a private duplicate in seo/index.ts).
  • api/handlers/seo.ts: the sitemap query already LEFT JOINs _emdash_seo for the noindex flag — now also selects seo_image and returns it per entry.
  • astro/routes/sitemap-[collection].xml.ts: declares the xmlns:image namespace and emits one <image:image> per entry that has an SEO image.

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes (emdash package — ran clean)
  • pnpm lint passes (left to CI)
  • pnpm test passes (targeted: tests/integration/seo/*, tests/unit/seo/* — 72/72)
  • pnpm format has been run (left to CI)
  • I have added/updated tests for my changes (sitemap route: image present / absent; existing namespace assertion updated)
  • User-visible strings in the admin UI are wrapped for translation (if applicable) — n/a, this is XML output, no admin strings
  • I have added a changeset (if this PR changes a published package)
  • New features link to an approved Discussion: Media usage index — power image sitemaps, "Used in", and safe deletes #1503

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: Cursor + Claude Opus 4.8

Screenshots / test output

Test Files  3 passed (3)
     Tests  72 passed (72)

@changeset-bot

changeset-bot Bot commented Jun 16, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 547daa4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 14 packages
Name Type
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/admin Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
create-emdash Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added review/needs-review No maintainer or bot review yet area/core size/M labels Jun 16, 2026
@pkg-pr-new

pkg-pr-new Bot commented Jun 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@1504

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@1504

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@1504

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@1504

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@1504

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@1504

emdash

npm i https://pkg.pr.new/emdash@1504

create-emdash

npm i https://pkg.pr.new/create-emdash@1504

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@1504

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@1504

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@1504

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@1504

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@1504

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@1504

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@1504

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@1504

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@1504

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@1504

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@1504

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@1504

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@1504

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@1504

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@1504

commit: 547daa4

@ascorbic ascorbic left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks!

@ascorbic
ascorbic merged commit 8807701 into emdash-cms:main Jun 16, 2026
44 of 46 checks passed
@emdashbot emdashbot Bot mentioned this pull request Jun 16, 2026
@swissky
swissky deleted the feat/sitemap-image-support branch September 10, 2026 06:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core review/needs-review No maintainer or bot review yet size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants