New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[4.x] Hooks #9481
[4.x] Hooks #9481
Conversation
We thought through how this might end up being used and ended up on using Laravel's Pipeline feature. tl;dr It lets you pass something through multiple closures. Each closure does something and passes onto the We figured that this feature would eventually be used to modify stuff - for example the entries that get returned from a collection tag. So, we needed a way to be able to pass something through and finally return it. use Statamic\Tags\Collection as CollectionTag;
CollectionTag::addHook('fetched-entries', function ($entries, $next) {
// Take the first 5 items and convert them into custom entry instances.
$entries = $entries->take(5)->mapInto(CustomEntry::class);
// Then pass it along to any other registered hook closures, and finally
// back to the tag where the hook was triggered.
return $next($entries);
}); Then there's also the use case that I know you need your project, which is to perform some logic on the final version of a thing. For example, grabbing all the entry IDs that would be output in a listing. CollectionTag::addHook('fetched-entries', function ($entries, $next) {
// By calling $next() first, if there are other hooks that *do* modify entries, you'll be able
// to get the end result even if your hook is registered before theirs.
$entries = $next($entries);
$ids = $entries->pluck('id');
return $entries;
}); Also, inside the closure, {{ collection preset="basics" }} ... {{ /collection }} CollectionTag::addHook('init', function ($value, $next) {
if ($this->params->get('preset') === 'basics') {
$this->params->merge([
'from' => 'articles',
'limit' => '5',
'as' => 'articles',
]);
}
return $next($value);
}); Aside from the functionality itself, this PR adds the |
This looks great. Using a pipeline is a great idea. Would it also be worth adding an ‘output’ hook in the output method? That way most tags would be covered by default? |
We could, but I don't like adding code "just because". If someone shows a use case for it, sure, we can add it. |
Some more tweaks:
|
Edit by Jason:
This PR has changed substantially since this initial description. Check the comments below for more details.
This PR adds the concept of 'hooks' into points in the tag lifecycle, allowing for modification of the state of the tag at that point.
Combined with macroable, this allows for reuse of the base tags in some circumstances where otherwise a custom tag would be required.
Usage is as follows:
Ideally this PR would also allow for a hook into the output of the tag (eg a render or processed hook) but I couldn't see how to do that without affecting the magic __call() on all tags that implement it. Maybe you have some bright ideas on an approach for that? Failing that, we could add hook into the output() method.