vormkracht10/laravel-open-graph-image
A Laravel package for generating dynamic Open Graph images for social sharing. Build templates with Blade, add titles and branding, and serve cached preview images for pages, posts, or models without manual design work.
composer require backstagephp/laravel-og-imagephp artisan vendor:publish --tag="og-image-config" (and the views tag if you plan to customise templates).config/og-image.php first. This is where the day-to-day behaviour lives: the route/prefix that serves generated images, the default template, output dimensions, cache disk/path, TTL, and the browser binary used for rendering. Get the binary path right before writing any templates.{{-- resources/views/layouts/app.blade.php --}}
<meta property="og:image" content="{{ og_image()->for(auth()->user()?->name ?? config('app.name')) }}">
<meta name="twitter:card" content="summary_large_image">
og:image URL, and open it directly in the browser. If it renders, the rest is template work. If it 500s, it is almost always the headless browser/binary (see Gotchas).First real milestone: one template rendering correctly for one page type, cached, with the URL absolute and https.
One template per page type, not per page. Register templates for default, blog-post, product, author, etc., and select by context. Keep templates dumb — they should receive a small array of already-resolved strings. Building data inside Blade gets ugly fast when you later want to warm images.
Model-driven image resolution. A common pattern is a small accessor or dedicated OgImageData object on the model so both the meta tag and the warmer use the same source:
public function ogImage(): string
{
return og_image()->template('blog-post')->for([
'title' => $this->title,
'subtitle' => $this->author->name,
'eyebrow' => $this->published_at->format('M j, Y'),
]);
}
Then in Blade: <meta property="og:image" content="{{ $post->ogImage() }}">.
Never render on the hot path. The meta tag should point at a cached/static URL. Enable caching in config and let the first request (or the warmer) pay the render cost. If you serve through a CDN, the generated file should be content-addressed or versioned so a deploy invalidates it.
Prewarm on deploy (v1.4.0). php artisan og-image:warm generates images ahead of traffic. Wire it into your deploy script after migrate and before you flip symlinks/traffic:
php artisan migrate --force
php artisan og-image:warm
php artisan optimize
Scope what it warms. For a handful of marketing pages, a configured URL list is fine. For per-model images (thousands of posts), warm only what changed rather than everything on each deploy — run it nightly or chunked, and let organic traffic fill the long tail. Treat the warmer as a queue-agnostic backfill, not a per-deploy requirement.
Larastan integration (v1.4.0). The package now boots under Larastan so PHPStan resolves the package's view strings. Practically: if you were carrying @phpstan-ignore comments or ignore-errors entries around view('og-image::...') calls, drop them and re-run the analyser. If you keep custom templates in your app, the same benefit applies to your own view() calls returning og-image templates. Ensure your Larastan version is the one that supports package bootstrapping, and that static analysis runs with the package's service provider discoverable (i.e. not excluded in phpstan.neon).
Integration tips.
local and in CI, point the config at a stub/fixture image or disable generation entirely — you rarely need real renders in feature tests.og:image:width / og:image:height pair matching your configured dimensions; several crawlers use it to avoid a second fetch.og:image is never empty.APP_URL or the trusted-proxy/HTTPS scheme is wrong, the meta tag emits http:// or an internal hostname. Some crawlers silently drop the image. Check the emitted tag from outside the container.og-image:warm in CI without a browser. The newer command will fail hard in slim images (Alpine, distroless) lacking Chromium and its shared libs. Install the runtime deps and set the binary path in config; use --no-sandbox in containerised environments. Same failure mode applies to request-time rendering, so this is worth pinning down early.php artisan config:cache will freeze your og-image config. If you change the binary path or dimensions in a running environment, remember to re-cache.How can I help you explore Laravel packages today?