
Here’s the long title for this code snippet —
How to set up an external image as a WordPress featured image and inject it into header as an og:image
meta tag, suitable for LinkedIn and Facebook
Why did I do this? Because Yoast SEO does not add an og:image
tag automatically, if there is no locally hosted featured image. I also did it because in this very specific case, my images were served from a script and generated on the fly based on width, height, quality and cropping URL parameters. Here’s my workaround:
/**
* Use external URL for featured image (helps with social sharing)
*
* Get the cURL effective URL and save it in a custom meta field.
* Output custom Open Graph meta tags based on the saved URL.
*/
function whiskey_thumbnail_external_replace() {
global $post;
if (empty($post->ID) || (string) get_post_type($post->ID) !== 'custom-post-type') {
return;
} else {
if ((string) get_post_meta($post->ID, '_whiskey_featured_image', true) === '') {
$url = 'path/to/image/;
// Use cURL to get the image path if it doesn't exist
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $url,
CURLOPT_HEADER => true,
CURLOPT_NOBODY => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_ENCODING => ''
]);
$response = curl_exec($curl);
$redir = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL);
curl_close($curl);
//
$url = $redir;
update_post_meta($post->ID, '_whiskey_featured_image', $url);
} else {
$url = get_post_meta($post->ID, '_whiskey_featured_image', true);
}
if ((string) $url !== '') {
add_filter('wpseo_frontend_presenter_classes', 'whiskey_wpseo_frontend_presenters', 10, 1);
// LinkedIn
echo '<meta name="image" property="og:image" content="' . $url . '">';
// Facebook
echo '<meta property="og:image" content="' . $url . '">';
echo '<meta property="og:image:alt" content="' . get_the_title($post->ID) . '">';
if (getimagesize($url)) {
$size = getimagesize($url);
echo '<meta property="og:image:width" content="' . $size[0] . '">
<meta property="og:image:height" content="' . $size[1] . '">';
}
}
}
}
function whiskey_wpseo_frontend_presenters($presenters) {
if ($matches = preg_grep('/Image_Presenter/', $presenters)) {
return array_diff($presenters, $matches);
} else {
return $presenters;
}
}
add_action('wp_head', 'whiskey_thumbnail_external_replace', -1000);
Note that I am storing the final URL in a custom meta field and I am using CURLINFO_EFFECTIVE_URL
to get the last effective URL (after all redirects). Also note that you need CURLOPT_FOLLOWLOCATION
to be set to true
.
After I get the image, I am adding 5 meta tags (one for LinkedIn and 4 for Facebook). Here they are:
<!-- LinkedIn -->
<meta name="image" property="og:image" content="/path/to/image/">
<!-- Facebook -->
<meta property="og:image" content="/path/to/image/">
<meta property="og:image:alt" content="This is the title">
<meta property="og:image:width" content="1920">
<meta property="og:image:height" content="1080">
If you are using an SEO plugin other than Yoast’s, you might not need this workaround.
Photo by Eric Park on Unsplash.

Technical SEO specialist, JavaScript developer and senior full-stack developer. Owner of getButterfly.com.
If you like this article, go ahead and follow me on X or buy me a coffee to support my work!
you could also use the wordpress http api, and add from external url to media library and set as thumbnail as well
True, but the idea was to not save anything locally. In my specific case, these images would expire and change, so I need the featured image to be dynamic.