Docs

10. Hooks and Filters

This comprehensive reference guide covers all WordPress hooks (actions and filters) provided by Order Daemon for extending functionality. It serves as the primary resource for developers building custom integrations, extensions, and modifications to the Order Daemon automation framework.

Overview

Order Daemon provides a comprehensive hook system that allows developers to:

  • Extend the Rule Engine: Add custom triggers, conditions, and actions
  • Modify Processing Logic: Intercept and alter rule evaluation and execution
  • Integrate External Systems: Connect webhooks, APIs, and third-party services
  • Customize Admin Interface: Modify dashboards, forms, and user experience
  • Enhance Audit Capabilities: Add custom logging and monitoring
  • Implement Security Policies: Add authentication and authorization layers

All hooks follow WordPress conventions and integrate seamlessly with existing WordPress and WooCommerce functionality.

Hook Architecture

Hook Categorization

Order Daemon hooks are organized into functional categories:

  1. Registration Hooks: Component discovery and registration
  2. Processing Hooks: Rule evaluation and execution flow
  3. Data Hooks: Content filtering and transformation
  4. UI Hooks: Admin interface customization
  5. Integration Hooks: External system connectivity
  6. Performance Hooks: Optimization and monitoring
  7. Security Hooks: Authentication and authorization

Hook Naming Convention

All Order Daemon hooks follow the pattern: odcm_{category}_{action}

  • odcm_register_*: Component registration hooks
  • odcm_before_*: Pre-processing hooks
  • odcm_after_*: Post-processing hooks
  • odcm_*_config: Configuration hooks
  • odcm_enable_*: Feature toggle hooks

Hook Stability Guarantee

Hooks are classified by stability:

  • 🟢 Stable: Public API, backward compatibility guaranteed
  • 🟡 Experimental: May change in minor releases
  • 🔴 Internal: For core use only, no compatibility guarantee

Development Guidelines

Basic Principles

  1. Respect Hook Contracts: Always return expected data types
  2. Maintain Performance: Avoid expensive operations in frequently-called hooks
  3. Handle Errors Gracefully: Use try-catch blocks and log errors appropriately
  4. Follow WordPress Standards: Use WordPress coding standards and conventions
  5. Document Your Extensions: Provide clear documentation for custom hooks

Hook Priority Guidelines

// Use these priority ranges:
add_action('odcm_hook', 'callback', 5);   // Early execution (setup, validation)
add_action('odcm_hook', 'callback', 10);  // Default priority (most extensions)
add_action('odcm_hook', 'callback', 20);  // Late execution (cleanup, logging)

Error Handling Pattern

add_filter('odcm_some_filter', function($value) {
    try {
        // Your custom logic here
        return modify_value($value);
    } catch (Exception $e) {
        if (function_exists('odcm_log_event')) {
            odcm_log_event(
                'Custom extension error: ' . $e->getMessage(),
                ['error' => $e->getMessage()],
                null,
                'error',
                'custom_extension'
            );
        }
        return $value; // Return original value on error
    }
});

Component Registration Hooks

🟢 odcm_register_triggers

Purpose: Register custom trigger components
Type: Action
When: During plugin initialization

add_action('odcm_register_triggers', function($registry) {
    $registry->register_trigger(new CustomTrigger());
});

class CustomTrigger implements TriggerInterface {
    public function get_id(): string { return 'custom_event'; }
    public function get_label(): string { return 'Custom Event Trigger'; }
    public function get_capability(): string { return 'core'; }

    public function should_trigger($context, $settings): bool {
        // Implementation logic
        return true;
    }
}

🟢 odcm_register_conditions

Purpose: Register custom condition components
Type: Action
When: During plugin initialization

add_action('odcm_register_conditions', function($registry) {
    $registry->register_condition(new CustomCondition());
});

class CustomCondition implements ConditionInterface {
    public function get_id(): string { return 'custom_check'; }
    public function get_label(): string { return 'Custom Condition Check'; }

    public function evaluate(\WC_Order $order, $settings): bool {
        // Evaluation logic
        return $order->get_total() > 100;
    }
}

🟢 odcm_register_actions

Purpose: Register custom action components
Type: Action
When: During plugin initialization

add_action('odcm_register_actions', function($registry) {
    $registry->register_action(new CustomAction());
});

