Generate Open Graph and Twitter Card Meta Tags in WordPress with PHP

Open Graph meta tags control how your WordPress content appears when shared on Facebook, LinkedIn, Slack, and other platforms that read the og: namespace from the document <head>. Without them, platforms fall back to heuristic title and image selection that often picks an unrelated thumbnail or truncates the title unpredictably. The four required Open Graph properties — og:title, og:type, og:image, and og:url — must appear on every page that can be shared, including archives, taxonomies, and the homepage. WordPress post thumbnails are the natural source for og:image, but falling back to the first attached image ensures coverage for posts that were published before a featured image policy was adopted. Facebook recommends images of at least 1200 × 630 pixels for the news feed layout — specifying og:image:width and og:image:height allows the platform to pre-allocate space before downloading the image. Twitter cards use a parallel set of twitter: meta tags; the twitter:card property must be set to summary_large_image to display the featured image prominently in the timeline. The og:description value should come from the post excerpt when one is set manually, and fall back to a stripped, truncated version of the post content. Sanitizing all output with esc_attr() before placing values in attribute positions prevents XSS from malicious post titles or custom field values reaching the head. The canonical URL post explains how to ensure og:url matches the canonical link tag for consistent signals. The JSON-LD structured data guide is the complement to Open Graph — structured data targets search engines while OG targets social platforms. Validate the output with the Facebook Sharing Debugger (developers.facebook.com/tools/debug/) and Twitter Card Validator to confirm tags are parsed correctly before publishing. Disable this code immediately if you install Yoast SEO, Rank Math, or any other SEO plugin that already outputs Open Graph tags to prevent duplicates.

Problem: WordPress does not output Open Graph or Twitter Card meta tags by default, so shared links on social platforms display unpredictable titles, descriptions, and images.

Solution: Hook into wp_head and output the full set of og: and twitter: tags for singular posts, archives, and the home page, sourcing the image from the post thumbnail with a site logo fallback.

add_action('wp_head', function() {
    $title = $desc = $image = $url = '';

    if (is_singular()) {
        $post    = get_queried_object();
        $title   = get_the_title($post);
        $url     = get_permalink($post);
        $excerpt = has_excerpt($post) ? get_the_excerpt($post)
                 : wp_trim_words(strip_tags($post->post_content), 25, '...');
        $desc    = $excerpt;
        if (has_post_thumbnail($post)) {
            $image = get_the_post_thumbnail_url($post, 'large');
        } else {
            $imgs  = get_attached_media('image', $post);
            $first = reset($imgs);
            $image = $first ? wp_get_attachment_url($first->ID) : '';
        }
    } elseif (is_home()) {
        $title = get_bloginfo('name');
        $desc  = get_bloginfo('description');
        $url   = home_url('/');
    }

    if (empty($image)) {
        $image = get_site_icon_url(512);
    }

    if (empty($title)) return;

    $type = is_singular('post') ? 'article' : 'website';

    echo '<meta property="og:type"        content="' . esc_attr($type)  . '">' . PHP_EOL;
    echo '<meta property="og:title"       content="' . esc_attr($title) . '">' . PHP_EOL;
    echo '<meta property="og:description" content="' . esc_attr($desc)  . '">' . PHP_EOL;
    echo '<meta property="og:url"         content="' . esc_url($url)    . '">' . PHP_EOL;
    echo '<meta property="og:image"       content="' . esc_url($image)  . '">' . PHP_EOL;
    echo '<meta name="twitter:card"       content="summary_large_image">'      . PHP_EOL;
    echo '<meta name="twitter:title"      content="' . esc_attr($title) . '">' . PHP_EOL;
    echo '<meta name="twitter:description" content="' . esc_attr($desc). '">' . PHP_EOL;
    echo '<meta name="twitter:image"      content="' . esc_url($image)  . '">' . PHP_EOL;
}, 5);

NOTE: Use add_image_size('og-image', 1200, 630, true) in functions.php and replace 'large' with 'og-image' in the thumbnail call — this ensures the image crop is exactly the 1.91:1 ratio Facebook uses for news feed cards.