Skip to content

WordPress Integration

Generate OG images for WordPress sites.

Custom Plugin

Create a simple plugin to generate OG images:

php
<?php
/**
 * Plugin Name: OG Image API
 * Description: Generate dynamic Open Graph images
 * Version: 1.0.0
 */

// Prevent direct access
if (!defined('ABSPATH')) exit;

// Settings
define('OG_IMAGE_API_KEY', get_option('og_image_api_key', ''));
define('OG_IMAGE_API_URL', 'https://ogimageapi.io/api/generate');

/**
 * Add settings page
 */
add_action('admin_menu', function() {
    add_options_page(
        'OG Image API Settings',
        'OG Image API',
        'manage_options',
        'og-image-api',
        'og_image_settings_page'
    );
});

function og_image_settings_page() {
    if (isset($_POST['og_image_api_key'])) {
        update_option('og_image_api_key', sanitize_text_field($_POST['og_image_api_key']));
    }
    
    $api_key = get_option('og_image_api_key', '');
    ?>
    <div class="wrap">
        <h1>OG Image API Settings</h1>
        <form method="post">
            <table class="form-table">
                <tr>
                    <th>API Key</th>
                    <td>
                        <input type="text" name="og_image_api_key" value="<?php echo esc_attr($api_key); ?>" class="regular-text">
                    </td>
                </tr>
            </table>
            <?php submit_button(); ?>
        </form>
    </div>
    <?php
}

/**
 * Generate OG image for a post
 */
function generate_og_image($post_id) {
    $post = get_post($post_id);
    if (!$post || $post->post_status !== 'publish') return;
    
    $api_key = get_option('og_image_api_key');
    if (!$api_key) return;
    
    // Get post data
    $title = $post->post_title;
    $excerpt = get_the_excerpt($post_id) ?: wp_trim_words($post->post_content, 20);
    $author = get_the_author_meta('display_name', $post->post_author);
    $avatar = get_avatar_url($post->post_author, ['size' => 200]);
    
    // Determine template based on post type
    $template = 'blog';
    if ($post->post_type === 'product') {
        $template = 'product';
    }
    
    // Make API request
    $response = wp_remote_post(OG_IMAGE_API_URL, [
        'headers' => [
            'Content-Type' => 'application/json',
            'X-API-Key' => $api_key
        ],
        'body' => json_encode([
            'title' => $title,
            'subtitle' => $excerpt,
            'author_name' => $author,
            'author_avatar_url' => $avatar,
            'template' => $template,
            'theme' => 'dark'
        ]),
        'timeout' => 30
    ]);
    
    if (is_wp_error($response)) {
        error_log('OG Image API error: ' . $response->get_error_message());
        return;
    }
    
    // Save image
    $image_data = wp_remote_retrieve_body($response);
    $upload_dir = wp_upload_dir();
    $og_dir = $upload_dir['basedir'] . '/og-images';
    
    if (!file_exists($og_dir)) {
        wp_mkdir_p($og_dir);
    }
    
    $file_path = $og_dir . '/' . $post_id . '.png';
    file_put_contents($file_path, $image_data);
    
    // Save URL in post meta
    $file_url = $upload_dir['baseurl'] . '/og-images/' . $post_id . '.png';
    update_post_meta($post_id, '_og_image_url', $file_url);
    
    return $file_url;
}

// Generate on publish
add_action('publish_post', 'generate_og_image', 10, 1);
add_action('save_post', function($post_id) {
    if (get_post_status($post_id) === 'publish') {
        generate_og_image($post_id);
    }
});

/**
 * Output OG meta tags
 */
add_action('wp_head', function() {
    if (!is_singular()) return;
    
    $post_id = get_the_ID();
    $og_image = get_post_meta($post_id, '_og_image_url', true);
    
    // Generate if doesn't exist
    if (!$og_image) {
        $og_image = generate_og_image($post_id);
    }
    
    if ($og_image) {
        echo '<meta property="og:image" content="' . esc_url($og_image) . '" />' . "\n";
        echo '<meta property="og:image:width" content="1200" />' . "\n";
        echo '<meta property="og:image:height" content="630" />' . "\n";
        echo '<meta name="twitter:card" content="summary_large_image" />' . "\n";
        echo '<meta name="twitter:image" content="' . esc_url($og_image) . '" />' . "\n";
    }
}, 1);

/**
 * Add regenerate button to post editor
 */
add_action('add_meta_boxes', function() {
    add_meta_box(
        'og_image_preview',
        'OG Image Preview',
        'og_image_meta_box',
        ['post', 'page'],
        'side'
    );
});