class CustomAction implements ActionInterface {
    public function get_id(): string { return 'custom_action'; }
    public function get_label(): string { return 'Custom Order Action'; }

    public function execute(\WC_Order $order, $settings) {
        // Action implementation
        $order->add_order_note('Custom action executed');
    }
}

🟢 odcm_register_gateway_adapters

Purpose: Register webhook gateway adapters
Type: Action
When: Event router initialization

add_action('odcm_register_gateway_adapters', function($router) {
    $router->register_adapter('my_gateway', new CustomGatewayAdapter());
});

class CustomGatewayAdapter extends AbstractGatewayAdapter {
    public function get_slug(): string { return 'my_gateway'; }
    public function process_payload(array $payload): array {
        return ['processed' => true];
    }
}

Rule Processing Hooks

🟢 odcm_before_rule_validation

Purpose: Modify rule data before validation
Type: Filter
Parameters: $rule_data, $rule_id, $post

add_filter('odcm_before_rule_validation', function($rule, $rule_id, $post) {
    // Add default values or modify structure
    if (empty($rule['metadata'])) {
        $rule['metadata'] = ['source' => 'api'];
    }
    return $rule;
}, 10, 3);

🟢 odcm_before_rule_save

Purpose: Sanitize rule data before saving
Type: Filter
Parameters: $sanitized_data, $rule_id, $post

add_filter('odcm_before_rule_save', function($rule, $rule_id, $post) {
    // Add custom sanitization
    if (isset($rule['custom_field'])) {
        $rule['custom_field'] = sanitize_text_field($rule['custom_field']);
    }
    return $rule;
}, 10, 3);

🟢 odcm_after_rule_save

Purpose: React to rule save completion
Type: Action
Parameters: $rule_data, $rule_id, $post

add_action('odcm_after_rule_save', function($data, $rule_id, $post) {
    // Trigger external integrations
    do_action('my_plugin_rule_updated', $rule_id, $data);

    // Clear caches
    wp_cache_delete("rule_cache_{$rule_id}", 'order_daemon');
}, 10, 3);

🟢 odcm_rule_builder_config

Purpose: Modify Rule Builder UI configuration
Type: Filter
Parameters: $config

add_filter('odcm_rule_builder_config', function($config) {
    $config['ui']['custom_panel'] = true;
    $config['validation']['strict_mode'] = false;
    return $config;
});

Webhook & Event Hooks

🟢 odcm_webhook_test_event_types

Purpose: Add custom webhook test event types
Type: Filter
Parameters: $event_types, $gateway

add_filter('odcm_webhook_test_event_types', function($types, $gateway) {
    if ($gateway === 'my_gateway') {
        $types['custom_event'] = 'My Custom Event';
    }
    return $types;
}, 10, 2);

🟢 odcm_webhook_test_payload

Purpose: Provide custom test payloads
Type: Filter
Parameters: $payload, $gateway, $event_type

add_filter('odcm_webhook_test_payload', function($payload, $gateway, $event) {
    if ($gateway === 'my_gateway' && $event === 'custom_event') {
        return [
            'event_id' => uniqid(),
            'timestamp' => time(),
            'data' => ['test' => true]
        ];
    }
    return $payload;
}, 10, 3);

🟢 odcm_universal_event_context

Purpose: Modify universal event context
Type: Filter
Parameters: $context, $event

add_filter('odcm_universal_event_context', function($context, $event) {
    // Add custom context data
    $context['custom_tracking_id'] = generate_tracking_id();
    return $context;
}, 10, 2);

Admin Interface Hooks

🟢 odcm_insight_dashboard_accordion_state

Purpose: Control dashboard accordion states
Type: Filter
Parameters: $state

add_filter('odcm_insight_dashboard_accordion_state', function($state) {
    $state['custom_section'] = 'open';
    return $state;
});

🟢 odcm_debug_source_labels

Purpose: Customize debug source labels
Type: Filter
Parameters: $labels

add_filter('odcm_debug_source_labels', function($labels) {
    $labels['my_plugin'] = 'My Plugin Integration';
    return $labels;
});

🟢 odcm_insight_dashboard_settings_sections

Purpose: Add custom settings sections
Type: Action

add_action('odcm_insight_dashboard_settings_sections', function() {
    echo '<div class="custom-settings-section">';
    echo '<h3>My Plugin Settings</h3>';
    // Render custom settings form
    echo '</div>';
});

