Add WordPress hooks
Simply registers WordPress actions and filters in two ways:
- with PHP attributes on the methods of any service (recommended);
- with a class implementing
HookableInterface, which adds its hooks itself.
Hooks are registered on the after_setup_theme action, when the framework builds its container. Hooks that run earlier (plugins_loaded, setup_theme...) are not triggered: register them with add_action() in your plugin file.
With PHP attributes
Add #[Action] or #[Filter] to a public method of a service (any class of the src/ directory of a registered plugin or theme). No tag nor configuration is needed.
- Action
- Filter
<?php
namespace MyPlugin\Hook;
use Simply\Core\Attributes\Action;
class Setup
{
#[Action('init')]
public function registerBlocks(): void
{
// ...
}
}
<?php
namespace MyPlugin\Hook;
use Simply\Core\Attributes\Filter;
class Excerpt
{
#[Filter('excerpt_length', 20)]
public function length(int $length): int
{
return 30;
}
#[Filter('the_title', 10, 2)]
public function title(string $title, int $postId = 0): string
{
return $title;
}
}
Both attributes take (string $hook, int $priority = 10, int $numberArguments = 1), and can be repeated on the same method. Give optional parameters a default value: other code may apply the same hook with fewer arguments.
- The service is created when WordPress runs the hook, not on every request: inject what you need in the constructor without worrying about performance.
- The method must be public, and must not take a parameter by reference: otherwise the container build fails with an explicit message. For a hook that passes values by reference (
do_action_ref_array), useHookableInterface. - A service whose id is not its class name, and several services of the same class, all get their hooks.
Use other services lazily
Constructor injection creates the dependencies with the hook service. To create a dependency only when it is used, subscribe to it with ServiceMethodsSubscriberTrait:
<?php
namespace MyPlugin\Hook;
use MyPlugin\Service\TokenGenerator;
use Simply\Core\Attributes\Action;
use Symfony\Contracts\Service\Attribute\SubscribedService;
use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait;
use Symfony\Contracts\Service\ServiceSubscriberInterface;
class LiveEndpoint implements ServiceSubscriberInterface
{
use ServiceMethodsSubscriberTrait;
#[Action('rest_api_init')]
public function registerEndpoint(): void
{
$token = $this->tokenGenerator()->generate();
// ...
}
#[SubscribedService]
private function tokenGenerator(): TokenGenerator
{
return $this->container->get(__METHOD__);
}
}
(ServiceSubscriberTrait, deprecated by Symfony, is still supported.)
Debug the registered hooks
php bin/console simply:debug:hook --hook_name=the_title
lists the callbacks of a hook with their priority and source file. See the CLI.
Unhooking an attribute hook
The WordPress callback of an attribute hook is a Simply\Core\Hook\LazyHookListener, not [$service, 'method']: remove_action() with [$service, 'method'] does not find it. Find the listener instead, once the framework is ready:
<?php
use MyPlugin\Hook\Excerpt;
use Simply\Core\Hook\LazyHookListener;
add_action('simply/core/after_bootstrap', function (): void {
global $wp_filter;
foreach ($wp_filter['the_title']->callbacks[10] ?? [] as $callback) {
$listener = $callback['function'];
if ($listener instanceof LazyHookListener && $listener->class === Excerpt::class && $listener->method === 'title') {
remove_filter('the_title', $listener, 10);
}
}
});
LazyHookListener exposes the serviceId, class and method of the hook.
With HookableInterface
Implement Simply\Core\Contract\HookableInterface: its register() method is called on after_setup_theme, and adds the hooks. The class is tagged wp.hook automatically.
<?php
namespace MyPlugin\Hook;
use Simply\Core\Contract\HookableInterface;
class Excerpt implements HookableInterface
{
public function register(): void
{
add_filter('excerpt_length', [$this, 'length']);
add_filter('excerpt_more', [$this, 'more']);
}
public function length(int $length): int
{
return 30;
}
public function more(string $more): string
{
return '…';
}
}
Unlike attribute hooks, the class is created on every request. simply:make:hook generates this kind of class.
Do not add the wp.hook tag to a class that only uses attributes: the framework would call a register() method that does not exist.
With the CLI
php bin/console simply:make:hook
creates a HookableInterface class in src/Hook/ and a YAML file declaring it with the wp.hook tag. The tag is already added by autoconfiguration, and this definition replaces the one Simply creates for the class: if the class has constructor dependencies, add autowire: true to it, or delete the YAML file.