View as Markdown:
Advanced Patterns
This guide covers advanced techniques for optimizing performance, debugging issues, implementing complex rule patterns, and integrating MilliRules deeply into your applications.
Early Execution#Copied!
Early execution runs rules before WordPress fully loads, enabling caching systems, redirects, and performance optimizations.
MU-Plugin Early Execution#Copied!
1/**
2 * Plugin Name: MilliRules Early Execution
3 * Description: Runs MilliRules before WordPress loads
4 */
5
6require_once WPMU_PLUGIN_DIR . '/millirules-vendor/autoload.php';
7
8use MilliRulesMilliRules;
9use MilliRulesRules;
10use MilliRulesContext;
11
12// Initialize with PHP package only (WordPress not loaded yet)
13MilliRules::init(['PHP']);
14
15// Register early execution rules
16Rules::create('early_cache_check', 'php')
17 ->when()
18 ->request_url('/api/*')
19 ->request_method('GET')
20 ->then()
21 ->custom('check_cache')
22 ->custom('early_exit_if_cached')
23 ->register();
24
25// Execute early rules
26$result = MilliRules::execute_rules(['PHP']);
Custom Cache Integration#Copied!
1Rules::register_action('check_cache', function($args, Context $context) {
2 $cache_key = 'page_' . md5($context->get('request.uri', '') ?? '');
3 $cached = get_transient($cache_key);
4
5 if ($cached !== false) {
6 // Send cached response
7 header('Content-Type: text/html; charset=UTF-8');
8 header('X-Cache: HIT');
9 echo $cached;
10 exit;
11 }
12});
13
14Rules::register_action('save_to_cache', function($args, Context $context) {
15 $cache_key = 'page_' . md5($context->get('request.uri', '') ?? '');
16 $duration = $args['duration'] ?? 3600;
17
18 ob_start(function($buffer) use ($cache_key, $duration) {
19 set_transient($cache_key, $buffer, $duration);
20 return $buffer;
21 });
22});
23
24Rules::create('api_caching')
25 ->when()
26 ->request_url('/api/*')
27 ->request_method('GET')
28 ->then()
29 ->custom('check_cache') // Check first
30 ->custom('save_to_cache', ['duration' => 3600]) // Save if not cached
31 ->register();
Performance Optimization#Copied!
Rule Ordering for Performance#Copied!
1// Place most restrictive/fastest conditions first
2Rules::create('optimized_rule')
3 ->order(10)
4 ->when()
5 // Fast checks first
6 ->request_method('POST') // Very fast
7 ->request_url('/api/specific-endpoint') // Fast
8 ->cookie('session_id') // Fast
9
10 // Slower checks last
11 ->custom('expensive_validation') // Slow
12 ->then()
13 ->custom('process_request')
14 ->register();
Lazy Loading#Copied!
1// Load rules only when needed
2add_action('init', function() {
3 MilliRules::init();
4
5 // Load admin rules only in admin
6 if (is_admin()) {
7 require_once __DIR__ . '/rules/admin-rules.php';
8 }
9
10 // Load frontend rules only on frontend
11 if (!is_admin()) {
12 require_once __DIR__ . '/rules/frontend-rules.php';
13 }
14
15 // Load API rules only for API requests
16 if (str_starts_with($_SERVER['REQUEST_URI'] ?? '', '/api/')) {
17 require_once __DIR__ . '/rules/api-rules.php';
18 }
19}, 1);
Debugging Strategies#Copied!
Debug Logging#Copied!
1// Enable comprehensive debugging
2define('MILLIRULES_DEBUG', true);
3
4Rules::register_action('debug_log', function($args, Context $context) {
5 if (!defined('MILLIRULES_DEBUG') || !MILLIRULES_DEBUG) {
6 return;
7 }
8
9 $message = $args['message'] ?? '';
10 $data = $args['data'] ?? [];
11
12 error_log('=== MilliRules Debug ===');
13 error_log('Message: ' . $message);
14 error_log('Data: ' . print_r($data, true));
15 error_log('======================');
16});
17
18// Add debug actions to rules
19Rules::create('debuggable_rule')
20 ->when()
21 ->request_url('/api/*')
22 ->then()
23 ->custom('debug_log', [
24 'message' => 'API request started',
25 'data' => ['url' => '{request.uri}']
26 ])
27 ->custom('process_api')
28 ->custom('debug_log', [
29 'message' => 'API request completed'
30 ])
31 ->register();
Execution Statistics#Copied!
1// Track execution statistics
2$result = MilliRules::execute_rules();
3
4error_log('=== Execution Statistics ===');
5error_log('Rules processed: ' . $result['rules_processed']);
6error_log('Rules skipped: ' . $result['rules_skipped']);
7error_log('Rules matched: ' . $result['rules_matched']);
8error_log('Actions executed: ' . $result['actions_executed']);
9error_log('===========================');
10
11// Performance tracking
12$start_time = microtime(true);
13$start_memory = memory_get_usage();
14
15$result = MilliRules::execute_rules();
16
17$execution_time = microtime(true) - $start_time;
18$memory_used = memory_get_usage() - $start_memory;
19
20error_log("Execution time: {$execution_time}s");
21error_log("Memory used: " . size_format($memory_used));
Debug Conditions#Copied!
1Rules::register_condition('debug_context', function($args, Context $context) {
2 error_log('=== Context Debug ===');
3 error_log('Full context: ' . print_r($context, true));
4 error_log('===================');
5 return true; // Always matches
6});
7
8Rules::create('debug_rule')
9 ->when()
10 ->custom('debug_context')
11 ->your_actual_conditions()
12 ->then()
13 ->your_actions()
14 ->register();
Complex Rule Patterns#Copied!
Conditional Rule Groups#Copied!
1// Environment-specific rules
2$environment = wp_get_environment_type();
3
4if ($environment === 'local') {
5 // Local development rules
6 Rules::create('local_debug')
7 ->when()->constant('WP_DEBUG', true, '=')
8 ->then()->custom('enable_verbose_logging')
9 ->register();
10
11 Rules::create('local_logging')
12 ->when()->request_url('*')
13 ->then()->custom('log_all_requests')
14 ->register();
15
16} elseif ($environment === 'staging') {
17 // Staging environment rules
18 Rules::create('staging_monitoring')
19 ->when()->request_url('*')
20 ->then()->custom('track_staging_metrics')
21 ->register();
22
23} elseif ($environment === 'production') {
24 // Production rules
25 Rules::create('prod_caching')
26 ->when()->request_url('/api/*')
27 ->then()->custom('enable_aggressive_cache')
28 ->register();
29
30 Rules::create('prod_security')
31 ->when()->request_method('POST')
32 ->then()->custom('enhanced_security_check')
33 ->register();
34}
Dynamic Rule Generation#Copied!
1// Generate rules from configuration
2$protected_endpoints = [
3 '/api/users' => ['GET', 'POST'],
4 '/api/posts' => ['GET', 'POST', 'PUT', 'DELETE'],
5 '/api/settings' => ['GET', 'PUT'],
6];
7
8foreach ($protected_endpoints as $endpoint => $methods) {
9 $rule_id = 'protect_' . sanitize_title($endpoint);
10
11 Rules::create($rule_id)
12 ->when()
13 ->request_url($endpoint)
14 ->request_method($methods, 'IN')
15 ->is_user_logged_in(false) // Not logged in
16 ->then()
17 ->custom('send_401_unauthorized')
18 ->register();
19}
Package Filtering#Copied!
Execute rules with specific packages only.
Selective Package Execution#Copied!
1// Execute only PHP rules (before WordPress loads)
2$php_result = MilliRules::execute_rules(['PHP']);
3
4// Execute only WordPress rules
5$wp_result = MilliRules::execute_rules(['WP']);
6
7// Execute with custom packages
8$custom_result = MilliRules::execute_rules(['PHP', 'Custom']);
Context-Aware Package Selection#Copied!
1add_action('init', function() {
2 MilliRules::init();
3
4 // Determine which packages to use
5 $packages = ['PHP'];
6
7 if (function_exists('add_action')) {
8 $packages[] = 'WP';
9 }
10
11 if (class_exists('WooCommerce')) {
12 $packages[] = 'WooCommerce';
13 }
14
15 // Execute with selected packages
16 $result = MilliRules::execute_rules($packages);
17}, 5);
Context Manipulation#Copied!
Extending Context#Copied!
1// Add custom data to context before execution
2add_filter('millirules_context', function(Context $context) {
3 $context['custom'] = [
4 'api_key' => get_option('my_api_key'),
5 'feature_flags' => get_option('feature_flags', []),
6 'site_config' => get_site_config(),
7 ];
8
9 return $context;
10});
Context Transformation#Copied!
1// Transform context for specific rules
2Rules::register_action('with_transformed_context', function($args, Context $context) {
3 // Add computed values
4 $context['computed'] = [
5 'is_business_hours' => check_business_hours(),
6 'user_tier' => calculate_user_tier($context),
7 'request_complexity' => analyze_request($context),
8 ];
9
10 // Execute sub-action with transformed context
11 $callback = $args['callback'] ?? null;
12 if (is_callable($callback)) {
13 $callback($context);
14 }
15});
Error Handling#Copied!
Graceful Degradation#Copied!
1Rules::register_action('safe_api_call', function($args, Context $context) {
2 try {
3 $response = wp_remote_post($args['url'], [
4 'body' => json_encode($args['data']),
5 'headers' => ['Content-Type' => 'application/json'],
6 'timeout' => 10,
7 ]);
8
9 if (is_wp_error($response)) {
10 throw new Exception($response->get_error_message());
11 }
12
13 $status = wp_remote_retrieve_response_code($response);
14 if ($status >= 400) {
15 throw new Exception("API returned status {$status}");
16 }
17
18 // Success
19 return json_decode(wp_remote_retrieve_body($response), true);
20
21 } catch (Exception $e) {
22 error_log('API Error: ' . $e->getMessage());
23
24 // Fallback behavior
25 $fallback = $args['fallback'] ?? null;
26 if (is_callable($fallback)) {
27 return $fallback($context);
28 }
29
30 return null;
31 }
32});
Error Notification#Copied!
1Rules::register_action('notify_on_error', function($args, Context $context) {
2 try {
3 // Risky operation
4 perform_critical_operation($config);
5
6 } catch (Exception $e) {
7 // Log error
8 error_log('Critical error: ' . $e->getMessage());
9
10 // Notify admin
11 wp_mail(
12 get_option('admin_email'),
13 'MilliRules Critical Error',
14 "Error: {$e->getMessage()}nnContext: " . print_r($context, true)
15 );
16
17 // Store error for admin dashboard
18 update_option('millirules_last_error', [
19 'message' => $e->getMessage(),
20 'time' => time(),
21 'context' => $context,
22 ]);
23 }
24});
Testing Strategies#Copied!
Unit Testing Rules#Copied!
1class MilliRulesTest extends WP_UnitTestCase {
2 public function setUp(): void {
3 parent::setUp();
4 MilliRules::init();
5 }
6
7 public function test_api_cache_rule() {
8 // Register test action
9 Rules::register_action('test_cache', function($args, Context $context) {
10 update_option('test_cache_called', true);
11 });
12
13 // Create rule
14 Rules::create('test_api_cache')
15 ->when()
16 ->request_url('/api/test')
17 ->request_method('GET')
18 ->then()
19 ->custom('test_cache')
20 ->register();
21
22 // Simulate request
23 $_SERVER['REQUEST_URI'] = '/api/test';
24 $_SERVER['REQUEST_METHOD'] = 'GET';
25
26 // Execute
27 $result = MilliRules::execute_rules();
28
29 // Assert
30 $this->assertEquals(1, $result['rules_matched']);
31 $this->assertTrue(get_option('test_cache_called'));
32 }
33}
Integration Testing#Copied!
1function test_complete_workflow() {
2 // Setup
3 MilliRules::init();
4
5 $executed_actions = [];
6
7 Rules::register_action('track_execution', function($args, Context $context) use (&$executed_actions) {
8 $executed_actions[] = $args['step'];
9 });
10
11 // Create multi-step rule
12 Rules::create('workflow_test')
13 ->when()->request_url('/test-workflow')
14 ->then()
15 ->custom('track_execution', ['step' => 'validate'])
16 ->custom('track_execution', ['step' => 'process'])
17 ->custom('track_execution', ['step' => 'complete'])
18 ->register();
19
20 // Execute
21 $_SERVER['REQUEST_URI'] = '/test-workflow';
22 MilliRules::execute_rules();
23
24 // Verify execution order
25 assert($executed_actions === ['validate', 'process', 'complete']);
26
27 echo "Workflow test passed!n";
28}
Best Practices Summary#Copied!
1. Performance#Copied!
- Order conditions from fastest to slowest
- Cache expensive operations
- Use early execution for caching/redirects
- Load rules only when needed
2. Debugging#Copied!
- Enable debug logging in development
- Track execution statistics
- Use debug conditions to inspect context
- Monitor memory and execution time
3. Maintainability#Copied!
- Use descriptive rule IDs
- Group related rules by feature
- Document complex logic
- Use consistent naming conventions
4. Error Handling#Copied!
- Always validate input
- Provide fallback behaviors
- Log errors appropriately
- Notify admins of critical issues
5. Testing#Copied!
- Write unit tests for custom conditions/actions
- Test complete rule workflows
- Test with different package combinations
- Simulate various environments
Next Steps#Copied!
- WordPress Integration Guide - WordPress-specific patterns
- API Reference - Complete method documentation
- Real-World Examples - Complete working examples
Ready to explore WordPress integration? Continue to WordPress Integration Guide for WordPress-specific techniques and patterns.
MilliRules Documentation