Audit & Logging Hooks

🟢 odcm_log_event_data

Purpose: Modify audit log entry data
Type: Filter
Parameters: $log_data, $message, $extra, $order, $level, $source

add_filter('odcm_log_event_data', function($data, $message, $extra, $order, $level, $source) {
    // Add custom fields to audit entries
    $data['user_agent'] = $_SERVER['HTTP_USER_AGENT'] ?? '';
    $data['ip_address'] = $_SERVER['REMOTE_ADDR'] ?? '';
    return $data;
}, 10, 6);

🟢 odcm_audit_entry_display

Purpose: Customize audit entry display
Type: Filter
Parameters: $html, $entry

add_filter('odcm_audit_entry_display', function($html, $entry) {
    if ($entry['source'] === 'my_plugin') {
        $html = '<div class="custom-audit-entry">' . $html . '</div>';
    }
    return $html;
}, 10, 2);

Performance & Attribution Hooks

🟢 odcm_enable_context_cache

Purpose: Control context caching
Type: Filter
Parameters: $enabled

add_filter('odcm_enable_context_cache', function($enabled) {
    // Disable caching in development
    return !defined('WP_DEBUG') || !WP_DEBUG;
});

🟢 odcm_attribution_context

Purpose: Modify attribution context
Type: Filter
Parameters: $context

add_filter('odcm_attribution_context', function($context) {
    $context['custom_attribution'] = get_current_user_id();
    return $context;
});

🟢 odcm_enable_deep_attribution

Purpose: Control deep attribution tracking
Type: Filter
Parameters: $enabled

add_filter('odcm_enable_deep_attribution', function($enabled) {
    // Enable only for specific conditions
    return is_admin() && current_user_can('manage_options');
});

🟢 odcm_attribution_backtrace_limit

Purpose: Set backtrace depth limit
Type: Filter
Parameters: $limit

add_filter('odcm_attribution_backtrace_limit', function($limit) {
    return wp_is_development_mode() ? 50 : 20;
});

🟢 odcm_attribution_time_budget_ms

Purpose: Set attribution time budget
Type: Filter
Parameters: $milliseconds

add_filter('odcm_attribution_time_budget_ms', function($ms) {
    return wp_using_ext_object_cache() ? 50 : 25;
});

🟢 odcm_process_lifecycle_families

Purpose: Define process lifecycle families
Type: Filter
Parameters: $families

add_filter('odcm_process_lifecycle_families', function($families) {
    $families['custom_workflow'] = [
        'start' => 'custom_start',
        'steps' => ['custom_step_1', 'custom_step_2'],
        'end' => 'custom_complete'
    ];
    return $families;
});

Security & Entitlement Hooks

🟢 odcm_is_premium_user

Purpose: Override premium user detection
Type: Filter
Parameters: $is_premium

add_filter('odcm_is_premium_user', function($is_premium) {
    // Custom premium logic
    return has_valid_license() || is_development_site();
});

🟢 odcm_capability_check

Purpose: Custom capability validation
Type: Filter
Parameters: $has_capability, $capability, $user_id

add_filter('odcm_capability_check', function($has_cap, $capability, $user_id) {
    if ($capability === 'premium_feature') {
        return user_has_subscription($user_id);
    }
    return $has_cap;
}, 10, 3);

🟢 odcm_security_context

Purpose: Add security context data
Type: Filter
Parameters: $context

add_filter('odcm_security_context', function($context) {
    $context['session_token'] = wp_get_session_token();
    $context['login_time'] = get_user_meta(get_current_user_id(), 'last_login', true);
    return $context;
});

Integration Patterns

Plugin Integration Pattern

class MyPluginOrderDaemonIntegration {
    public function __construct() {
        // Register hooks during plugin initialization
        add_action('plugins_loaded', [$this, 'init'], 20);
    }

    public function init() {
        if (!class_exists('OrderDaemon\Plugin')) {
            return; // Order Daemon not available
        }

        $this->register_components();
        $this->register_webhooks();
        $this->customize_ui();
    }

    private function register_components() {
        add_action('odcm_register_triggers', [$this, 'register_triggers']);
        add_action('odcm_register_conditions', [$this, 'register_conditions']);
        add_action('odcm_register_actions', [$this, 'register_actions']);
    }

