Hooks
Hooks customize comment models, submissions, queries, and rendered data without forking Meerkat.
#How hooks work
Hooks that change data receive and return a $payload object:
1use Stillat\Meerkat\Database\Models\Comment;
2
3Comment::hook('saving', function ($payload) {
4 $payload->model->author_name = ucfirst($payload->model->author_name ?? '');
5 return $payload;
6});
Hooks that only respond to an event do not need a return value:
1use Stillat\Meerkat\Database\Models\Comment;
2
3Comment::hook('saved', function ($payload) {
4 Log::info('Comment saved', ['id' => $payload->model->id]);
5});
#Where to register
Register hooks in a service provider's boot() method.
1namespace App\Providers;
2
3use Illuminate\Support\ServiceProvider;
4use Stillat\Meerkat\Database\Models\Comment;
5use Stillat\Meerkat\Data\CommentRepository;
6use Stillat\Meerkat\Http\Controllers\CommentController;
7
8class MeerkatCustomizationsProvider extends ServiceProvider
9{
10 public function boot()
11 {
12 Comment::hook('saving', $this->normalizeAuthorName(...));
13 CommentRepository::hook('deletingComment', $this->logDeletion(...));
14 CommentController::hook('creatingComment', $this->checkBlacklist(...));
15 }
16}
#Common hooks
#saving (Comment model)
Change a comment immediately before Meerkat saves it by modifying $payload->model. The $payload->attributes array is a read-only copy taken before the save; changes to that array are ignored.
1Comment::hook('saving', function ($payload) {
2 if (strlen(trim($payload->model->comment_text ?? '')) < 5) {
3 $payload->model->moderation_status = 'pending';
4 $payload->model->is_published = false;
5 }
6
7 return $payload;
8});
#saved (Comment model)
Runs after a successful save. The payload includes was_created to distinguish new comments from updates.
1Comment::hook('saved', function ($payload) {
2 if ($payload->was_created) {
3 Http::post(env('SLACK_WEBHOOK'), [
4 'text' => "New comment on thread {$payload->model->thread_id}",
5 ]);
6 }
7});
#creatingComment (CommentController)
Runs after spam guards, rate limiting, and blueprint validation but before the form events.
1CommentController::hook('creatingComment', function ($comment) {
2 if (str_starts_with($comment->user_ip, '10.0.')) {
3 $comment->comment_data = array_merge($comment->comment_data, ['internal' => true]);
4 }
5 return $comment;
6});
#form-fields-prepared (Meerkat tag)
Change the fields rendered by {{ meerkat:form }} after Meerkat builds them and before it renders the HTML.
1\Stillat\Meerkat\Tags\Meerkat::hook('form-fields-prepared', function ($payload) {
2 $payload->fields = collect($payload->fields)
3 ->sortBy(fn ($field) => $field['handle'] === 'comment' ? 0 : 1)
4 ->values()
5 ->all();
6
7 return $payload;
8});
#Order hooks run
Hooks on the same event run in registration order. Each hook receives the previous hook's output.
#Hook reference
#Comment model
Register on Stillat\Meerkat\Database\Models\Comment.
| Hook | When it fires | Payload |
|---|---|---|
saving |
At the start of Comment::save(). |
attributes (read-only snapshot), model, is_creating. Modify model. (Alias: before-saving-comment-model.) |
saved |
After the row is written. | model, was_created. (Alias: after-saved-comment-model.) |
augmented |
When comment data is prepared for display. | The prepared data instance. |
#Comment submission
Register on Stillat\Meerkat\Http\Controllers\CommentController.
| Hook | When it fires | Payload |
|---|---|---|
creatingComment |
During submission, after validation and spam checks, before save. | The unsaved Comment. |
before-saving-comment |
Immediately before Meerkat writes the comment. | comment, entry, parent_comment, values, authenticated_user. |
after-saved-comment |
After a successful save. | comment, entry, is_new, visual_id. |
#Comment actions
Register on Stillat\Meerkat\Data\CommentRepository.
| Hook | When it fires | Payload |
|---|---|---|
deletingComment |
Before a comment is deleted. | The Comment. |
after-comment-deleted |
After deletion. | id, was_published, thread_id, had_children. |
markingAsSpam |
Before marking as spam (flags already set). | The Comment. |
markingAsHam |
Before marking as ham (flags already set). | The Comment. |
publishingComment |
Before publishing. | The Comment. |
unpublishingComment |
Before unpublishing. | The Comment. |
rejectingComment |
Before rejecting (fields already set). | The Comment. |
restoringComment |
Before restoring (removal fields cleared). | The Comment. |
after-spam-determined |
After spam detection, before any action is taken. | comment, entry, is_spam, checked_for_spam. Override is_spam / checked_for_spam. |
spam-action-decided |
After deciding what to do with a flagged comment, before doing it. | comment, is_spam, should_delete, should_unpublish. |
#Control Panel writes
Register on Stillat\Meerkat\Http\Controllers\CP\CommentController.
| Hook | When it fires | Payload |
|---|---|---|
before-saving-reply |
Before Meerkat saves a reply submitted from the Control Panel. | comment, parent_comment, entry, values, authenticated_user. |
before-updating-comment |
Before Meerkat saves a comment edited in the Control Panel. | comment, values, authenticated_user. |
#Control Panel listing
Register on Stillat\Meerkat\Hooks\CommentsIndexQuery.
| Hook | When it fires | Payload |
|---|---|---|
query |
When Meerkat builds the Control Panel comments listing query. | query. Modify the query. |
#Spam checks
Register on Stillat\Meerkat\Hooks\CommentSpamCheck. Runs for both front-end submissions and repository-driven checks.
| Hook | When it fires | Payload |
|---|---|---|
checking |
Before the configured spam guards run. | entry, comment, should_check, is_spam. Set should_check to false (with an is_spam value) to skip the guards. |
#API and Control Panel responses
| Hook | Register on | When it fires | Payload |
|---|---|---|---|
data |
Stillat\Meerkat\Http\Resources\Comments\PublicCommentResource |
Before the public API returns a comment. | comment, data, privileged, request. Modify data. |
values |
Stillat\Meerkat\Http\Resources\Comments\CommentResource |
Before Meerkat returns Control Panel comment values. | comment, values, request. Modify values. |
#{{ meerkat }} tag
Register on Stillat\Meerkat\Tags\Meerkat.
| Hook | When it fires | Payload |
|---|---|---|
comments-query-building |
After the comments query is built, before it runs. | query, params, tag_context. Modify the query. |
comments-query-results |
After the query runs, before the thread is assembled. | comments, query, params. Modify the comments. |
form-sections |
After the form's sections are built from the blueprint. | sections, blueprint. |
form-fields-prepared |
After the fields are flattened from the sections. | fields, sections, errors. |
attrs |
Before the <form> attributes are rendered. |
attrs, data. Modify attrs. |
after-open |
After the opening <form> tag, before the fields. |
html, data. Modify html. |
before-close |
Before the closing </form> tag. |
html, data. Modify html. |