Hooks Reference
Complete reference guide to LaraDashboard's enum-based hooks system for extending functionality with action hooks and filter hooks.
Hooks Reference
LaraDashboard implements a WordPress-like hooks system using PHP enums for type safety. This allows modules and custom code to extend functionality without modifying core files.
Overview
What Are Hooks?
Hooks are predefined points in the code where external code can be attached:
- Action Hooks - Execute code at specific points (no return value)
- Filter Hooks - Modify data passing through (returns modified value)
Why Use Hooks?
- Non-invasive - Extend without modifying core code
- Upgradeable - Core updates won't break customizations
- Type-safe - Enum-based hooks prevent typos
- Modular - Multiple modules can hook into the same point
- Testable - Hooks can be tested independently
Using Hooks
Method 1: Hook Facade (Recommended)
use App\Support\Facades\Hook;
use App\Enums\Hooks\UserActionHook;
use App\Enums\Hooks\PostFilterHook;
// Add action hook
Hook::addAction(UserActionHook::USER_CREATED_AFTER, function ($user) {
// Send welcome email
$user->notify(new WelcomeNotification());
});
// Add filter hook
Hook::addFilter(PostFilterHook::POST_CONTENT, function ($content, $post) {
return $content . '<p>Thanks for reading!</p>';
}, 20, 2);
Method 2: Helper Functions
use App\Enums\Hooks\UserActionHook;
use App\Enums\Hooks\AdminFilterHook;
// Add action - accepts enum or string
ld_add_action(UserActionHook::USER_CREATED_AFTER, function ($user) {
Log::info("User created: {$user->email}");
});
// Add filter - accepts enum or string
ld_add_filter(AdminFilterHook::ADMIN_MENU_GROUPS_BEFORE_SORTING, function ($groups) {
// Add custom menu group
return $groups;
});
// Fire action
ld_do_action(UserActionHook::USER_CREATED_AFTER, $user);
// Apply filter
$content = ld_apply_filters(PostFilterHook::POST_CONTENT, $content, $post);
Priority Parameter
Lower priority runs first (default is 20):
// Runs first (priority 5)
Hook::addFilter(PostFilterHook::POST_CONTENT, function ($content) {
return $this->sanitize($content);
}, 5);
// Runs second (priority 10)
Hook::addFilter(PostFilterHook::POST_CONTENT, function ($content) {
return $this->processShortcodes($content);
}, 10);
// Runs last (priority 30)
Hook::addFilter(PostFilterHook::POST_CONTENT, function ($content) {
return $this->addTracking($content);
}, 30);
Hook Enums Reference
All hooks are defined as PHP enums in app/Enums/Hooks/.
Admin Filter Hooks
App\Enums\Hooks\AdminFilterHook
| Hook | Description |
|---|---|
ADMIN_HEAD |
Filter content in admin head |
ADMIN_SITE_ONLY |
Control admin-only mode |
ADMIN_FOOTER_BEFORE |
Before admin footer |
ADMIN_FOOTER_AFTER |
After admin footer |
DARK_MODE_TOGGLER_BEFORE_BUTTON |
Before dark mode toggle |
DARK_MODE_TOGGLER_AFTER_BUTTON |
After dark mode toggle |
HEADER_RIGHT_MENU_BEFORE |
Before header right menu |
HEADER_RIGHT_MENU_AFTER |
After header right menu |
USER_DROPDOWN_BEFORE |
Before user dropdown |
USER_DROPDOWN_AFTER_USER_INFO |
After user info in dropdown |
SIDEBAR_MENU_GROUP_BEFORE |
Before sidebar menu group |
SIDEBAR_MENU_BEFORE |
Before sidebar menu item |
SIDEBAR_MENU_AFTER |
After sidebar menu item |
ADMIN_MENU_GROUPS_BEFORE_SORTING |
Modify menu groups before sort |
use App\Enums\Hooks\AdminFilterHook;
use App\Support\Facades\Hook;
// Add custom content to header
Hook::addFilter(AdminFilterHook::HEADER_RIGHT_MENU_AFTER, function ($html) {
return $html . '<a href="/notifications">Notifications</a>';
});
// Disable admin-only mode for frontend modules
Hook::addFilter(AdminFilterHook::ADMIN_SITE_ONLY, function () {
return false;
});
User Hooks
UserActionHook
App\Enums\Hooks\UserActionHook
| Hook | Description |
|---|---|
USER_CREATED_BEFORE |
Before user creation |
USER_CREATED_AFTER |
After user creation |
USER_UPDATED_BEFORE |
Before user update |
USER_UPDATED_AFTER |
After user update |
USER_PROFILE_UPDATED_BEFORE |
Before profile update |
USER_PROFILE_UPDATED_AFTER |
After profile update |
USER_DELETED_BEFORE |
Before user deletion |
USER_DELETED_AFTER |
After user deletion |
USER_BULK_DELETED_BEFORE |
Before bulk deletion |
USER_BULK_DELETED_AFTER |
After bulk deletion |
use App\Enums\Hooks\UserActionHook;
// Send welcome email after user creation
Hook::addAction(UserActionHook::USER_CREATED_AFTER, function ($user) {
$user->notify(new WelcomeNotification());
Log::info("New user: {$user->email}");
});
// Cleanup after user deletion
Hook::addAction(UserActionHook::USER_DELETED_AFTER, function ($user) {
Cache::forget("user-{$user->id}");
});
UserFilterHook
App\Enums\Hooks\UserFilterHook
| Hook | Description |
|---|---|
USER_CREATED_BEFORE |
Filter user data before create |
USER_UPDATED_BEFORE |
Filter user data before update |
USER_STORE_VALIDATION_RULES |
Modify store validation rules |
USER_UPDATE_VALIDATION_RULES |
Modify update validation rules |
USERS_AFTER_BREADCRUMBS |
After users page breadcrumbs |
USERS_AFTER_TABLE |
After users table |
use App\Enums\Hooks\UserFilterHook;
// Add custom validation rule
Hook::addFilter(UserFilterHook::USER_STORE_VALIDATION_RULES, function ($rules) {
$rules['department'] = 'required|string';
return $rules;
});
Post Hooks
PostActionHook
App\Enums\Hooks\PostActionHook
| Hook | Description |
|---|---|
POST_CREATED_BEFORE |
Before post creation |
POST_CREATED_AFTER |
After post creation |
POST_UPDATED_BEFORE |
Before post update |
POST_UPDATED_AFTER |
After post update |
POST_DELETED_BEFORE |
Before post deletion |
POST_DELETED_AFTER |
After post deletion |
POST_PUBLISHED_BEFORE |
Before post publication |
POST_PUBLISHED_AFTER |
After post publication |
POST_TAXONOMIES_UPDATED |
After taxonomies updated |
POST_META_UPDATED |
After meta updated |
use App\Enums\Hooks\PostActionHook;
// Notify subscribers when post is published
Hook::addAction(PostActionHook::POST_PUBLISHED_AFTER, function ($post) {
$subscribers = User::subscribers()->get();
Notification::send($subscribers, new NewPostNotification($post));
});
// Clear cache when post is updated
Hook::addAction(PostActionHook::POST_UPDATED_AFTER, function ($post) {
Cache::tags(['posts', "post-{$post->id}"])->flush();
});
PostFilterHook
App\Enums\Hooks\PostFilterHook
| Hook | Description |
|---|---|
POST_CONTENT |
Filter post content |
POST_TITLE |
Filter post title |
POST_EXCERPT |
Filter post excerpt |
POST_QUERY |
Modify post query |
POSTS_AFTER_BREADCRUMBS |
After posts page breadcrumbs |
use App\Enums\Hooks\PostFilterHook;
// Add social buttons to post content
Hook::addFilter(PostFilterHook::POST_CONTENT, function ($content, $post) {
return $content . view('partials.social-buttons', compact('post'))->render();
}, 20, 2);
Settings Hooks
SettingFilterHook
App\Enums\Hooks\SettingFilterHook
| Hook | Description |
|---|---|
SETTINGS_TABS |
Add/modify settings tabs |
SETTINGS_UPDATE_VALIDATION_RULES |
Modify validation rules |
SETTINGS_RESTRICTED_FIELDS |
Add restricted field names |
SETTINGS_GENERAL_TAB_BEFORE_SECTION_START |
Before general tab section |
SETTINGS_GENERAL_TAB_BEFORE_SECTION_END |
End of general tab section |
SETTINGS_APPEARANCE_TAB_* |
Appearance tab hooks |
SETTINGS_CONTENT_TAB_* |
Content tab hooks |
SETTINGS_INTEGRATIONS_TAB_* |
Integrations tab hooks |
SETTINGS_TAB_MENU_BEFORE |
Before tab menu item |
SETTINGS_TAB_MENU_AFTER |
After tab menu item |
SETTINGS_TAB_CONTENT_BEFORE |
Before tab content |
SETTINGS_TAB_CONTENT_AFTER |
After tab content |
use App\Enums\Hooks\SettingFilterHook;
// Add custom settings tab
Hook::addFilter(SettingFilterHook::SETTINGS_TABS, function ($tabs) {
$tabs['yourmodule'] = [
'title' => __('Your Module'),
'icon' => 'lucide:box',
'view' => 'yourmodule::settings.tab',
];
return $tabs;
});
// Add section to general tab
Hook::addFilter(
SettingFilterHook::SETTINGS_GENERAL_TAB_BEFORE_SECTION_END,
function ($html) {
return $html . view('yourmodule::settings.general-section')->render();
}
);
SettingActionHook
App\Enums\Hooks\SettingActionHook
| Hook | Description |
|---|---|
SETTINGS_SAVING_BEFORE |
Before batch save |
SETTINGS_SAVED_AFTER |
After batch save |
SETTING_CREATED_BEFORE |
Before single setting create |
SETTING_CREATED_AFTER |
After single setting create |
SETTING_UPDATED_BEFORE |
Before single setting update |
SETTING_UPDATED_AFTER |
After single setting update |
SETTING_DELETED_BEFORE |
Before setting delete |
SETTING_DELETED_AFTER |
After setting delete |
SETTINGS_CACHE_CLEARED |
When settings cache is cleared |
SETTINGS_CACHE_REFRESHED |
When cache is refreshed |
use App\Enums\Hooks\SettingActionHook;
// Clear cache after settings saved
Hook::addAction(SettingActionHook::SETTINGS_SAVED_AFTER, function ($settings) {
Cache::tags(['settings'])->flush();
});
Permission Hooks
PermissionFilterHook
App\Enums\Hooks\PermissionFilterHook
| Hook | Description |
|---|---|
PERMISSION_GROUPS |
Add custom permission groups |
PERMISSIONS_BY_GROUP |
Filter permissions by group |
PERMISSION_CREATED_BEFORE |
Filter data before create |
PERMISSION_STORE_VALIDATION_RULES |
Modify validation rules |
use App\Enums\Hooks\PermissionFilterHook;
// Register module permissions
Hook::addFilter(PermissionFilterHook::PERMISSION_GROUPS, function ($groups) {
return array_merge($groups, [
[
'group_name' => 'crm',
'permissions' => [
'crm.view',
'crm.create',
'crm.edit',
'crm.delete',
],
],
]);
});
Role Hooks
App\Enums\Hooks\RoleActionHook and App\Enums\Hooks\RoleFilterHook
| Hook | Type | Description |
|---|---|---|
ROLE_CREATED_BEFORE |
Action | Before role creation |
ROLE_CREATED_AFTER |
Action | After role creation |
ROLE_UPDATED_BEFORE |
Action | Before role update |
ROLE_UPDATED_AFTER |
Action | After role update |
ROLE_DELETED_BEFORE |
Action | Before role deletion |
ROLE_DELETED_AFTER |
Action | After role deletion |
Media Hooks
App\Enums\Hooks\MediaActionHook and App\Enums\Hooks\MediaFilterHook
| Hook | Type | Description |
|---|---|---|
MEDIA_UPLOADED_AFTER |
Action | After media upload |
MEDIA_DELETED_BEFORE |
Action | Before media deletion |
MEDIA_DELETED_AFTER |
Action | After media deletion |
MEDIA_URL |
Filter | Filter media URL |
MEDIA_ALLOWED_TYPES |
Filter | Filter allowed upload types |
Email Hooks
App\Enums\Hooks\EmailActionHook and App\Enums\Hooks\EmailFilterHook
| Hook | Type | Description |
|---|---|---|
EMAIL_SENDING |
Action | Before email is sent |
EMAIL_SENT |
Action | After email is sent |
EMAIL_FAILED |
Action | When email fails |
EMAIL_CONTENT |
Filter | Filter email content |
EMAIL_SUBJECT |
Filter | Filter email subject |
EMAIL_RECIPIENTS |
Filter | Filter recipients |
Inbound Email Hooks
App\Enums\InboundEmailHook
Hooks for the IMAP-based inbound email processing system. See Inbound Email System for full documentation.
| Hook | Type | Description |
|---|---|---|
BEFORE_PROCESS |
Action | Before any processing begins on an email |
PROCESS |
Action | Main processing hook |
AFTER_PROCESS |
Action | After successful processing |
PROCESS_FAILED |
Action | When email processing fails |
UNMATCHED |
Action | When no handler matches the email |
use App\Enums\InboundEmailHook;
use App\Support\Facades\Hook;
// Log incoming emails before processing
Hook::addAction(InboundEmailHook::BEFORE_PROCESS, function ($email) {
Log::info("Processing email from: {$email->from_email}");
});
// Notify after successful processing
Hook::addAction(InboundEmailHook::AFTER_PROCESS, function ($email, $handler, $result) {
// $handler - the handler that processed the email
// $result - InboundEmailHandlerResult with success status
Notification::send($admins, new EmailProcessedNotification($email));
});
// Handle unmatched emails - create new tickets
Hook::addAction(InboundEmailHook::UNMATCHED, function ($email) {
Ticket::create([
'title' => $email->subject ?? 'Email inquiry',
'description' => $email->getBodyContent(),
'customer_email' => $email->from_email,
'source' => 'email',
]);
});
// Alert on processing failures
Hook::addAction(InboundEmailHook::PROCESS_FAILED, function ($email, $errorMessage) {
Log::error("Inbound email failed: {$errorMessage}", [
'email_id' => $email->id,
'from' => $email->from_email,
]);
});
Module Hooks
App\Enums\Hooks\ModuleActionHook and App\Enums\Hooks\ModuleFilterHook
| Hook | Type | Description |
|---|---|---|
MODULE_ACTIVATED |
Action | When module is activated |
MODULE_DEACTIVATED |
Action | When module is deactivated |
MODULE_INSTALLED |
Action | When module is installed |
MODULE_UNINSTALLED |
Action | When module is uninstalled |
MODULE_CONFIG |
Filter | Filter module configuration |
Authentication Hooks
App\Enums\Hooks\AuthActionHook and App\Enums\Hooks\AuthFilterHook
| Hook | Type | Description |
|---|---|---|
USER_LOGGED_IN |
Action | After successful login |
USER_LOGGED_OUT |
Action | After logout |
USER_PASSWORD_RESET |
Action | After password reset |
LOGIN_CREDENTIALS |
Filter | Filter login credentials |
LOGIN_RESPONSE |
Filter | Filter login response |
Dashboard Hooks
App\Enums\Hooks\DashboardFilterHook
| Hook | Description |
|---|---|
DASHBOARD_WIDGETS |
Add dashboard widgets |
DASHBOARD_STATS |
Filter dashboard statistics |
DASHBOARD_QUICK_ACTIONS |
Add quick actions |
use App\Enums\Hooks\DashboardFilterHook;
// Add custom widget
Hook::addFilter(DashboardFilterHook::DASHBOARD_WIDGETS, function ($widgets) {
$widgets[] = view('yourmodule::widgets.stats')->render();
return $widgets;
});
Creating Custom Module Hooks
Define Hook Enums
Create your own hook enums for extensibility:
<?php
declare(strict_types=1);
namespace Modules\YourModule\Enums\Hooks;
enum YourModuleActionHook: string
{
case ORDER_CREATED = 'yourmodule.action.order_created';
case ORDER_COMPLETED = 'yourmodule.action.order_completed';
case ORDER_CANCELLED = 'yourmodule.action.order_cancelled';
}
enum YourModuleFilterHook: string
{
case ORDER_TOTAL = 'yourmodule.filter.order_total';
case ORDER_ITEMS = 'yourmodule.filter.order_items';
case CHECKOUT_FIELDS = 'yourmodule.filter.checkout_fields';
}
Fire Hooks in Your Code
use App\Support\Facades\Hook;
use Modules\YourModule\Enums\Hooks\YourModuleActionHook;
use Modules\YourModule\Enums\Hooks\YourModuleFilterHook;
class OrderService
{
public function createOrder(array $data): Order
{
// Filter order data
$data = Hook::applyFilters(YourModuleFilterHook::ORDER_ITEMS, $data);
$order = Order::create($data);
// Fire action
Hook::doAction(YourModuleActionHook::ORDER_CREATED, $order);
return $order;
}
public function calculateTotal(Order $order): float
{
$total = $order->items->sum('subtotal');
// Allow filtering total
return Hook::applyFilters(YourModuleFilterHook::ORDER_TOTAL, $total, $order);
}
}
Best Practices
1. Use Enum Hooks
Always prefer enums over string hooks for type safety:
// Good - Type safe
Hook::addAction(UserActionHook::USER_CREATED_AFTER, $callback);
// Avoid - Prone to typos
Hook::addAction('action.user.created_after', $callback);
2. Register in Service Provider
public function boot(): void
{
$this->app->booted(function () {
$this->registerHooks();
});
}
protected function registerHooks(): void
{
Hook::addFilter(AdminFilterHook::ADMIN_MENU_GROUPS_BEFORE_SORTING, [$this, 'addMenu']);
Hook::addFilter(PermissionFilterHook::PERMISSION_GROUPS, [$this, 'addPermissions']);
}
3. Handle Errors Gracefully
Hook::addAction(UserActionHook::USER_CREATED_AFTER, function ($user) {
try {
$this->sendWelcomeEmail($user);
} catch (\Exception $e) {
Log::error("Welcome email failed: " . $e->getMessage());
// Don't re-throw to prevent breaking the chain
}
});
4. Use Appropriate Priorities
| Priority | Use Case |
|---|---|
| 1-9 | Critical, must run first |
| 10-19 | Early processing |
| 20 | Default priority |
| 21-30 | Standard modifications |
| 31+ | Late processing, cleanup |
5. Queue Heavy Operations
Hook::addAction(PostActionHook::POST_PUBLISHED_AFTER, function ($post) {
// Queue instead of running inline
NotifySubscribersJob::dispatch($post);
});
Testing Hooks
use App\Support\Facades\Hook;
use App\Enums\Hooks\UserActionHook;
public function test_user_created_hook_fires(): void
{
$hookFired = false;
Hook::addAction(UserActionHook::USER_CREATED_AFTER, function ($user) use (&$hookFired) {
$hookFired = true;
});
User::factory()->create();
$this->assertTrue($hookFired);
}
public function test_filter_modifies_content(): void
{
Hook::addFilter(PostFilterHook::POST_CONTENT, function ($content) {
return strtoupper($content);
});
$result = Hook::applyFilters(PostFilterHook::POST_CONTENT, 'hello');
$this->assertEquals('HELLO', $result);
}
API Reference
Hook Facade Methods
use App\Support\Facades\Hook;
// Actions
Hook::doAction($tag, ...$args); // Fire action
Hook::addAction($tag, $callback, $priority, $args); // Register action
Hook::removeAction($tag, $callback, $priority); // Remove action
// Filters
Hook::applyFilters($tag, $value, ...$args); // Apply filters
Hook::addFilter($tag, $callback, $priority, $args); // Register filter
Hook::removeFilter($tag, $callback, $priority); // Remove filter
Helper Functions
// Actions
ld_do_action($hookName, ...$args);
ld_add_action($hookName, $callback, $priority = 20, $args = 1);
// Filters
ld_apply_filters($hookName, $value, $args = null);
ld_add_filter($hookName, $callback, $priority = 20, $args = 1);
Next Steps
- Module Development - Build modules with hooks
- Admin Menu System - Add menus using hooks
- Settings System - Extend settings with hooks