Skip to content

Hooks & Events ​

Minimum Version Requirement

This feature requires WhatsMarkSaaS v2.0.0 or higher. Ensure your installation meets this requirement before proceeding.

Overview ​

WhatsMarkSaaS implements a WordPress-style hook system that allows modules to integrate with core functionality without modifying core code. This guide covers actions, filters, lifecycle hooks, and custom hook creation.

Hook System Architecture ​

The hook system provides two types of hooks:

Hook TypePurposeReturn Value
ActionsExecute code at specific pointsNone (void)
FiltersModify and return data through pipelineModified value

Registering Hooks ​

registerHooks() Method ​

Hooks must be registered in the main module class registerHooks() method:

php
<?php

namespace Modules\OrderTracker;

use Corbital\ModuleManager\Support\Module;

class OrderTracker extends Module
{
    /**
     * Register WordPress-style action and filter hooks.
     *
     * @return void
     */
    public function registerHooks(): void
    {
        // Register actions
        add_action('after_activate', [$this, 'onActivate']);
        add_action('order_created', [$this, 'handleOrderCreated']);

        // Register filters
        add_filter('dashboard_widgets', [$this, 'addDashboardWidget']);
        add_filter('order_status_options', [$this, 'addCustomStatus']);
    }

    /**
     * Handle module activation.
     */
    public function onActivate($data): void
    {
        \Log::info('OrderTracker module activated', $data);
    }

    /**
     * Handle order creation event.
     */
    public function handleOrderCreated($orderData): void
    {
        // Send notification, log event, trigger webhook, etc.
    }

    /**
     * Add custom dashboard widget.
     */
    public function addDashboardWidget($widgets): array
    {
        $widgets[] = [
            'name' => 'Order Summary',
            'component' => 'order-tracker::widgets.summary',
        ];

        return $widgets;
    }

    /**
     * Add custom order status.
     */
    public function addCustomStatus($statuses): array
    {
        $statuses['on_hold'] = 'On Hold';
        return $statuses;
    }
}

Actions ​

Actions execute code at specific points without returning a value.

Registering Actions ​

Signature:

php
add_action(string $tag, callable $callback, int $priority = 10, int $acceptedArgs = 1): void

Parameters:

ParameterTypeDescription
$tagstringHook name
$callbackcallableFunction to execute
$priorityintExecution order (default: 10, lower = earlier)
$acceptedArgsintNumber of arguments callback accepts

Example:

php
public function registerHooks(): void
{
    add_action('after_activate', function ($data) {
        \Log::info('Module activated', $data);
    });

    add_action('order_created', function ($order) {
        // Send notification
        $this->sendOrderNotification($order);
    }, 20);
}

Firing Actions ​

Signature:

php
do_action(string $tag, mixed ...$args): void

Example:

php
// In controller
public function store(Request $request)
{
    $order = Order::create($validated);

    // Fire action with order data
    do_action('order_created', $order);

    return redirect()->route('order-tracker.index');
}

Action with Multiple Parameters ​

php
// Register action
add_action('order_status_changed', function ($order, $oldStatus, $newStatus) {
    \Log::info("Order {$order->id} status changed from {$oldStatus} to {$newStatus}");
}, 10, 3);

// Fire action
do_action('order_status_changed', $order, $oldStatus, $newStatus);

Filters ​

Filters modify and return data through a pipeline.

Registering Filters ​

Signature:

php
add_filter(string $tag, callable $callback, int $priority = 10, int $acceptedArgs = 1): void

Example:

php
public function registerHooks(): void
{
    add_filter('dashboard_widgets', function ($widgets) {
        $widgets[] = [
            'name' => 'Order Statistics',
            'component' => 'order-tracker::widgets.stats',
        ];
        return $widgets;
    });

    add_filter('order_total', function ($total, $order) {
        // Apply discount
        if ($order->has_discount) {
            $total *= 0.9; // 10% discount
        }
        return $total;
    }, 10, 2);
}

Applying Filters ​

Signature:

php
apply_filters(string $tag, mixed $value, mixed ...$args): mixed

Example:

php
// Get widgets with filter applied
$widgets = apply_filters('dashboard_widgets', []);

// Calculate total with filters
$total = apply_filters('order_total', $order->total, $order);

Filter Pipeline ​

Multiple filters on the same hook execute in priority order:

php
// Priority 10 (executes first)
add_filter('order_total', function ($total) {
    return $total * 1.1; // Add 10% tax
}, 10);

// Priority 20 (executes second)
add_filter('order_total', function ($total) {
    return round($total, 2); // Round to 2 decimals
}, 20);

// Result: (100 * 1.1) rounded = 110.00
$total = apply_filters('order_total', 100);

Lifecycle Hooks ​

WhatsMarkSaaS provides built-in lifecycle hooks for module events:

Available Lifecycle Hooks ​

HookTrigger PointArguments
before_activateBefore module activation$moduleName
after_activateAfter module activation$moduleName
before_deactivateBefore module deactivation$moduleName
after_deactivateAfter module deactivation$moduleName
before_installBefore module installation$moduleName
after_installAfter module installation$moduleName
before_uninstallBefore module uninstallation$moduleName
after_uninstallAfter module uninstallation$moduleName

Using Lifecycle Hooks ​

php
public function registerHooks(): void
{
    // Log activation
    add_action('after_activate', function ($moduleName) {
        \Log::info("Module {$moduleName} activated");
    });

    // Cleanup on deactivation
    add_action('before_deactivate', function ($moduleName) {
        \Cache::forget("module:{$moduleName}:cache");
    });

    // Setup on installation
    add_action('after_install', function ($moduleName) {
        // Create default settings
        $this->createDefaultSettings();
    });

    // Cleanup on uninstallation
    add_action('before_uninstall', function ($moduleName) {
        // Remove module data
        $this->cleanupModuleData();
    });
}