    private function register_webhooks() {
        add_action('odcm_register_gateway_adapters', [$this, 'register_gateway']);
        add_filter('odcm_webhook_test_event_types', [$this, 'add_test_events'], 10, 2);
    }

    private function customize_ui() {
        add_filter('odcm_rule_builder_config', [$this, 'customize_builder']);
        add_action('odcm_insight_dashboard_settings_sections', [$this, 'add_settings']);
    }
}

new MyPluginOrderDaemonIntegration();

Theme Integration Pattern

// In functions.php
function theme_order_daemon_customizations() {
    if (!function_exists('odcm_can_use')) {
        return; // Order Daemon not available
    }

    // Customize audit display for front-end
    add_filter('odcm_audit_entry_display', 'theme_customize_audit_display', 10, 2);

    // Add custom context for front-end orders
    add_filter('odcm_attribution_context', 'theme_add_frontend_context');
}
add_action('after_setup_theme', 'theme_order_daemon_customizations');

function theme_customize_audit_display($html, $entry) {
    if (is_admin()) {
        return $html; // Only modify front-end display
    }

    return '<div class="theme-audit-entry">' . $html . '</div>';
}

function theme_add_frontend_context($context) {
    if (!is_admin()) {
        $context['page_template'] = get_page_template_slug();
        $context['theme'] = get_stylesheet();
    }
    return $context;
}

Service Integration Pattern

class ExternalServiceIntegration {
    private $api_client;

    public function __construct($api_client) {
        $this->api_client = $api_client;
        $this->register_hooks();
    }

    private function register_hooks() {
        // React to rule executions
        add_action('odcm_after_rule_save', [$this, 'sync_rule_to_service'], 10, 3);

        // Add custom webhook gateway
        add_action('odcm_register_gateway_adapters', [$this, 'register_gateway']);

        // Enhance audit with service data
        add_filter('odcm_log_event_data', [$this, 'add_service_context'], 10, 6);
    }

    public function sync_rule_to_service($data, $rule_id, $post) {
        try {
            $this->api_client->sync_rule($rule_id, $data);
        } catch (Exception $e) {
            odcm_log_event(
                'Failed to sync rule to external service',
                ['error' => $e->getMessage(), 'rule_id' => $rule_id],
                null,
                'error',
                'external_sync'
            );
        }
    }

    public function register_gateway($router) {
        $router->register_adapter('external_service', new ExternalServiceAdapter());
    }

    public function add_service_context($data, $message, $extra, $order, $level, $source) {
        if ($source === 'external_service') {
            $data['service_version'] = $this->api_client->get_version();
        }
        return $data;
    }
}

Hook Development Best Practices

Performance Optimization

// Cache expensive operations
add_filter('odcm_rule_builder_config', function($config) {
    static $cached_config = null;

    if ($cached_config === null) {
        $cached_config = wp_cache_get('my_plugin_config', 'order_daemon');

        if (false === $cached_config) {
            $cached_config = expensive_config_generation();
            wp_cache_set('my_plugin_config', $cached_config, 'order_daemon', HOUR_IN_SECONDS);
        }
    }

    return array_merge($config, $cached_config);
});

Error Handling and Logging

add_action('odcm_after_rule_save', function($data, $rule_id, $post) {
    try {
        risky_external_operation($data);
    } catch (Exception $e) {
        // Log the error with full context
        odcm_log_event(
            'External operation failed',
            [
                'error' => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'rule_id' => $rule_id,
                'rule_data' => $data
            ],
            null,
            'error',
            'my_plugin'
        );

        // Don't let the error break order processing
        return;
    }
}, 10, 3);

Conditional Hook Registration

class ConditionalHookRegistration {
    public function __construct() {
        add_action('init', [$this, 'maybe_register_hooks']);
    }

    public function maybe_register_hooks() {
        // Only register hooks when needed
        if (!$this->should_register_hooks()) {
            return;
        }

        add_filter('odcm_rule_builder_config', [$this, 'modify_config']);
        add_action('odcm_after_rule_save', [$this, 'handle_rule_save'], 10, 3);
    }

    private function should_register_hooks(): bool {
        return (
            function_exists('odcm_can_use') &&
            is_plugin_active('required-dependency/plugin.php') &&
            get_option('my_plugin_integration_enabled', false)
        );
    }
}

