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:

  1. Action Hooks - Execute code at specific points (no return value)
  2. 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

/