---
title: "Add Open Graph and Twitter Card Tags to Joomla - Code Snippets"
description: "Give every Joomla article a proper preview card on Facebook, LinkedIn, WhatsApp and X, with the right title, text and image, using one HTML or PHP snippet."
url: "https://www.tassos.gr/docs/code-snippets/howto/seo-meta-tags/open-graph-tags"
date: "2026-10-22T23:05:59+00:00"
language: "en-GB"
---

[ Home ](https://www.tassos.gr/docs) / [ Code Snippets ](https://www.tassos.gr/docs/code-snippets) / [ How-to Guides ](https://www.tassos.gr/docs/code-snippets/howto) / [ SEO & Meta Tags ](https://www.tassos.gr/docs/code-snippets/howto/seo-meta-tags)

#  Add Open Graph and Twitter Card Tags to Joomla

##  Give every Joomla article a proper preview card on Facebook, LinkedIn, WhatsApp and X, with the right title, text and image, using one HTML or PHP snippet.

 ![Add Open Graph and Twitter Card Tags to Joomla](https://www.tassos.gr/images/2026/10/code-snippets-open-graph-tags-v2-card.png) Heads up! This article contains PHP code and is intended for developers. We offer this code as a courtesy, but don't provide support for code customizations or 3rd party development.

Share a Joomla article on Facebook, LinkedIn, WhatsApp or X, and the preview card comes up with no image, a generic title, or nothing at all. Those networks build the card from Open Graph meta tags in the page's head, and Joomla doesn't write any. You can add them with one snippet in Code Snippets, as a few lines of HTML or as a PHP snippet that handles more cases.

## [Using an HTML snippet](#using-an-html-snippet)

This is the basic version: seven meta tags, filled in by smart tags when the page renders. It covers single article pages and needs a condition to stay off the other pages.

1. Install [Code Snippets](https://www.tassos.gr/docs/code-snippets/getting-started/how-to-install) if it isn't installed already.
2. Log into your Joomla backend.
3. Go to **Components** → **Tassos Code Snippets**.
4. Click **New**.
5. Enter a title, for example *Open Graph tags*.
6. Set **Code Type** to **HTML**.
7. Set **Insertion Method** to **Auto-Insert Locations**.
8. Set **Location** to **Site Header**.
9. Paste this code into the editor:

    ```
    <meta property="og:type" content="article">
    <meta property="og:title" content="{tcs article.title --htmlSpecialChars=true}">
    <meta property="og:description" content="{tcs page.desc --htmlSpecialChars=true}">
    <meta property="og:url" content="{tcs url --htmlSpecialChars=true}">
    <meta property="og:site_name" content="{tcs site.name --htmlSpecialChars=true}">
    <meta property="og:image" content="{tcs site.url}{tcs article.images.image_fulltext --filter=re:#.*}">

    <meta name="twitter:card" content="summary_large_image">
    ```
10. Open the **Conditional Logic** tab:

    - Set **Display on** to **Selected Pages**.
    - Click **New Condition Set**.
    - Click **Select Condition** and choose **Content View**.
    - Select **Single Article**.
11. Click **Save & Close**.

Each `{tcs ...}` smart tag is replaced with the article's title, the page's meta description, the page address, the site name and the article's Full Article Image. The `--htmlSpecialChars` option turns characters like `&` into their HTML form so they can't break the tag, and the `--filter` option drops the size hints Joomla keeps after the `#` in image paths.

The condition matters. Outside a single article page the article smart tags print nothing, and a card with an empty title is worse than no card. The Content View condition is part of Code Snippets Pro. With the free version, use the PHP snippet below, which needs no condition.

Being the basic version, it has two limits. The description comes from the article's Meta Description, or the page's one when the article has none, so an article without either gets an empty description. And an article with no Full Article Image gets an image tag that points at your homepage, so set a full image on each article you plan to share.

## [Using a PHP snippet](#using-a-php-snippet)

Use this method if you want more flexibility. It works on every page of the site, not just articles, picks the Intro Image when an article has no full image, writes a description from the article text when the Meta Description field is empty, and needs no condition. On every page it adds the tags the networks read: the type, title, address and site name, an image, and the card format for X. On a single article page the title is the article's title, the image is the article's Full Article Image, or its Intro Image when there's no full one, and the description is the article's Meta Description. When that field is empty, the first 200 characters of the article text are used, cut at a whole word. Every other page gets its page title, its own meta description if one is set, and the default image.

```
use Joomla\CMS\Document\HtmlDocument;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Uri\Uri;
use Joomla\Database\DatabaseInterface;
use Joomla\Database\ParameterType;

// The image for pages that have no image of their own, like the homepage.
// A path inside your site or a full URL. 1200 x 630 pixels works best.
$defaultImage = 'images/social-share.jpg';

// Your site's handle on X (Twitter), with the @. Leave empty to skip it.
$twitterHandle = '';

// Do not edit below.

$app = Factory::getApplication();

$app->registerEvent('onBeforeCompileHead', function () use (
    $app, $defaultImage, $twitterHandle
) {
    $doc = $app->getDocument();

    if (!($doc instanceof HtmlDocument))
    {
        return;
    }

    // Another extension already added Open Graph tags. Leave them alone.
    if ($doc->getMetaData('og:title', 'property'))
    {
        return;
    }

    $input       = $app->getInput();
    $title       = $doc->getTitle();
    $description = $doc->getDescription();
    $image       = $defaultImage;
    $type        = 'website';

    $isArticle = $input->getCmd('option') === 'com_content'
        && $input->getCmd('view') === 'article';

    if ($isArticle)
    {
        $id    = $input->getInt('id');
        $db    = Factory::getContainer()->get(DatabaseInterface::class);
        $query = $db->createQuery()
            ->select($db->quoteName(['title', 'introtext', 'metadesc', 'images']))
            ->from($db->quoteName('#__content'))

            ->where($db->quoteName('id') . ' = :id')
            ->bind(':id', $id, ParameterType::INTEGER);
        $article = $db->setQuery($query)->loadObject();

        if ($article)
        {
            $images = json_decode($article->images, true) ?: [];
            $own    = $images['image_fulltext'] ?? '';
            $own    = $own !== '' ? $own : ($images['image_intro'] ?? '');
            $title  = $article->title;
            $type   = 'article';

            if ($own !== '')
            {
                // Joomla stores the editor's size hints after a #. Drop them.

                $image = HTMLHelper::cleanImageURL($own)->url;
            }

            if ($article->metadesc !== '')
            {
                $description = $article->metadesc;
            }
            else
            {
                // No meta description: use the first words of the article.
                $text = preg_replace('/\{[^}]*\}/', '', $article->introtext);
                $text = preg_replace('/<[^>]+>/', ' ', $text);
                $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
                $text = trim(preg_replace('/\s+/', ' ', $text));

                if (mb_strlen($text) > 200)
                {
                    $text = mb_substr($text, 0, 200);
                    $text = mb_substr($text, 0, mb_strrpos($text, ' ')) . '...';
                }

                $description = $text;
            }
        }
    }

    // Social networks only accept full image URLs.
    if ($image !== '' && !preg_match('#^https?://#i', $image))

    {
        $image = Uri::root() . ltrim($image, '/');
    }

    $doc->setMetaData('og:type', $type, 'property');
    $doc->setMetaData('og:title', $title, 'property');
    $doc->setMetaData('og:url', Uri::getInstance()->toString(), 'property');
    $doc->setMetaData('og:site_name', $app->get('sitename'), 'property');
    $card = $image !== '' ? 'summary_large_image' : 'summary';
    $doc->setMetaData('twitter:card', $card);

    if ($description !== '')
    {
        $doc->setMetaData('og:description', $description, 'property');
    }

    if ($image !== '')
    {
        $doc->setMetaData('og:image', $image, 'property');
    }

    if ($twitterHandle !== '')
    {
        $doc->setMetaData('twitter:site', $twitterHandle);
    }
});
```

To change the default image, upload one to the **Media** manager and put its path in `$defaultImage`. An image of 1200 by 630 pixels fills the card on every network. To add your site's X handle to the tags, put it in `$twitterHandle`.

The snippet does nothing on a page where another extension has already added an `og:title` tag, so it won't fight with an SEO extension that writes its own.

1. Install [Code Snippets](https://www.tassos.gr/docs/code-snippets/getting-started/how-to-install) if it isn't installed already.
2. Log into your Joomla backend.
3. Go to **Components** → **Tassos Code Snippets**.
4. Click **New**.
5. Enter a title, for example *Open Graph tags*.
6. Set **Code Type** to **PHP**.
7. Set **Insertion Method** to **Auto-Insert Locations**.
8. Set **Location** to **On Page Load**.
9. Paste the code above into the editor.
10. Click **Save & Close**.

Use one snippet or the other, never both. Two sets of tags on one page leave the networks to guess which to read.

## [Check that it works](#check-that-it-works)

1. Open an article that has a Full Article Image.
2. View the page source and search for `og:`.

The head holds six `og:` tags and one `twitter:card` tag. The title is the article's title, the description is its meta description, and the image is the full address of its image, like `https://example.com/images/beaches.jpg`. With the PHP snippet, the homepage shows the default image. To see the finished card, paste the page's address into Facebook's Sharing Debugger or LinkedIn's Post Inspector. Both need a site they can reach, so a local site won't do.

 The PHP snippet doesn't check that the default image exists. Upload it before you publish the snippet, or the card for your homepage shows a broken image.

The card's description is only as good as the article's meta description. To fill that field on every article automatically, see [Auto-Generate Meta Descriptions from Article Text in Joomla](https://www.tassos.gr/docs/code-snippets/howto/seo-meta-tags/auto-generate-meta-description). To learn more about the two snippet types, read the [HTML snippet docs](https://www.tassos.gr/docs/code-snippets/types/html) and the [PHP snippet docs](https://www.tassos.gr/docs/code-snippets/types/php).

 Last updated on Oct 17th 2026 12:10