Hook Priority Management

// Use descriptive priority constants
class HookPriorities {
    const EARLY_SETUP = 5;
    const DEFAULT_EXECUTION = 10;
    const LATE_CLEANUP = 20;
    const FINAL_PROCESSING = 50;
}

// Register with appropriate priorities
add_action('odcm_register_triggers', 'register_core_triggers', HookPriorities::EARLY_SETUP);
add_action('odcm_after_rule_save', 'process_rule_save', HookPriorities::DEFAULT_EXECUTION);
add_action('odcm_after_rule_save', 'cleanup_after_save', HookPriorities::LATE_CLEANUP);

Testing & Debugging

Hook Testing Framework

class HookTestFramework {
    private $fired_hooks = [];

    public function start_monitoring($hook_name) {
        $this->fired_hooks[$hook_name] = [];

        add_action($hook_name, function(...$args) use ($hook_name) {
            $this->fired_hooks[$hook_name][] = $args;
        }, 1); // Early priority to catch everything
    }

    public function get_hook_calls($hook_name) {
        return $this->fired_hooks[$hook_name] ?? [];
    }

    public function assert_hook_fired($hook_name, $times = null) {
        $calls = $this->get_hook_calls($hook_name);

        if ($times === null) {
            return !empty($calls);
        }

        return count($calls) === $times;
    }
}

// Usage in tests
function test_custom_trigger_registration() {
    $test = new HookTestFramework();
    $test->start_monitoring('odcm_register_triggers');

    // Trigger the hook
    do_action('odcm_register_triggers', new MockRegistry());

    // Verify it was called
    assert($test->assert_hook_fired('odcm_register_triggers', 1));
}

Debug Hook Information

// Debug helper for hook development
function debug_order_daemon_hooks() {
    if (!defined('WP_DEBUG') || !WP_DEBUG) {
        return;
    }

    $hooks = [
        'odcm_register_triggers',
        'odcm_register_conditions',
        'odcm_register_actions',
        'odcm_before_rule_save',
        'odcm_after_rule_save'
    ];

    foreach ($hooks as $hook) {
        add_action($hook, function(...$args) use ($hook) {
            error_log("Hook fired: {$hook} with " . count($args) . " arguments");
        }, 999); // Late priority to see final state
    }
}
add_action('init', 'debug_order_daemon_hooks');

Hook Performance Monitoring

class HookPerformanceMonitor {
    private $timings = [];

    public function monitor_hook($hook_name) {
        add_action($hook_name, [$this, 'start_timing'], 1);
        add_action($hook_name, [$this, 'end_timing'], 999);
    }

    public function start_timing() {
        $hook = current_action();
        $this->timings[$hook]['start'] = microtime(true);
    }

    public function end_timing() {
        $hook = current_action();
        $this->timings[$hook]['end'] = microtime(true);
        $duration = $this->timings[$hook]['end'] - $this->timings[$hook]['start'];

        if ($duration > 0.1) { // Log slow hooks
            error_log("Slow hook: {$hook} took {$duration}s");
        }
    }
}

Migration & Compatibility

Version Compatibility Checks

function ensure_order_daemon_version($min_version) {
    if (!class_exists('OrderDaemon\Plugin')) {
        return false;
    }

    $installed_version = OrderDaemon\Plugin::get_version();
    return version_compare($installed_version, $min_version, '>=');
}

// Use in hook registration
if (ensure_order_daemon_version('2.0.0')) {
    add_action('odcm_new_hook_introduced_in_v2', 'my_callback');
} else {
    add_action('odcm_legacy_hook', 'my_fallback_callback');
}

Deprecation Handling

// Handle deprecated hooks gracefully
function handle_deprecated_hook() {
    if (has_action('old_odcm_hook')) {
        _deprecated_hook(
            'old_odcm_hook',
            '2.0.0',
            'odcm_new_hook',
            'Use the new hook for better performance'
        );

        // Bridge old to new
        add_action('odcm_new_hook', function($new_args) {
            $legacy_args = convert_to_legacy_format($new_args);
            do_action('old_odcm_hook', $legacy_args);
        });
    }
}
add_action('init', 'handle_deprecated_hook');

Was this article helpful?

  • Loading...
Table of Contents
  • Loading...