SEO

Open Graph tags in Joomla: why shared links show the wrong picture

Open Graph tags in Joomla: why shared links show the wrong picture

Joomla core writes no Open Graph tags, so shared links show the wrong picture. Which tags you need, how to add them with an override, how to clear caches.

Someone shares your article on LinkedIn or in a WhatsApp group, and the preview shows your logo stretched into a banner, or a cookie notice as the description, or no picture at all. The article has a perfectly good image. The preview just never found it.

Those previews are built from Open Graph tags: a handful of meta elements with names like og:title and og:image. Facebook introduced them, and LinkedIn, WhatsApp, Slack, Teams, Mastodon and X all read them. Joomla core does not write a single one. Not in Joomla 4, not in 5, not in 6.

What happens without them

When a crawler finds no Open Graph tags it guesses. The title usually comes from the <title> element, which in Joomla may carry the site name in front of it. The description comes from the meta description if there is one, otherwise from whatever text sits near the top of the page. The image is the worst guess: often the logo, sometimes a banner from a module, sometimes nothing because the image is loaded lazily.

Check what you have before you change anything. Open an article, view the page source and search for og:. If you find tags, something already writes them: a social sharing plugin, an SEO extension, or a template framework such as Helix, Gantry or YOOtheme. Fix the settings there. Adding a second set gives you duplicate tags, and each platform picks its own favourite.

The tags that matter

Four tags do most of the work, and two more are worth adding:

<meta property="og:title" content="Article title, without the site name">
<meta property="og:description" content="One or two sentences">
<meta property="og:image" content="https://www.example.com/images/photo.jpg">
<meta property="og:url" content="https://www.example.com/blog/article-alias">
<meta property="og:type" content="article">
<meta name="twitter:card" content="summary_large_image">

Note the attribute: Open Graph uses property, the X card tag uses name. X falls back to the og: values for title, description and image, so you do not need a full set of twitter: tags. Without twitter:card, though, X shows a small thumbnail instead of the large picture.

The image URL has to be absolute, with https:// and the domain. A relative path like images/photo.jpg is the most common reason a preview stays empty.

Adding them with a template override

If you do not want an extension for this, an override of the single article view is enough. Create it under System > Site Templates > Cassiopeia Details and Files > Create Overrides > Components > com_content > article. Better still, do it in a child template, as described in Child templates in Joomla. Then open html/com_content/article/default.php and put this right below the existing use lines and the defined('_JEXEC') check:

use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Uri\Uri;

$doc    = Factory::getApplication()->getDocument();
$images = json_decode($this->item->images ?? '{}');
$src    = ($images->image_fulltext ?? '') ?: ($images->image_intro ?? '');

$desc = $this->item->metadesc
    ?: HTMLHelper::_('string.truncate', strip_tags($this->item->introtext), 200, true, false);

$doc->setMetaData('og:type', 'article', 'property');
$doc->setMetaData('og:title', $this->item->title, 'property');
$doc->setMetaData('og:description', $desc, 'property');
$doc->setMetaData('og:url', Uri::getInstance()->toString(['scheme', 'host', 'port', 'path']), 'property');

if ($src) {
    $url = HTMLHelper::_('cleanImageURL', $src)->url;
    if (!preg_match('#^https?://#', $url)) {
        $url = Uri::root() . ltrim($url, '/');
    }
    $doc->setMetaData('og:image', $url, 'property');
    $doc->setMetaData('twitter:card', 'summary_large_image');
}

A few details in there are easy to miss. Since Joomla 4 the image fields store more than a path: images/photo.jpg#joomlaImage://local-images/photo.jpg?width=1200&height=630. The cleanImageURL helper strips that suffix. Without it, the crawler requests a URL that does not exist. The full text image is tried first, then the intro image. And og:url is built without the query string, so a link shared with tracking parameters still points to one address.

If use lines for Factory or HTMLHelper are already in the file, leave out the duplicates. PHP stops with a fatal error when the same class is imported twice.

A fallback for every other page

Category blogs, the home page and contact pages get nothing from the override above. For those, add a default in the template's index.php. The component has already run by the time index.php is executed, so you can check whether an article set its own image:

if (!$this->getMetaData('og:image', 'property')) {
    $this->setMetaData('og:image', Uri::root() . 'images/share-default.jpg', 'property');
    $this->setMetaData('og:title', $this->getTitle(), 'property');
    $this->setMetaData('twitter:card', 'summary_large_image');
}
$this->setMetaData('og:site_name', Factory::getApplication()->get('sitename'), 'property');

In a child template you need a copy of index.php in the child for this, which means you take over maintenance of that file. If that is a step too far, this is where a small plugin or an existing extension starts to make sense.

The image itself

Most platforms crop to a ratio of roughly 1.91 to 1. An image of 1200 by 630 pixels works everywhere. A square photo gets its top and bottom cut off, and a portrait photo loses most of its subject. Images narrower than about 600 pixels are shown as a small thumbnail on Facebook and LinkedIn, or not at all.

Keep the file reasonably small. WhatsApp in particular skips images that take too long to fetch, and then shows the link without a picture.

When the preview stays wrong

Every platform caches the preview the first time someone shares a URL, often for days. You fix the tags, share the link again, and still see the old version. That does not mean your fix failed.

  • Facebook: the Sharing Debugger at developers.facebook.com/tools/debug shows exactly which tags it found. Click Scrape Again to refresh the cache.
  • LinkedIn: the Post Inspector at linkedin.com/post-inspector does the same, and fetches the page again each time you inspect it.
  • WhatsApp, Slack, Teams: there is no public refresh button. Test with the URL plus a harmless parameter such as ?v=2, which counts as a new URL.

If the debugger reports that it cannot fetch the page at all, look at what stands between the crawler and your site. A firewall rule in Admin Tools or RSFirewall that blocks unknown user agents, Cloudflare's bot protection, or an old robots.txt with Disallow: /images/ can each stop the crawler from fetching the page or the picture. Facebook's crawler identifies itself as facebookexternalhit, LinkedIn's as LinkedInBot. See Robots.txt in Joomla for what belongs in that file.

Where this fits

Open Graph tags do not affect your ranking in Google. They decide what people see before they click on a shared link, which on many sites is a bigger share of the visits than search. The title and description you set for search engines, covered in Page titles and meta descriptions in Joomla, are a good starting point, and the override above reuses the article's meta description for exactly that reason. Structured data is a separate thing again, aimed at search results rather than social feeds: see Structured data in Joomla 5 and 6.

Stuck on something else?

Doctor Joomla is a project of Cloudfaction, a Dutch agency building and maintaining Joomla sites since 1999. The articles are made with the help of AI, so tell us if something does not match your screen. Mail info@cloudfaction.nl if you want someone to look at yours.

Rather have someone look at it

Doctor Joomla is a Cloudfaction project.

A Dutch agency that has been building and running Joomla sites since 1999. If your site needs more than an article can fix, get in touch.