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.

Was this page helpful?