One of the most powerful tools in WordPress is the hook system it uses. It’s a nice way to modify values from anywhere. It adds huge flexibility to any WordPress site. Let’s take a look, how to implement this in Laravel.
The Basic Concept
The basic idea is really the same as the WordPress hook system. There are some values somewhere in the code, and we want to modify them easily from outside, without modifying any code. Also, setting up a priority would be nice, since we have more control over the modifications.
Events vs. Hooks
It would be really nice if we could use Laravel’s event system to implement this functionality, but this is not really ideal for that. Because of this, we’ll implement a small hook repository that will store and order the registered hooks based on their priority.
The Hook Repository
This repository will be a really simple place to store our hooks and use them whenever we need:
class HookRepository { /** * The repository items. * * @var \Illuminate\Support\Collection */ protected $items; /** * Create a new repository instance. * * @return void */ public function __construct() { $this->items = collect(); } /** * Dynamically call methods. * * @param string $method * @param array $arguments * @return mixed */ public function __call(string $method, array $arguments) { return $this->items->{$method}(...$arguments); } /** * Register a new hook callback. * * @param string|array $hook * @param callable $callback * @param int $priority * @return void */ public function register($hook, callable $callback, int $priority = 10): void { $this->items->push(compact('hook', 'callback', 'priority')); } /** * Apply the callbacks on the given hook and value. * * @param string $hook * @param array $arguments * @return mixed */ public function apply(string $hook, ...$arguments) { return $this->items->filter(function ($filter) use ($hook) { return !! array_filter((array) $filter['hook'], function ($item) use ($hook) { return Str::is($item, $hook); }); })->sortBy('priority')->reduce(function ($value, $filter) use ($arguments) { return call_user_func_array($filter['callback'], [$value] + $arguments); }, $arguments[0] ?? null); } }
So, we have two methods here, the register and the apply. All the other calls will be forwarded to the collection instance that holds the hooks.
We can register hooks in a service provider for example:
public function boot() { Hook::register('jobs.tags', function ($tags, $job) { return array_merge($tags, $job->someCondition() ? ['foo'] : ['bar']); }); }
Applying Hooks
So, where to apply hooks? Basically anywhere you want. The upside of this solution is, you don’t really need a complex value manager for different places. You can use hooks, pass any parameter you want and return with the modified value that will be used later.
public function tags() { return Hook::apply('jobs.tags', ['a', 'b'], $this); }
We call the apply method and pass the hook and the value first, then any other parameter we may need in the callback.
Summary
The hook system is a nice and slim solution that you can use everywhere in your system. This is very handy especially when you are hooking into the application from a package or another service.
Of course, this example class can be extended with many other methods like flush or remove, but it represents the basic idea well enough.