Skip to content

Kirby 4.5.0

Hooks

What are hooks?

Kirby fires a bunch of events when important things happen in the background. For example when a page is being created or deleted or a file gets uploaded. You can hook into those events and add your own functions that will be executed when those events happen.

Hooks are not restricted to Panel events, but are implemented everywhere: most hooks are called no matter if an event happens in the Panel, on the command line or in your own scripts.

For many hooks, Kirby provides two variants of each hook: before and after hooks.

Before hooks

A before hook is triggered before an action is executed, i.e. before a page is actually updated, a file uploaded, a route called etc.

Typical use cases for before hooks include:

  • Throw an error to prevent certain users from executing an action in general or under certain circumstances.
  • Store information in the session.
  • Log something before an action is executed.

After hooks

An after hook is triggered right after the action was executed. Some typical use cases for these hooks are:

  • Automatically resize a huge image and save a smaller version instead.
  • Modify user entered information when a user saves the page.
  • Log something when an action is executed.

Hooks can execute code, but you can't return anything from them or redirect anywhere. If you try to, an error is thrown in the Panel.

Available events

Registering hooks

Hooks can be registered in your config.php or in plugins:

In your config

/site/config/config.php
return [
    'hooks' => [
        'page.delete:before' => function ($page) {
            // do something before a page gets deleted
        }
    ]
];

In a plugin

In a plugin, hooks are registered with the hooks extension. The extension accepts an array of key/value pairs where the key is the event and the value a function with the code that should be executed before or after an event.

Kirby::plugin('your/plugin', [
    'hooks' => [
        'page.delete:before' => function ($page) {
            // do something before a page gets deleted
        },
        'page.create:after' => function ($page) {
            // do something after the page was created
        }
    ]
]);

If you want to register more than one function to a hook, you can simple pass an array of functions:

Kirby::plugin('your/plugin', [
    'hooks' => [
        'page.delete:before' => [
                     function ($page) {
                // do something before a page gets deleted
             },
                     function ($page) {
                // do something else before a page gets deleted
             }
                ],
    ]
]);

Wildcard hooks

If you want to register the same hook for multiple events, you can register a wildcard hook (either in your config or in a plugin):

/site/config/config.php
return [
    'hooks' => [
        'page.*:before' => function ($page) {
            // do something before something happens with a page
        }
    ]
];

The following wildcards are supported (in this example for an event type.action:state):

  • type.*:state,
  • type.action:*,
  • type.*:*,
  • *.action:state,
  • *.action:*,
  • *:state,
  • *

Depending on where you put the wildcard *, your hook will receive all events that match the wildcard name.

If you only want to react on some, but not all matched events, you can filter inside the hook with the $event object:

/site/config/config.php
return [
    'hooks' => [
        'page.*:before' => function ($event, $page) {
            // check if we want to handle the action
            if (in_array($event->action(), ['create', 'delete']) !== true) {
                // no, return early
                return;
            }

            // do something before a page gets created or deleted
        }
    ]
];

You can read more about the $event object below.

Accessing $kirby, $site and $user in a hook callback

You get full access to the current Kirby instance and its API with $this in a hook callback.

$kirby    = $this;
$site     = $this->site();
$user     = $this->user();
$username = $this->user()->username();
$role     = $this->user()->role();

Hook arguments

Kirby provides the hook arguments by variable name, not by position (similar to controllers). This allows you to request just the arguments you need in any order. All arguments that are not available will be passed as null:

/site/config/config.php
return [
    'hooks' => [
        'route:after' => function ($result, $path) {
            // this hook only cares about these two arguments
        }
    ]
];

There is also a special $event argument that contains all information about the event, including the full event name, its individual parts (type, action and state) and all named hook arguments:

/site/config/config.php
return [
    'hooks' => [
        'page.create:before' => function ($event) {
            $name   = $event->name();   // 'page.create:before'
            $type   = $event->type();   // 'page'
            $action = $event->action(); // 'create'
            $state  = $event->state();  // 'before'
            $page   = $event->page();   // $page
            $input  = $event->input();  // $input
        }
    ]
];

Error Handling

You can react on errors in a hook callback by throwing an Exception. The error message will be displayed in the Panel.

Kirby::plugin('your/plugin', [
    'hooks' => [
        'page.update:after' => function ($newPage, $oldPage) {
            throw new Exception('Page Updated');
        },
        'page.create:after' => function ($page) {
            throw new Exception('Page Created');
        },
    ]
]);

Creating your own hooks

You can also define your own custom hook types in plugins, which works just like with the built-in hooks:

Kirby::plugin('your/plugin', [
    'hooks' => [
        'your-plugin.your-hook' => function ($page) {
            // do whatever you need
        },
    ]
]);

As you can see, only the name of the hook has changed. Please make sure to namespace your hooks by including the plugin name in the hook name. Otherwise your hooks might conflict with other plugins or future built-in hooks.

You can trigger your own hooks from anywhere in the system with the $kirby->trigger() and $kirby->apply() methods.

The two main use-cases for custom hooks are communication between two plugins (one plugin triggers an event and another registers a hook to listen for it) and hooks that are registered from the site config to allow users to add custom behavior to plugins.