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 Type | Purpose | Return Value |
|---|---|---|
| Actions | Execute code at specific points | None (void) |
| Filters | Modify and return data through pipeline | Modified value |
Registering Hooks β
registerHooks() Method β
Hooks must be registered in the main module class registerHooks() method:
<?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:
add_action(string $tag, callable $callback, int $priority = 10, int $acceptedArgs = 1): voidParameters:
| Parameter | Type | Description |
|---|---|---|
$tag | string | Hook name |
$callback | callable | Function to execute |
$priority | int | Execution order (default: 10, lower = earlier) |
$acceptedArgs | int | Number of arguments callback accepts |
Example:
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:
do_action(string $tag, mixed ...$args): voidExample:
// 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 β
// 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:
add_filter(string $tag, callable $callback, int $priority = 10, int $acceptedArgs = 1): voidExample:
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:
apply_filters(string $tag, mixed $value, mixed ...$args): mixedExample:
// 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:
// 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 β
| Hook | Trigger Point | Arguments |
|---|---|---|
before_activate | Before module activation | $moduleName |
after_activate | After module activation | $moduleName |
before_deactivate | Before module deactivation | $moduleName |
after_deactivate | After module deactivation | $moduleName |
before_install | Before module installation | $moduleName |
after_install | After module installation | $moduleName |
before_uninstall | Before module uninstallation | $moduleName |
after_uninstall | After module uninstallation | $moduleName |
Using Lifecycle Hooks β
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:
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:
// 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:
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:
// 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:
| Priority | When to Use |
|---|---|
1-9 | Critical, must execute first |
10 | Default priority (standard hooks) |
11-19 | After default hooks |
20+ | Low priority, cleanup tasks |
Priority Example β
// 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 β
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:
/**
* 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_activateafter_activatebefore_deactivateafter_deactivate
Application:
app_module_headers- Add scripts/styles to headerapp_module_footers- Add scripts to footerdashboard_widgets- Filter dashboard widgets
Custom Module Hooks:
Create a HOOKS.md file in your module documenting all hooks:
# 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:
- Verify
registerHooks()is called - Check hook tag spelling matches exactly
- Verify module is activated
- Check priority order
Filters not modifying data β
Solutions:
- Ensure filter callback returns modified value
- Verify filter is registered before being applied
- Check priority order (lower priority executes first)
Next Steps β
- Helper Functions - Use module utility functions
This guide is for WhatsMarkSaaS v2.0.0+ custom module development.