Los plugins son la forma más limpia de cambiar el comportamiento de Joomla sin tocar su código. En este ejemplo vamos a crear un plugin de contenido que convierte {aviso}texto{/aviso}, escrito dentro de un artículo, en una caja destacada.
Usaremos la estructura moderna que introdujo Joomla 4 y que es la recomendada en Joomla 5: espacios de nombres, un proveedor de servicios y una clase que se suscribe a eventos.
Estructura de archivos
plg_content_aviso/
├── aviso.xml
├── services/
│ └── provider.php
└── src/
└── Extension/
└── Aviso.php
1. El manifiesto: aviso.xml
Describe el plugin y, muy importante, declara su espacio de nombres.
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="content" method="upgrade">
<name>Contenido - Aviso</name>
<author>Julio Blanco</author>
<version>1.0.0</version>
<description>Convierte {aviso}texto{/aviso} en una caja destacada.</description>
<namespace path="src">Bnet\Plugin\Content\Aviso</namespace>
<files>
<folder plugin="aviso">services</folder>
<folder>src</folder>
</files>
</extension>
2. El proveedor de servicios: services/provider.php
Le dice a Joomla cómo construir el plugin.
<?php
defined('_JEXEC') or die;
use Bnet\Plugin\Content\Aviso\Extension\Aviso;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
return new class implements ServiceProviderInterface {
public function register(Container $container)
{
$container->set(PluginInterface::class, function (Container $container) {
$plugin = new Aviso(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('content', 'aviso')
);
$plugin->setApplication(Factory::getApplication());
return $plugin;
});
}
};
3. La clase del plugin: src/Extension/Aviso.php
Se suscribe al evento onContentPrepare, que Joomla lanza antes de mostrar el texto de un artículo.
<?php
namespace Bnet\Plugin\Content\Aviso\Extension;
defined('_JEXEC') or die;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\Event;
use Joomla\Event\SubscriberInterface;
final class Aviso extends CMSPlugin implements SubscriberInterface
{
public static function getSubscribedEvents(): array
{
return ['onContentPrepare' => 'alPreparar'];
}
public function alPreparar(Event $event)
{
[$context, $article] = array_values($event->getArguments());
if (empty($article->text) || strpos($article->text, '{aviso}') === false) {
return;
}
$article->text = preg_replace(
'#\{aviso\}(.*?)\{/aviso\}#s',
'<div class="alert alert-info">$1</div>',
$article->text
);
}
}
4. Instalar y probar
- Comprime la carpeta
plg_content_avisoen un ZIP. - Instálalo desde Sistema → Instalar → Extensiones.
- Actívalo en Sistema → Gestionar → Plugins, buscando “Aviso”.
- Escribe en un artículo
{aviso}Oferta válida hasta fin de mes{/aviso}y míralo en la web.
Detalles que marcan la diferencia
- Salir pronto: si el texto no contiene la etiqueta, el plugin no hace nada. Se ejecuta en cada artículo, así que importa.
- Revisar el contexto: con
$contextpuedes limitar el plugin a artículos (com_content.article) y no tocar módulos u otros componentes. - Parámetros: añadiendo un bloque
<config>al XML, el usuario podría elegir el estilo de la caja desde la administración. - Idiomas: en un plugin real, los textos van en archivos de idioma, no escritos en el código.
Este mismo esquema sirve para plugins mucho más complejos: integraciones con otros sistemas, cambios en el envío de formularios o procesos automáticos tras guardar un contenido.
¿Necesitas ayuda con esto? Es parte de mi servicio de Desarrollo de extensiones Joomla. Cuéntame tu caso.