Skip to content

Add OpenGraph images and SEO meta tags to plugin pages#407

Merged
simonhamp merged 2 commits into
mainfrom
plugin-page-meta-tags
Jun 30, 2026
Merged

Add OpenGraph images and SEO meta tags to plugin pages#407
simonhamp merged 2 commits into
mainfrom
plugin-page-meta-tags

Conversation

@simonhamp

Copy link
Copy Markdown
Member

Summary

Plugin listing pages had no per-plugin <title> or OpenGraph/Twitter tags, so social shares fell back to the generic site card. This adds proper SEO metadata and a generated OG image for every plugin, mirroring how blog posts already work.

What changed

  • SEO meta on plugin pagesPluginDirectoryController now sets the title, description, and OpenGraph/Twitter tags on both the plugin show and license pages (following the existing ShowBlogController pattern).
  • Generated OG images via TheOg — a queued GeneratePluginOgImage job renders an image to the public disk and stores its URL on a new plugins.og_image column. It's dispatched from PluginSyncService::sync() (the single content pipeline — webhooks, the customer create flow, and the SyncPlugin job) and from Filament EditPlugin::afterSave(), so images stay fresh. The OgImageService was refactored to share its rendering between articles and plugins; the article path is unchanged.
  • Plugin detail "pills"PluginOgLayout renders the plugin version, required nativephp/mobile constraint, and iOS/Android minimum versions (shown with a +, e.g. iOS 18.2+) as rounded pill badges. Intervention has no rounded-rectangle primitive, so PillBox composes a stadium shape from a rectangle + a circle at each end.
  • Backfill commandphp artisan plugins:generate-og-images [--missing] generates images synchronously for existing plugins (no queue worker required).
  • Cleanup — deleting a plugin removes its generated OG image.

Why

Shared plugin links (Slack, X, etc.) now show a branded, per-plugin card with the plugin's name, description, and platform/version support instead of a generic fallback.

Testing

  • New PluginShowSeoMetaTest (title + OG/Twitter meta, generated-image usage, default fallback, license page).
  • New PluginOgImageTest (job renders + stores the image, sync dispatches the job, delete cleanup, pill label composition incl. the + minimum behavior, backfill command).
  • PluginSyncServiceTest updated to fake the queue so it stays a focused unit test.

Note

Existing plugins won't have an image until their next sync/edit or a run of plugins:generate-og-images. Generation is queued, so a worker (Horizon) must be processing the queue.

🤖 Generated with Claude Code

Plugin listing pages had no per-plugin <title>/OpenGraph tags, so social
shares fell back to the generic site card. This adds:

- SEO/OG/Twitter meta (title, description, image) on the plugin show and
  license pages, mirroring the blog controller pattern.
- Generated OG images via TheOg (like blog posts): a queued
  GeneratePluginOgImage job renders to the public disk and stores the URL
  on a new plugins.og_image column. Dispatched from PluginSyncService and
  Filament EditPlugin so images stay fresh.
- A PluginOgLayout that renders plugin version, required NativePHP Mobile
  constraint, and iOS/Android minimums as rounded "pill" badges (composed
  from rectangles + circles via a PillBox feature, since Intervention has
  no rounded-rect primitive).
- A plugins:generate-og-images command to backfill existing plugins.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@simonhamp simonhamp marked this pull request as ready for review June 30, 2026 15:34
The plugin deleting hook resolves SatisService, whose constructor assigns
the (string-typed) api key from config. In CI SATIS_API_KEY is unset, so
the null config value triggered a TypeError. Mock the service in the
deletion test (matching existing Satis test conventions) since the test
only exercises OG image cleanup.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@simonhamp simonhamp merged commit 0c1081a into main Jun 30, 2026
2 checks passed
@simonhamp simonhamp deleted the plugin-page-meta-tags branch June 30, 2026 15:49
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