Twitter — now rebranded as X — has changed beyond recognition since this plugin was first written. The platform's card system still technically exists, but the open web has largely moved on to the Open Graph protocol, which is supported by X, LinkedIn, Bluesky, Mastodon, and virtually every other platform that renders link previews. If you're building or maintaining a Joomla 5 site in 2026 and want rich link previews wherever your content gets shared, Open Graph meta tags are the right tool. This article documents the original Twitter Cards plugin as a worked Joomla plugin example — the code and concepts remain instructive — but the practical recommendation at the end has changed.
twitter: meta tags, but Open Graph tags are now the standard approach and are supported by X as a fallback. See the TL;DR below.TL:DR – The Twitter Card meta tag format predated the Open Graph protocol and has since been largely superseded by it. X will read og: tags if twitter: tags are absent, so a single set of Open Graph tags now covers X, Bluesky, LinkedIn, Mastodon, and most other platforms simultaneously. I wrote about how to provide that functionality in Ridiculously Responsive Social Sharing Buttons for Joomla, which handles Open Graph tags cleanly and is what I now use in place of socialcards.
Contents
Writing this plugin was genuinely useful as a learning exercise — it forced me to understand how to write a Joomla plugin, navigate the XML installation format, and work with some PHP functions like strstr. The objective was to inject the right meta tags automatically into the <head> of each article page. Here is what those tags look like:
Twitter Card meta data
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@Your X/Twitter username">
<meta name="twitter:title" content="Your article title">
<meta name="twitter:description" content="Your article introtext">
<meta name="twitter:image" content="link to your image">
These tags need to be placed on each page inside the <head> tag, with unique content drawn from the Joomla article. The sections below walk through how the plugin achieves that, including all the source code:
- User Story
- Possible methods
- Different kinds of Plugin in Joomla
- Events
- XML Installation file
- Plugin PHP file
- Localisation strings
User Story
As a Joomla Administrator, I want to automatically add the meta data required to generate a rich link preview when someone shares a link to my Joomla 5 site on X or any other social platform. This makes shared links more visually engaging and drives more traffic back to the content.
In 2026 that goal is better served by Open Graph tags than by platform-specific twitter: tags, but the mechanism for injecting either set into the document head from a Joomla plugin is identical. This plugin remains a clean, minimal example of how to do it.
Possible methods
There are extensions in the Joomla Extensions Directory that handle social meta tags, and several have been updated for Joomla 5. If you just want the functionality without the learning exercise, a well-maintained extension from the JED is the pragmatic choice. Check that any extension you install explicitly lists Joomla 5 compatibility before installing it.
Search results also surface approaches that use JavaScript to inspect page elements and write meta tags into the head. That remains a brittle solution — search engines and social crawlers often don't execute JavaScript when fetching pages for link preview generation, so server-side meta tags are far more reliable.
The Joomla Plugin approach is the cleanest server-side method. The Joomla documentation has been updated to cover Joomla 5 plugin development:
Different kinds of Plugin in Joomla
Joomla has a wide range of plugin groups. This is a content plugin — the group responsible for processing and augmenting article content. If you've used plugins like emailcloak or pagebreak, you've already used plugins from this group as a site administrator.
Joomla 5 introduced a more rigorous event system compared to Joomla 4, with plugins increasingly expected to implement SubscriberInterface and declare their event subscriptions explicitly rather than relying on method naming conventions. The plugin code shown here uses the Joomla 4 convention; porting it to the Joomla 5 event dispatcher pattern is straightforward and worth doing for any production use.
|
|
Events
Joomla plugins are code installed into your site that fires when a particular event occurs. Joomla ships with a set of core plugin events and you can define your own. As a starting point, the core content plugin events are the right place to look. The event list is documented at Plugin/Events/Content.
The event used here is onContentBeforeDisplay. Its description says it handles information that should be placed immediately before the generated content — but in practice, calling $document->setMetaData() inside this event writes tags into the document <head>, which is exactly what's needed. The event fires with the article object available, giving access to the title, introtext, and images fields.
In Joomla 5's dispatcher model, the equivalent approach is to subscribe to onContentBeforeDisplay via getSubscribedEvents(), but the underlying document API call is the same.
The socialcards plugin
XML Installation file
The installation manifest must be in XML format. This is the standard for all Joomla extensions and is required for the installer to correctly handle installation, updates, and uninstallation. The format has been consistent across Joomla 3, 4, and 5, though Joomla 5 adds support for namespace declarations in the manifest.
The XML file identifies the extension type, group, and update method, along with author metadata, version, and a description string that references the localisation file. method="upgrade" allows new versions to be installed over existing ones cleanly. It then lists the files to deploy and defines the plugin's own configuration parameters.
socialcards.xml
<?xml version="1.0" encoding="utf-8"?>
<extension type="plugin" group="content" method="upgrade">
<name>Social Cards</name>
<creationDate>Jan 2021</creationDate>
<author>Angus Fox</author>
<authorEmail>This email address is being protected from spambots. You need JavaScript enabled to view it. </authorEmail>
<authorUrl>www.multizone.co.uk</authorUrl>
<copyright>Copyright 2021 Multizone Limited</copyright>
<license>GNU/GPLv3</license>
<version>1.0.2</version>
<description>PLG_SOCIALCARDS_DESC</description>
<files>
<filename plugin="socialcards">socialcards.php</filename>
<folder>language</folder>
</files>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="social_card"
type="text"
default="summary"
label="PLG_SOCIALCARDS_CARD_LABEL"
description="PLG_SOCIALCARDS_CARD_DESCRIPTION"
readonly="readonly"
>
</field>
<field
name="social_site"
type="text"
required="true"
label="PLG_SOCIALCARDS_SITE_LABEL"
description="PLG_SOCIALCARDS_SITE_DESCRIPTION"
>
</field>
</fieldset>
</fields>
</config>
</extension>
Plugin PHP file
The plugin was written for Joomla 4 and uses CMSPlugin rather than the older JPlugin. Note that in Joomla 5, JFactory calls are deprecated — JFactory::getConfig() and JFactory::getDocument() should be replaced with dependency injection or the application object. The code below is preserved as originally written; adapting it for Joomla 5 means injecting the application and document via the constructor, which the Joomla 5 plugin documentation covers in detail.
The plugin sets the card type to summary, reads the X/Twitter username from the plugin parameters, pulls the title from the article object, truncates the introtext to fit the description field, and constructs the image URL from the article's image_fulltext field. It works best when articles have both an introtext and a full-text image set.
socialcards.php
<?php
/**
* @version $Id: socialcards.php 2021-10-12 09:00 you $
* @package Joomla
* @subpackage Content Plugin Social Cards for Joomla! 4
* @author Angus Fox
* @copyright Copyright 2021 Multizone Limited
* @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
* Joomla! is free software. This version may have been modified pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
**/
// no direct access
defined( '_JEXEC' ) or die;
// This plugin was written for Joomla 4 and uses CMSPlugin.
// For Joomla 5, replace JFactory calls with dependency injection.
// See https://docs.joomla.org/Creating_a_Plugin_for_Joomla
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Event\Event;
use Joomla\Event\SubscriberInterface;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;
class plgContentSocialcards extends CMSPlugin {
// Load the language file on instantiation
protected $autoloadLanguage = true;
function onContentBeforeDisplay($context, &$article, &$params, $limitstart)
{
/*
* Add meta tags for twitter:site, twitter:title, twitter:description and twitter:image
* X (formerly Twitter) still reads these tags; they also serve as a fallback
* alongside Open Graph tags on platforms that support both.
* For best results requires an article image (image_fulltext) to exist.
*/
// Set the Meta Data from the plugin parameters
// Note: JFactory is deprecated in Joomla 5 — refactor for production use
$config = JFactory::getConfig();
$document = JFactory::getDocument();
// The type of card is set from the parameters to 'summary'.
$social_card = $this->params->get('social_card');
if (isset($social_card)) {
$document->setMetaData('twitter:card', $social_card);
} else {
echo "<div class=\"alert alert-danger\" role=\"alert\">" . $social_card_name .
"plugin error <a href=\"https://www.multizone.co.uk/\" class=\"alert-link\">Vendor</a>. Try updating, setting parameters and enabling.</div>";
}
// The site is set from the parameters. A site is an X/Twitter username without the @
$social_site = $this->params->get('social_site');
if (isset($social_site)) {
$document->setMetaData('twitter:site', $social_site);
} else {
echo "<div class=\"alert alert-danger\" role=\"alert\">" . $social_site_name .
"plugin error <a href=\"https://www.multizone.co.uk/\" class=\"alert-link\">Vendor</a>. Try updating, setting parameters and enabling.</div>";
}
// Title and Description are set from the Article Title and Introtext
$document->setMetaData('twitter:title', $article->title);
$introtext_notags = strip_tags($article->introtext);
$introtext_truncated = substr($introtext_notags, 0, 160);
$document->setMetaData('twitter:description', $introtext_truncated);
// Need the images JSON to get the article image path
$images = json_decode($article->images);
// Remove the query string to clean up the image path
$image_truncated = strstr($images->image_fulltext, chr(63), true);
// Need the current URI to get the root URL
$uri = Uri::getInstance();
// The Meta data for the Image link is set to the root URL plus article image path
$document->setMetaData('twitter:image', $uri->root() . $image_truncated);
return '';
}
}
?>
Localisation strings
Plugins carry language string files — one for the front end and one for the back end. They are simple key-value mappings. The format is not XML, which catches people out when they've just been editing the manifest. Note that in Joomla 5, the language folder structure inside the plugin package is preferred over placing language files in the global /language directory, but both still work.
en-GB.plg_content_socialcards.sys.ini
; $Id: en-GB.socialcards.ini
; Content Plugin Social Cards for Joomla! - Backend Language strings
; Copyright 2021 Multizone Limited
; License GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
; Author Angus Fox
PLG_SOCIALCARDS_NAME="Social Cards"
PLG_SOCIALCARDS_DESC="The Social Cards plugin adds meta tags to your Joomla! article pages so that links shared on X (Twitter), Bluesky, LinkedIn and other platforms generate a rich card preview visible to the recipient's followers."
PLG_SOCIALCARDS_CARD_DESCRIPTION="This must be 'summary'."
PLG_SOCIALCARDS_CARD_LABEL="Type of card"
PLG_SOCIALCARDS_SITE_LABEL="X / Twitter username"
PLG_SOCIALCARDS_SITE_DESCRIPTION="Enter the site username (without the @) to associate with the card"
en-GB.socialcards.ini
; $Id: en-GB.socialcards.ini
; Content Plugin Social Cards for Joomla! - Backend Language strings
; Copyright 2021 Multizone Limited
; License GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
; Author Angus