Hooks are entry points into the Contao core (and some of its extension bundles). Have a look at the hook reference for a list of all available hooks. You can register your own callable logic that will be executed as soon as a certain point in the execution flow of the core will be reached. Consider the following example.
if (isset($GLOBALS['TL_HOOKS']['activateAccount']) && \is_array($GLOBALS['TL_HOOKS']['activateAccount']))
{
foreach ($GLOBALS['TL_HOOKS']['activateAccount'] as $callback)
{
$this->import($callback[0]);
$this->{$callback[0]}->{$callback[1]}($objMember, $this);
}
}
The hook activateAccount
will be executed as soon as a user account is activated
and all the callable functions registered to the particular hook are called in
order of addition.
In order to be compatible with the method execution you need to consider the parameters that will be passed to your function.
$this->{$callback[0]}->{$callback[1]}($objMember, $this);
In this case an instance of Contao\MemberModel
and an instance of Contao\ModuleRegistration
will be passed as arguments to the hook.
Some hooks require its listener to return a specific value, that will be passed
along. For example the compileFormFields
needs you to return arrFields
.
if (isset($GLOBALS['TL_HOOKS']['compileFormFields']) && \is_array($GLOBALS['TL_HOOKS']['compileFormFields']))
{
foreach ($GLOBALS['TL_HOOKS']['compileFormFields'] as $callback)
{
$this->import($callback[0]);
$arrFields = $this->{$callback[0]}->{$callback[1]}($arrFields, $formId, $this);
}
}
As of Contao 4.13, there are four different ways of subscribing to a hook. The recommended way is using PHP attributes together with invokable services. Which one you use depends on your setup. For example, if you still need to support PHP 7 you can use annotations. If you still develop hooks for Contao 4.4 then you still need to use the PHP array configuration.
Using attributes or annotations means it is only necessary to create one file for the respective adaptation when using Contao’s default
way of automatically registering services under the App\
namespace within the src/
folder.
since 4.13 Contao implements PHP attributes (available since PHP 8) with which you can tag your service to be registered as a hook.
// src/EventListener/ParseArticlesListener.php
namespace App\EventListener;
use Contao\CoreBundle\DependencyInjection\Attribute\AsHook;
use Contao\FrontendTemplate;
use Contao\Module;
class ParseArticlesListener
{
#[AsHook('parseArticles', priority: 100)]
public function onParseArticles(FrontendTemplate $template, array $newsEntry, Module $module): void
{
// Do something …
}
}
The priority parameter is optional.
since 4.8
Contao also supports its own annotation formats via the Service Annotation Bundle.
// src/EventListener/ParseArticlesListener.php
namespace App\EventListener;
use Contao\CoreBundle\ServiceAnnotation\Hook;
use Contao\FrontendTemplate;
use Contao\Module;
class ParseArticlesListener
{
/**
* @Hook("parseArticles", priority=100)
*/
public function onParseArticles(FrontendTemplate $template, array $newsEntry, Module $module): void
{
// Do something …
}
}
The priority parameter is optional.
since 4.5 Since Contao 4.5 hooks can be registered using the contao.hook
service tag.
# config/services.yaml
services:
App\EventListener\ActivateAccountListener:
tags:
- { name: contao.hook, hook: activateAccount, method: onAccountActivation, priority: 100 }
The service tag can have the following options:
Option | Type | Description |
---|---|---|
name | string | Must be contao.hook . |
hook | string | The name of the hook this service will listen to. |
method | string | Optional: the method name in the service - otherwise infered from the hook (e.g. onActivateAccount ). |
priority | integer | Optional: priority of the hook. (Default: 0 ) |
In this legacy way hooks are registered by extending the respective global array in your
config.php
file (ever since hooks were introduced in Contao).
// contao/config.php
use App\EventListener\ActivateAccountListener;
$GLOBALS['TL_HOOKS']['activateAccount'][] = [ActivateAccountListener::class, 'onActivateAccount'];
In this case, the method onActivateAccount
in the class or service App\EventListener\ActivateAccountListener
is called as soon as the hook activateAccount
is executed. Note that the first element in the array can also be a service reference
since Contao 4.3.
// src/EventListener/ActivateAccountListener.php
namespace App\EventListener;
use Contao\MemberModel;
use Contao\ModuleRegistration;
class ActivateAccountListener
{
public function onAccountActivation(MemberModel $member, ModuleRegistration $module): void
{
// Do something …
}
}
When using the default priority, or a priority of 0
the hook will be executed according to the extension loading order, along side hooks
that are using the legacy configuration via $GLOBALS['TL_HOOK']
. With a priority that is greater than zero the hook will be executed
before the legacy registered hooks. With a priority of lower than zero the hook will be executed after the legacy registered hooks.
since 4.9 You can also use invokable classes for your services. If a service is
tagged with contao.hook
and no method name is given, the __invoke
method will
be called automatically. This also means that you can define the service annotation
on the class, instead of a method:
// src/EventListener/ParseArticlesListener.php
namespace App\EventListener;
use Contao\CoreBundle\DependencyInjection\Attribute\AsHook;
use Contao\FrontendTemplate;
use Contao\Module;
#[AsHook('parseArticles')]
class ParseArticlesListener
{
public function __invoke(FrontendTemplate $template, array $newsEntry, Module $module): void
{
// Do something …
}
}
// src/EventListener/ParseArticlesListener.php
namespace App\EventListener;
use Contao\CoreBundle\ServiceAnnotation\Hook;
use Contao\FrontendTemplate;
use Contao\Module;
/**
* @Hook("parseArticles")
*/
class ParseArticlesListener
{
public function __invoke(FrontendTemplate $template, array $newsEntry, Module $module): void
{
// Do something …
}
}
# config/services.yaml
services:
App\EventListener\ParseArticlesListener:
tags:
- { name: contao.hook, hook: activateAccount }
// src/EventListener/ParseArticlesListener.php
namespace App\EventListener;
use Contao\FrontendTemplate;
use Contao\Module;
class ParseArticlesListener
{
public function __invoke(FrontendTemplate $template, array $newsEntry, Module $module): void
{
// Do something …
}
}
// contao/config.php
use App\EventListener\ParseArticlesListener;
$GLOBALS['TL_HOOKS']['activateAccount'][] = [ParseArticlesListener::class, '__invoke'];
// src/EventListener/ParseArticlesListener.php
namespace App\EventListener;
use Contao\FrontendTemplate;
use Contao\Module;
class ParseArticlesListener
{
public function __invoke(FrontendTemplate $template, array $newsEntry, Module $module): void
{
// Do something …
}
}