Use hooks when a payload may be transformed before the owning system continues. Use events when listeners need to react after something happened.
Hook and event names should use at least three lowercase dot-delimited segments.
Declare In Manifest
'hooks' => [
'core.frontend_targets.list' => ['amv_example_notes_frontend_targets_list'],
'core.frontend_targets.resolve' => ['amv_example_notes_frontend_target_resolve'],
],
'events' => [
'example_notes.note.created' => ['amv_example_notes_note_created_listener'],
],
Register A Hook Listener
$hookRegistry = amv_core_hook_listener_register(
$hookRegistry,
'example_notes.note.before_save',
'amv_example_notes_normalize_before_save',
100,
['provider_key' => 'example_notes']
);
function amv_example_notes_normalize_before_save(array $payload): array
{
$payload['slug'] = amv_core_slug_normalize((string) ($payload['slug'] ?? $payload['title'] ?? ''));
return $payload;
}
The owning addon still validates and writes the record. A hook only returns a transformed payload.
Apply A Hook
$payload = amv_core_hook_apply(
$hookRegistry,
'example_notes.note.before_save',
$payload,
['addon_key' => 'example_notes']
);
Dispatch An Event
amv_core_event_dispatch($eventRegistry, 'example_notes.note.created', [
'note_uuid' => $noteUuid,
'actor_uuid' => $actorUuid,
]);
Events should not change the original write. They are for follow-up behavior such as audit records, notifications, cache invalidation, or indexing.
Listener Example
function amv_example_notes_note_created_listener(array $payload): void
{
amv_audit_trail_record('example_notes.note.created', [
'note_uuid' => (string) ($payload['note_uuid'] ?? ''),
]);
}
Smoke Expectations
For a governed addon, smoke tests should prove:
- hook name is valid
- listener registers
- hook application returns the expected transformed payload
- event dispatch reaches a listener without mutating the source write
- listener failure does not expose private stack traces to public routes
Related: Hooks and Events/Hook and Event Overview, Addon Development/Build Your First Addon.