Plugin groups and events
The group of a plugin determines when Joomla loads it and which events it usually handles. The content plugin from the previous lesson works only where content is output or saved. Other tasks need another group — the file structure stays the same.
Groups
| Group | Folder | Purpose |
|---|---|---|
content | plugins/content | Preparing, saving and deleting content |
system | plugins/system | Stages of handling any request |
user | plugins/user | Login, logout, registration, saving a user |
authentication | plugins/authentication | Ways of checking a name and password |
editors-xtd | plugins/editors-xtd | Buttons below the editor |
webservices | plugins/webservices | API routes |
console | plugins/console | Console commands |
task | plugins/task | Scheduler tasks |
A system plugin
Plugins of the system group are loaded on every request — on the site and in the panel. Create a second plugin modelled on the first:
plugins/system/hello/
├── hello.xml
├── services/provider.php
└── src/Extension/Hello.phpIn the manifest replace group="content" with group="system", the name with plg_system_hello, the namespace with My\Plugin\System\Hello. In the provider use PluginHelper::getPlugin('system', 'hello') and the new class. The class itself:
// plugins/system/hello/src/Extension/Hello.php
namespace My\Plugin\System\Hello\Extension;
defined('_JEXEC') or die;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\Event;
use Joomla\Event\SubscriberInterface;
final class Hello extends CMSPlugin implements SubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
'onAfterInitialise' => 'addHeader',
];
}
public function addHeader(Event $event): void
{
$this->getApplication()->setHeader('X-Frame-Options', 'SAMEORIGIN', true);
}
}Install the plugin through Discover and enable it. Open the browser developer tools, the Network tab: the response headers of every page now include X-Frame-Options.
Request events
System events come in this order:
| Event | When it happens |
|---|---|
onAfterInitialise | Joomla is loaded, the request is not parsed yet |
onAfterRoute | The component and the page are determined |
onAfterDispatch | The component has run, the content is ready |
onBeforeRender | Before the template assembles the page |
onBeforeCompileHead | Before the head tags are output — the last chance to add styles and scripts |
onAfterRender | The page is ready and its whole text can be changed |
To run code on the site only, check the client: $this->getApplication()->isClient('site').
A user plugin
The plugin plugins/user/hello with the namespace My\Plugin\User\Hello is created the same way. It greets a user after login:
// plugins/user/hello/src/Extension/Hello.php
public static function getSubscribedEvents(): array
{
return [
'onUserAfterLogin' => 'greet',
];
}
public function greet(Event $event): void
{
$options = $event->getArgument('options');
$this->getApplication()->enqueueMessage('Welcome back, ' . $options['user']->name . '!');
}The event carries an options array that holds the user who logged in. enqueueMessage() queues a message — it appears at the top of the next page. Log in on the site: "Welcome back, Anna!" is shown above the content.
Content and user events
| Event | When it happens |
|---|---|
onContentPrepare | Text is being prepared for output |
onContentBeforeSave, onContentAfterSave | Before and after a record is saved |
onContentAfterDelete | After a record is deleted |
onContentPrepareForm | A form is prepared — fields can be added to it |
onUserAfterLogin, onUserLogout | Login and logout |
onUserBeforeSave, onUserAfterSave | Before and after a user is saved |
Ready examples are in the core folders: plugins/content, plugins/system, plugins/user.
Common mistake
Heavy work — database queries or calls to an external service — is put into a system plugin without any conditions. Such code runs on every request, including the control panel and the API. Check the client and the address first, and only then do the work.