Skip to content

Emit og:image from a cover URL string, not only a media object - #6

Merged
DanMat merged 1 commit into
mainfrom
fix/cover-og-image
Sep 7, 2026
Merged

DanMat merged 1 commit into
mainfrom
fix/cover-og-image

Conversation

@DanMat

@DanMat DanMat commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Flagged by the danmat.dev portfolio agent: blog posts emit no og:image for social/link previews even with a cover set.

Root cause (verified on the live site)

BlogHead does map coverog:image / twitter:image / JSON-LD image — but only when core hands it cover as a resolved media object {url, ...}. Core's EntryView produces that shape only for a media-typed field; a field of any other type comes through as a plain string, which the old is_array() check skipped.

danmat's blog.cover is declared text and holds an absolute image URL (e.g. https://danmat.dev/theme/assets/img/plates/aegis-03.jpg). So the theme rendered the hero from that string, but the head contributor received a string and emitted no image — on every post.

Fix

BlogHead now accepts either shape:

  • a media object {url} (unchanged), or
  • a text cover holding an http(s) absolute or site-relative /path URL.

A javascript: / data: / protocol-relative //host / bare-id value is rejected (no image, plain summary card) rather than emitted — same escape-by-default discipline as the canonical handling. The now-unused absolute() helper is removed.

Docs

README and the agent guide now describe cover as a media reference or an image URL, and note the ignored-unsafe-value behaviour.

Tests

A URL-string cover emits the image across OG/Twitter/JSON-LD; a site-relative cover is absolutised; unsafe strings yield no image; the media-object path is unchanged. phpstan L6 + cs-fixer clean.

Fixes preview images for all existing danmat posts with no content migration — though declaring cover as a media field is still the richer model (alt text, dimensions) whenever the site wants to move to it.
🤖 Generated with Claude Code

The SEO head only set og:image / twitter:image / JSON-LD image when core
handed it `cover` as a resolved media object ({url, ...}) — which core's
EntryView produces only for a `media`-typed field. A blog that models `cover`
as a `text` field holding an image URL (e.g. danmat.dev, whose covers are
absolute https URLs) got no preview image on any post, even though the theme
rendered the hero from the same string.

BlogHead now accepts either shape: a media object, or a `text` cover holding
an http(s) absolute or site-relative `/path` URL. A `javascript:`/`data:`/
protocol-relative/bare-id value is rejected (no image, plain summary card)
rather than trusted. Removes the now-unused absolute() helper.

Docs: README + agent guide describe cover as media OR a URL string.

Tests: cover as a URL string emits the image across OG/Twitter/JSON-LD;
site-relative is absolutised; unsafe strings yield no image; the media-object
path is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@DanMat
DanMat merged commit 90c9bf9 into main Sep 7, 2026
2 checks passed
@DanMat
DanMat deleted the fix/cover-og-image branch September 7, 2026 02:45
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.

1 participant