function og_image_meta_box($post) {
    $og_image = get_post_meta($post->ID, '_og_image_url', true);
    ?>
    <div id="og-image-preview">
        <?php if ($og_image): ?>
            <img src="<?php echo esc_url($og_image); ?>" style="max-width:100%;">
        <?php else: ?>
            <p>No OG image generated yet.</p>
        <?php endif; ?>
    </div>
    <p>
        <button type="button" class="button" id="regenerate-og-image">
            Regenerate OG Image
        </button>
    </p>
    <script>
    jQuery('#regenerate-og-image').on('click', function() {
        jQuery(this).prop('disabled', true).text('Generating...');
        jQuery.post(ajaxurl, {
            action: 'regenerate_og_image',
            post_id: <?php echo $post->ID; ?>,
            nonce: '<?php echo wp_create_nonce('regenerate_og_image'); ?>'
        }, function(response) {
            location.reload();
        });
    });
    </script>
    <?php
}

add_action('wp_ajax_regenerate_og_image', function() {
    check_ajax_referer('regenerate_og_image', 'nonce');
    
    $post_id = intval($_POST['post_id']);
    $result = generate_og_image($post_id);
    
    wp_send_json_success(['url' => $result]);
});

WooCommerce Integration

Add product-specific handling:

php
/**
 * Generate OG image for WooCommerce products
 */
function generate_product_og_image($post_id) {
    $product = wc_get_product($post_id);
    if (!$product) return;
    
    $api_key = get_option('og_image_api_key');
    if (!$api_key) return;
    
    // Get product data
    $title = $product->get_name();
    $price = '$' . $product->get_price();
    $original_price = $product->is_on_sale() ? '$' . $product->get_regular_price() : null;
    $image_url = wp_get_attachment_url($product->get_image_id());
    $rating = $product->get_average_rating();
    
    $payload = [
        'title' => $title,
        'product_image_url' => $image_url,
        'price' => $price,
        'brand' => $product->get_attribute('brand') ?: get_bloginfo('name'),
        'rating' => floatval($rating),
        'template' => 'product',
        'theme' => 'dark'
    ];
    
    if ($original_price) {
        $payload['original_price'] = $original_price;
        $payload['badge'] = 'SALE';
    }
    
    $response = wp_remote_post(OG_IMAGE_API_URL, [
        'headers' => [
            'Content-Type' => 'application/json',
            'X-API-Key' => $api_key
        ],
        'body' => json_encode($payload),
        'timeout' => 30
    ]);
    
    // Save image...
    // Same as above
}

add_action('woocommerce_update_product', 'generate_product_og_image');

Bulk Generation

Generate images for all existing posts:

php
/**
 * Add bulk generate tool
 */
add_action('admin_menu', function() {
    add_management_page(
        'Bulk Generate OG Images',
        'Generate OG Images',
        'manage_options',
        'bulk-generate-og',
        'bulk_generate_og_page'
    );
});

function bulk_generate_og_page() {
    if (isset($_POST['generate_all'])) {
        $posts = get_posts([
            'post_type' => ['post', 'page'],
            'post_status' => 'publish',
            'numberposts' => -1
        ]);
        
        $count = 0;
        foreach ($posts as $post) {
            generate_og_image($post->ID);
            $count++;
        }
        
        echo '<div class="notice notice-success"><p>Generated ' . $count . ' OG images.</p></div>';
    }
    ?>
    <div class="wrap">
        <h1>Bulk Generate OG Images</h1>
        <form method="post">
            <p>This will generate OG images for all published posts and pages.</p>
            <?php submit_button('Generate All OG Images', 'primary', 'generate_all'); ?>
        </form>
    </div>
    <?php
}

Theme Integration

If not using a plugin, add to your theme:

php
// functions.php

function theme_og_image($post_id = null) {
    if (!$post_id) $post_id = get_the_ID();
    
    $og_image = get_post_meta($post_id, '_og_image_url', true);
    
    if (!$og_image) {
        // Generate dynamically using query params
        $title = urlencode(get_the_title($post_id));
        $excerpt = urlencode(get_the_excerpt($post_id));
        
        // Use a signed URL or your own proxy endpoint
        $og_image = 'https://your-proxy.com/og?title=' . $title . '&subtitle=' . $excerpt;
    }
    
    return $og_image;
}

Best Practices

  1. Cache generated images — Store in uploads folder
  2. Generate on publish — Not on every page load
  3. Use a plugin — Easier to maintain
  4. Handle WooCommerce separately — Products need different data
  5. Add admin interface — Let editors regenerate

Generate stunning Open Graph images programmatically.