Skip to content

feat(blog): custom hero, OG and blog card images for articles#425

Merged
simonhamp merged 1 commit into
mainfrom
blog-og-hero-images
Jul 10, 2026
Merged

feat(blog): custom hero, OG and blog card images for articles#425
simonhamp merged 1 commit into
mainfrom
blog-og-hero-images

Conversation

@simonhamp

Copy link
Copy Markdown
Member

What

Articles can now have a custom hero image uploaded in the admin. From that single upload, three derivatives are generated, each with its own admin-adjustable crop:

  • Social (OG) image — 1200×630 (TheOG's dimensions), written to the same og-images/{slug}.png path, so it replaces the TheOG-generated image in og:image/Twitter meta while a hero exists. Remove the hero and the article reverts to TheOG generation.
  • Blog card preview — 1200×450, rendered flush at the top of /blog cards (≤200px tall, clipped by the card's rounded corners).
  • Article header — 2048×1000 (2× retina), rendered at the top of the article page at up to 500px tall.

Also renames the admin Articles section to Blog (nav label, breadcrumb, list title — no class renames) and stacks the article form labels instead of inline.

How

  • ImageCropper Filament field (app/Filament/Forms/Components/ImageCropper.php + blade): a dependency-free Alpine crop tool — aspect-locked drag/resize selection box storing {x, y, width, height} rects as JSON. Crops are non-destructive and re-adjustable at any time without re-uploading. The Croppie plugin was considered but it requires Filament ^3.2 (this app is on v5) and only supports destructive upload-time crops, one file per field.
  • ArticleImageService: scales oversized heroes down in place (max 2400px wide), generates the three crops via Intervention Image (already a direct dependency), clamps/centers invalid or missing crop rects, and handles file cleanup when the hero is replaced, the slug changes, the hero is removed, or the article is deleted.
  • Uploads validated to min 1200×630. Crop selections appear after saving (create redirects to edit); replacing the hero resets crops to centered defaults.

Testing

  • 13 feature tests covering derivative generation/dimensions, crop selection + clamping, hero downscaling, TheOG fallback, file lifecycle, page rendering, and the Filament save flows.
  • Full suite green: 1199 tests. Note: the full suite needs memory_limit > 128M (peaks ~259MB) — this is pre-existing (confirmed on a clean main worktree), Herd's default CLI limit fails partway through the suite either way.
  • Verified end to end in the browser: cropper init/restore math, UI save → regenerated OG image reflecting the selected crop (pixel-checked), card/header/og:image rendering, and deletion cleanup.

🤖 Generated with Claude Code

…rop tools

Articles can now have a hero image uploaded in the admin. From one upload,
three derivatives are generated with admin-adjustable crop selections:
- OG image (1200x630, replaces TheOG-generated image while present)
- blog card preview (1200x450, shown atop /blog cards)
- article header (2048x1000, shown atop the article at up to 500px tall)

Includes a dependency-free Filament ImageCropper field (Alpine), an
ArticleImageService for scaling/cropping via Intervention Image, file
lifecycle cleanup on replace/slug change/delete, stacked form labels,
and the admin 'Articles' section renamed to 'Blog'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@simonhamp simonhamp marked this pull request as ready for review July 10, 2026 16:43
@simonhamp simonhamp merged commit 77a1cb9 into main Jul 10, 2026
2 checks passed
@simonhamp simonhamp deleted the blog-og-hero-images branch July 10, 2026 17:36
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