Headless WordPress: OG images on publish

No plugin to install, no marketplace review: a mu-plugin (one PHP file in wp-content/mu-plugins/) calls the OGImagen API when a post is published and stores the permanent image URL in post meta. Your Next.js / Astro frontend reads it over REST or WPGraphQL.

1. The mu-plugin

<?php
/**
 * Plugin Name: OGImagen on publish
 * Drop into wp-content/mu-plugins/ogimagen.php
 * Define OGIMAGEN_API_KEY (and optionally OGIMAGEN_BRAND_KIT_ID) in wp-config.php.
 */
add_action('transition_post_status', function ($new, $old, $post) {
    if ($new !== 'publish' || $post->post_type !== 'post') return;
    if (get_post_meta($post->ID, 'ogimagen_url', true)) return; // already done

    $res = wp_remote_post('https://ogimagen.com/api/v1/templates', [
        'timeout' => 20,
        'headers' => [
            'Authorization' => 'Bearer ' . OGIMAGEN_API_KEY,
            'Content-Type'  => 'application/json',
        ],
        'body' => wp_json_encode([
            'template'   => 'blog',
            'title'      => get_the_title($post),
            'siteName'   => wp_parse_url(home_url(), PHP_URL_HOST),
            'brandKitId' => defined('OGIMAGEN_BRAND_KIT_ID') ? OGIMAGEN_BRAND_KIT_ID : null,
        ]),
    ]);
    if (is_wp_error($res)) return;

    $data = json_decode(wp_remote_retrieve_body($res), true);
    if (!empty($data['url'])) {
        update_post_meta($post->ID, 'ogimagen_url', esc_url_raw($data['url']));
    }
}, 10, 3);

// Expose the meta field to REST + WPGraphQL consumers.
add_action('init', function () {
    register_post_meta('post', 'ogimagen_url', [
        'show_in_rest' => true,
        'single'       => true,
        'type'         => 'string',
    ]);
});

That's the whole integration for the template path: synchronous, deterministic, zero credits, every post carries the same branded layout.

2. Read it from the frontend

// Next.js App Router
export async function generateMetadata({ params }) {
  const post = await fetch(
    `${WP_URL}/wp-json/wp/v2/posts?slug=${params.slug}`
  ).then((r) => r.json()).then((p) => p[0]);

  return {
    openGraph: {
      images: post.meta?.ogimagen_url ? [post.meta.ogimagen_url] : [],
    },
  };
}

Using Yoast alongside? Write the same URL into _yoast_wpseo_opengraph-image and Yoast's yoast_head output picks it up, no frontend change needed.

3. Optional: AI for hero posts

Swap the endpoint for /api/v1/generations on posts with a custom field flag. AI is async, so pass webhookUrl pointing at a tiny REST route (or a serverless function) that runs update_post_meta when the generation.completed event arrives, payload and signature details in the API docs. Include an idempotencyKey (hash of slug + title) so republishing never double-charges.

Classic (non-headless) WordPress?

The same mu-plugin works on a classic theme, Yoast/Rank Math will output the meta tag for you. If you'd rather not touch PHP at all, the n8n/Make recipe drives WordPress over its REST API with zero code on the server.


Full parameter reference in the API docs. Other platforms: all recipes.