CMS Dynamic OG Images: Wire Ghost & WordPress
To make a CMS generate a dynamic OG image, point your og:image meta tag at an endpoint that takes the post's title, author, and template as URL parameters and returns a 1200×630 PNG. In Ghost you inject the tag through code injection or a theme template; in WordPress you filter the og:image output. Set the template once, and every post ships a branded social card automatically — no per-post export, no design tool.
What is a dynamic OG image, and why wire it to your CMS?
A dynamic OG image is a social card built at request time from a post's metadata, rather than a static file you design and upload by hand. The og:image tag points at a generator endpoint — https://card.example.com/og?title=...&template=... — and that endpoint reads the parameters, composes the card, and returns a 1200×630 PNG. Your CMS already holds the title, author, and publish date; wiring it to a dynamic endpoint means those fields flow straight into a branded card with zero manual steps.
The payoff is consistency at scale. Manual cards drift — one post gets a designed image, the next gets nothing and falls back to a blank gray box. A dynamic endpoint guarantees every post gets the same branded, correctly-sized card.
Static uploads vs. dynamic generation: which fits your CMS?
| Manual upload per post | Dynamic OG endpoint | |
|---|---|---|
| Per-post effort | Design + export + upload each time | Zero — built from metadata |
| Brand consistency | Drifts as authors skip it | Enforced by the template |
| Correct 1200×630 size | Depends on the author | Guaranteed by the renderer |
| Title always current | Stale if the post is renamed | Re-renders from live metadata |
| Best for | A handful of cornerstone posts | Any blog publishing regularly |
Static uploads make sense for a few hand-tuned landing pages. For a blog that ships posts on a schedule, dynamic generation is the only approach that stays consistent without becoming a chore. If you want the underlying mechanics of the rendering layer, the dynamic OG image API guide covers how the endpoint itself works; this guide is about the CMS wiring.
How do you wire Ghost to a dynamic OG endpoint?
Ghost reads Open Graph tags from its theme and from any code you inject. The cleanest path is a theme template that outputs an og:image tag whose content is your endpoint URL with the post title encoded in:
{{!-- in default.hbs or post.hbs --}}
<meta property="og:image"
content="https://card.example.com/og?title={{encode title}}&template=dispatch" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
If you can't edit the theme, Ghost's Settings → Code injection site header is a fallback, though it can't read the per-post title the way a Handlebars template can — so prefer the theme route when you have it. Either way, the og:image value must be an absolute HTTPS URL; a relative path is the single most common reason a preview comes back blank.
How do you wire WordPress to a dynamic OG endpoint?
WordPress has no native Open Graph output, so the tag comes from either a plugin (Yoast, the OG plugin) or a theme filter. To inject a dynamic endpoint, filter the og:image value to your generator URL built from the current post title:
add_filter( 'wpseo_opengraph_image', function () {
$title = rawurlencode( get_the_title() );
return "https://card.example.com/og?title={$title}&template=verso";
} );
That hook targets Yoast specifically. If you run a different plugin, filter its equivalent output, or — on a custom theme — echo the og:image tag directly in wp_head. The principle is identical to Ghost: the title flows from post metadata into the endpoint URL, and the endpoint returns the card. For the full tag breakdown both CMSes depend on, see the Open Graph meta tag reference.
Why caching is non-negotiable for a CMS-wired endpoint
A dynamic endpoint renders on demand, which sounds expensive — but platforms scrape each URL once and store the result. The first time Facebook or Slack fetches your card, it renders; every share after that hits the platform's cache. The job on your side is to cache the rendered PNG keyed by title and template so even the first scrape of a re-shared post is cheap.
Keep the parameter set small and stable. If your URL encodes a timestamp or a session value, every request is a cache miss and the card changes on every scrape — which can desync the preview a platform already stored. Title and template are enough.
The one-line takeaway
Wire your CMS once: output an og:image tag that points at a dynamic endpoint and passes the post title, then cache the result by title and template. Every Ghost or WordPress post ships a branded 1200×630 card with no manual work. Doing exactly that — deriving your brand kit, then auto-generating a correct card for every post — is what Social Card Studio is built for. When a preview still won't render, work through Why Your Link Preview Is Broken.
Frequently asked questions
How do I generate a dynamic OG image from my CMS?
Point your og:image meta tag at a dynamic endpoint that takes the post's title, author, and template as URL parameters, then renders a 1200×630 PNG on demand. In Ghost you inject the tag through code injection or a theme template; in WordPress you filter the og:image output. The endpoint reads the parameters and returns a branded card.
Why use a dynamic OG image instead of uploading one per post?
A dynamic endpoint builds the card from post metadata at request time, so every post gets a branded, correctly-sized 1200×630 image without manual design work. You set the template once; the title, author, and colors fill in automatically for every post you publish.
Can a dynamic OG image work with caching?
Yes, and it should. Cache the rendered PNG keyed by the post's title and template so repeat scrapes hit the cache instead of re-rendering. Platforms like Facebook and Slack scrape the URL once and store it, so the first render cost is paid once per unique card.