Creating Custom Hooks ​

Define Custom Actions ​

In your module controller:

php
public function processOrder($orderId)
{
    $order = Order::findOrFail($orderId);

    // Allow modules to modify before processing
    do_action('before_order_process', $order);

    // Process order
    $this->process($order);

    // Allow modules to execute after processing
    do_action('after_order_process', $order);
}

Other modules can hook into these actions:

php
// In another module
add_action('before_order_process', function ($order) {
    // Validate inventory
    $this->checkInventory($order);
});

add_action('after_order_process', function ($order) {
    // Send confirmation email
    $this->sendConfirmation($order);
});

Define Custom Filters ​

In your module:

php
public function calculateShipping($order)
{
    $baseShipping = 10.00;

    // Allow modules to modify shipping cost
    $shipping = apply_filters('order_shipping_cost', $baseShipping, $order);

    return $shipping;
}

Other modules can modify shipping:

php
// In shipping module
add_filter('order_shipping_cost', function ($cost, $order) {
    if ($order->total > 100) {
        return 0; // Free shipping over $100
    }
    return $cost;
}, 10, 2);

Hook Priority System ​

Priority Levels ​

Priority determines hook execution order:

PriorityWhen to Use
1-9Critical, must execute first
10Default priority (standard hooks)
11-19After default hooks
20+Low priority, cleanup tasks

Priority Example ​

php
// Execute first (priority 5)
add_filter('order_total', function ($total) {
    return $total + 5; // Add shipping
}, 5);

// Execute second (priority 10, default)
add_filter('order_total', function ($total) {
    return $total * 1.1; // Add tax
});

// Execute third (priority 15)
add_filter('order_total', function ($total) {
    return round($total, 2); // Round result
}, 15);

// Result: ((100 + 5) * 1.1) rounded = 115.50
$total = apply_filters('order_total', 100);

Conditional Hook Registration ​

Register Hooks Based on Conditions ​

php
public function registerHooks(): void
{
    // Only register if another module is active
    if (module_enabled('Notifications')) {
        add_action('order_created', [$this, 'sendNotification']);
    }

    // Only register for specific tenants
    if (tenant_setting('enable_custom_status')) {
        add_filter('order_status_options', [$this, 'addCustomStatus']);
    }

    // Only register in production
    if (app()->environment('production')) {
        add_action('order_created', [$this, 'sendToAnalytics']);
    }
}

Hook Documentation ​

Documenting Custom Hooks ​

Document all custom hooks your module provides:

php
/**
 * Fires after an order is successfully created.
 *
 * @since 1.0.0
 *
 * @param \Modules\OrderTracker\Models\Order $order The created order object.
 */
do_action('order_created', $order);

/**
 * Filters the order status options.
 *
 * @since 1.0.0
 *
 * @param array $statuses Array of status options (key => label).
 * @return array Modified status options.
 */
$statuses = apply_filters('order_status_options', $statuses);

Hook Reference ​

Common WhatsMarkSaaS Hooks ​

Module Lifecycle:

  • before_activate
  • after_activate
  • before_deactivate
  • after_deactivate

Application:

  • app_module_headers - Add scripts/styles to header
  • app_module_footers - Add scripts to footer
  • dashboard_widgets - Filter dashboard widgets

Custom Module Hooks:

Create a HOOKS.md file in your module documenting all hooks:

markdown
# OrderTracker Hooks

## Actions {#actions-example}

### order_created
Fires after an order is created.

**Parameters:**
- `$order` (Order) - The created order object

**Example:**
```php
add_action('order_created', function($order) {
    \Log::info("Order {$order->id} created");
});

order_status_changed ​

Fires when an order status changes.

Parameters:

  • $order (Order) - The order object
  • $oldStatus (string) - Previous status
  • $newStatus (string) - New status

Filters ​

order_total ​

Filters the order total amount.

Parameters:

  • $total (float) - The order total
  • $order (Order) - The order object

Returns: (float) Modified total


## Best Practices

### Hook Naming Conventions

1. **Use descriptive names** - `order_created` not `oc`
2. **Use underscores** - `order_status_changed` not `orderStatusChanged`
3. **Prefix module hooks** - `ordertracker_order_created`
4. **Be consistent** - Follow existing naming patterns

### Performance Considerations

1. **Avoid heavy operations** - Keep hook callbacks lightweight
2. **Use priority wisely** - Don't force early execution without reason
3. **Cache results** - Cache expensive filter results
4. **Limit hook count** - Don't create unnecessary hooks

### Error Handling

```php
add_action('order_created', function ($order) {
    try {
        $this->sendNotification($order);
    } catch (\Exception $e) {
        \Log::error('Failed to send order notification', [
            'order_id' => $order->id,
            'error' => $e->getMessage(),
        ]);
    }
});

Troubleshooting ​

Hooks not firing ​

Solutions:

  1. Verify registerHooks() is called
  2. Check hook tag spelling matches exactly
  3. Verify module is activated
  4. Check priority order

Filters not modifying data ​

Solutions:

  1. Ensure filter callback returns modified value
  2. Verify filter is registered before being applied
  3. Check priority order (lower priority executes first)

Next Steps ​


This guide is for WhatsMarkSaaS v2.0.0+ custom module development.

Β© 2024 - Corbital Technologies. All rights reserved.