Skip to content

WordPress Filters ​

Flowguard provides filter hooks that allow developers to modify data and behavior before it's processed.

Overview ​

Filters are WordPress hooks that let you modify data as it passes through Flowguard. Unlike actions (which execute code), filters transform data and return modified values.

Use filters to:

  • Modify flow data before execution
  • Customize default settings
  • Transform step configurations
  • Add custom validation
  • Integrate with other systems

Available Filters ​

flowguard_flow_data ​

Modifies flow data before it's sent for execution.

Hook Name: flowguard_flow_data

Parameters:

ParameterTypeDescription
$flow_dataarrayComplete flow data
$flow_idintThe flow post ID

Flow Data Structure:

php
$flow_data = [
    'id'       => 123,
    'title'    => 'Login Test Flow',
    'steps'    => [
        [
            'id'     => 'step_1',
            'type'   => 'navigate',
            'config' => [
                'url' => 'https://yoursite.com/login'
            ]
        ],
        // ... more steps
    ],
    'settings' => [
        'timeout'    => 30000,
        'retries'    => 0,
        'screenshot' => true,
    ],
    'siteUrl'  => 'https://yoursite.com',
];

Return Value: Modified $flow_data array

Example Usage:

php
/**
 * Add custom headers to all flows
 */
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    $flow_data['headers'] = [
        'X-Flow-ID' => $flow_id,
        'X-Site-ID' => get_current_blog_id(),
    ];
    
    return $flow_data;
}, 10, 2);

Use Cases:

1. Add Authentication Tokens ​

php
/**
 * Add auth token to flows that need it
 */
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    // Only for flows with "API" in the title
    if (strpos($flow_data['title'], 'API') !== false) {
        $flow_data['authToken'] = get_option('my_api_token');
    }
    
    return $flow_data;
}, 10, 2);

2. Modify Timeouts Dynamically ​

php
/**
 * Increase timeout for slow pages
 */
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    foreach ($flow_data['steps'] as &$step) {
        if ($step['type'] === 'navigate') {
            // Double timeout for navigation steps
            if (!isset($step['timeout'])) {
                $step['timeout'] = $flow_data['settings']['timeout'] * 2;
            }
        }
    }
    
    return $flow_data;
}, 10, 2);

3. Add Custom Step Data ​

php
/**
 * Add metadata to steps
 */
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    foreach ($flow_data['steps'] as &$step) {
        $step['metadata'] = [
            'flow_id'   => $flow_id,
            'timestamp' => current_time('c'),
            'user_id'   => get_current_user_id(),
        ];
    }
    
    return $flow_data;
}, 10, 2);

4. Replace URLs for Staging ​

php
/**
 * Replace production URLs with staging URLs
 */
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    $is_staging = defined('WP_ENVIRONMENT_TYPE') && WP_ENVIRONMENT_TYPE === 'staging';
    
    if ($is_staging) {
        foreach ($flow_data['steps'] as &$step) {
            if ($step['type'] === 'navigate' && isset($step['config']['url'])) {
                $step['config']['url'] = str_replace(
                    'https://production.com',
                    'https://staging.com',
                    $step['config']['url']
                );
            }
        }
    }
    
    return $flow_data;
}, 10, 2);

5. Add Performance Monitoring ​

php
/**
 * Add performance markers
 */
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    $flow_data['performance'] = [
        'enabled'     => true,
        'track_steps' => true,
        'report_url'  => 'https://monitor.example.com/api/report',
    ];
    
    return $flow_data;
}, 10, 2);

6. Inject Test Data ​

php
/**
 * Add test user credentials dynamically
 */
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    // Find fill steps for username/password
    foreach ($flow_data['steps'] as &$step) {
        if ($step['type'] === 'fill') {
            // Replace placeholder with actual test credentials
            if (isset($step['config']['text'])) {
                $step['config']['text'] = str_replace(
                    '{{TEST_USER}}',
                    get_option('flowguard_test_username'),
                    $step['config']['text']
                );
                
                $step['config']['text'] = str_replace(
                    '{{TEST_PASS}}',
                    get_option('flowguard_test_password'),
                    $step['config']['text']
                );
            }
        }
    }
    
    return $flow_data;
}, 10, 2);

7. Add Conditional Logic ​

php
/**
 * Skip certain steps based on conditions
 */
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    // Skip login steps if already logged in
    $is_logged_in = is_user_logged_in();
    
    if ($is_logged_in) {
        $flow_data['steps'] = array_filter($flow_data['steps'], function($step) {
            return !isset($step['tags']) || !in_array('login', $step['tags']);
        });
        
        // Re-index array
        $flow_data['steps'] = array_values($flow_data['steps']);
    }
    
    return $flow_data;
}, 10, 2);

8. Add Custom Validation ​

php
/**
 * Validate flow data before execution
 */
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    // Ensure all navigate steps have valid URLs
    foreach ($flow_data['steps'] as $step) {
        if ($step['type'] === 'navigate') {
            $url = $step['config']['url'] ?? '';
            
            if (!filter_var($url, FILTER_VALIDATE_URL)) {
                // Log error
                error_log("Flowguard: Invalid URL in flow {$flow_id}: {$url}");
                
                // Fix it
                $step['config']['url'] = home_url();
            }
        }
    }
    
    return $flow_data;
}, 10, 2);

9. Add Environment Variables ​

php
/**
 * Inject environment-specific configuration
 */
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    $flow_data['environment'] = [
        'name'     => wp_get_environment_type(),
        'debug'    => WP_DEBUG,
        'multisite' => is_multisite(),
        'locale'   => get_locale(),
    ];
    
    return $flow_data;
}, 10, 2);

10. Modify Settings Based on Flow Type ​

php
/**
 * Adjust settings for different flow types
 */
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    // Critical flows get more retries
    if (strpos(strtolower($flow_data['title']), 'critical') !== false) {
        $flow_data['settings']['retries'] = 3;
        $flow_data['settings']['timeout'] = 60000;
    }
    
    // Quick smoke tests run fast
    if (strpos(strtolower($flow_data['title']), 'smoke') !== false) {
        $flow_data['settings']['timeout'] = 10000;
        $flow_data['settings']['screenshot'] = false;
    }
    
    return $flow_data;
}, 10, 2);

flowguard_test_mode_allow_host ​

Allows external HTTP requests to specific hosts during Test Mode. By default, Test Mode blocks all external requests. Use this filter to whitelist hosts that should still be allowed.

Hook Name: flowguard_test_mode_allow_host

Parameters:

ParameterTypeDescription
$allowboolWhether to allow the request (default: false)
$hoststringThe request hostname (e.g., api.example.com)
$urlstringThe full request URL

Return Value: true to allow the request, false to block it.

Example Usage:

php
/**
 * Allow requests to your custom API during test mode
 */
add_filter('flowguard_test_mode_allow_host', function($allow, $host, $url) {
    // Allow your internal API
    if ($host === 'internal-api.yourcompany.com') {
        return true;
    }

    // Allow a specific analytics service
    if (strpos($host, 'plausible.io') !== false) {
        return true;
    }

    return $allow;
}, 10, 3);

flowguard_api_url ​

Modifies the API URL used for flow execution. Useful for routing flow execution through a custom proxy or alternative server.

Hook Name: flowguard_api_url

Parameters:

ParameterTypeDescription
$urlstringThe API URL (default: https://api.flowguardwp.io or http://localhost:3000)

Return Value: Modified URL string.

Example Usage:

php
/**
 * Route flow execution through a custom proxy
 */
add_filter('flowguard_api_url', function($url) {
    if (wp_get_environment_type() === 'staging') {
        return 'https://staging-api.yourcompany.com';
    }

    return $url;
}, 10, 1);

Filter Priority ​

Filters accept priority and argument count parameters:

php
add_filter('flowguard_flow_data', 'your_function', $priority, $accepted_args);

Default priority: 10

Lower numbers = Earlier execution Higher numbers = Later execution

Example with priority:

php
// Run first (priority 5) - Set defaults
add_filter('flowguard_flow_data', 'set_flow_defaults', 5, 2);

// Run second (priority 10) - Modify URLs
add_filter('flowguard_flow_data', 'replace_urls', 10, 2);

// Run last (priority 20) - Final validation
add_filter('flowguard_flow_data', 'validate_flow_data', 20, 2);

Removing Filters ​

To remove a previously added filter:

php
remove_filter('flowguard_flow_data', 'your_function', $priority);

Example:

php
// Add filter
add_filter('flowguard_flow_data', 'modify_data', 10, 2);

// Remove filter later
remove_filter('flowguard_flow_data', 'modify_data', 10);

Best Practices ​

1. Always Return the Data ​

Filters must return the modified data:

php
// ✅ Good - Returns modified data
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    $flow_data['custom'] = 'value';
    return $flow_data;
}, 10, 2);

// ❌ Bad - Doesn't return anything
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    $flow_data['custom'] = 'value';
    // Missing return statement!
}, 10, 2);

2. Preserve Data Structure ​

Don't break the expected data structure:

php
// ✅ Good - Adds new fields, keeps structure
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    $flow_data['custom_field'] = 'value';
    return $flow_data;
}, 10, 2);

// ❌ Bad - Replaces entire array
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    return ['completely' => 'different'];
}, 10, 2);

3. Check Existence Before Modifying ​

Verify data exists before accessing it:

php
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    // Check if steps array exists
    if (isset($flow_data['steps']) && is_array($flow_data['steps'])) {
        foreach ($flow_data['steps'] as &$step) {
            // Modify steps safely
        }
    }
    
    return $flow_data;
}, 10, 2);

4. Use Type Checking ​

Ensure data types are correct:

php
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    // Ensure timeout is an integer
    if (isset($flow_data['settings']['timeout'])) {
        $flow_data['settings']['timeout'] = absint($flow_data['settings']['timeout']);
    }
    
    return $flow_data;
}, 10, 2);

5. Handle Errors Gracefully ​

Don't let filters break execution:

php
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    try {
        // Your modifications
        $flow_data = apply_custom_logic($flow_data);
    } catch (Exception $e) {
        error_log('Flowguard filter error: ' . $e->getMessage());
        // Return original data on error
    }
    
    return $flow_data;
}, 10, 2);

6. Document Your Filters ​

Comment complex filter logic:

php
/**
 * Inject environment-specific URLs into flow navigation steps
 *
 * Replaces placeholder URLs like {{BASE_URL}} with the actual
 * WordPress site URL based on the current environment.
 *
 * @param array $flow_data Complete flow data
 * @param int   $flow_id   Flow post ID
 * @return array Modified flow data
 */
add_filter('flowguard_flow_data', function($flow_data, $flow_id) {
    // Implementation
    return $flow_data;
}, 10, 2);

7. Use Appropriate Priority ​

Order filters logically based on dependencies:

php
// Priority 5: Set base configuration
add_filter('flowguard_flow_data', 'set_defaults', 5, 2);

// Priority 10: Apply modifications
add_filter('flowguard_flow_data', 'apply_customizations', 10, 2);

// Priority 15: Final adjustments
add_filter('flowguard_flow_data', 'finalize_data', 15, 2);

Complete Example: Dynamic Flow Configuration ​

Here's a complete example that implements dynamic flow configuration:

php
<?php
/**
 * Flowguard Dynamic Configuration
 */

class Flowguard_Config {
    
    private $config;
    
    public function __construct() {
        // Load configuration
        $this->config = $this->load_config();
        
        // Add filter
        add_filter('flowguard_flow_data', [$this, 'modify_flow_data'], 10, 2);
    }
    
    /**
     * Load configuration from options
     */
    private function load_config() {
        return [
            'environments' => [
                'production' => [
                    'base_url' => 'https://production.com',
                    'timeout'  => 30000,
                ],
                'staging' => [
                    'base_url' => 'https://staging.com',
                    'timeout'  => 60000,
                ],
            ],
            'test_users' => [
                'admin' => [
                    'username' => 'test_admin',
                    'password' => 'test_pass_123',
                ],
                'customer' => [
                    'username' => 'test_customer',
                    'password' => 'test_pass_456',
                ],
            ],
        ];
    }
    
    /**
     * Modify flow data based on configuration
     */
    public function modify_flow_data($flow_data, $flow_id) {
        // 1. Replace environment placeholders
        $flow_data = $this->replace_placeholders($flow_data);
        
        // 2. Inject test credentials
        $flow_data = $this->inject_credentials($flow_data);
        
        // 3. Adjust timeouts
        $flow_data = $this->adjust_timeouts($flow_data);
        
        // 4. Add tracking
        $flow_data = $this->add_tracking($flow_data, $flow_id);
        
        // 5. Validate
        $flow_data = $this->validate($flow_data);
        
        return $flow_data;
    }
    
    /**
     * Replace environment placeholders
     */
    private function replace_placeholders($flow_data) {
        $environment = wp_get_environment_type();
        $base_url = $this->config['environments'][$environment]['base_url'] ?? home_url();
        
        foreach ($flow_data['steps'] as &$step) {
            if ($step['type'] === 'navigate' && isset($step['config']['url'])) {
                $step['config']['url'] = str_replace(
                    '{{BASE_URL}}',
                    $base_url,
                    $step['config']['url']
                );
            }
        }
        
        return $flow_data;
    }
    
    /**
     * Inject test user credentials
     */
    private function inject_credentials($flow_data) {
        // Detect which user type based on flow title
        $user_type = 'customer'; // default
        
        if (stripos($flow_data['title'], 'admin') !== false) {
            $user_type = 'admin';
        }
        
        $credentials = $this->config['test_users'][$user_type] ?? null;
        
        if (!$credentials) {
            return $flow_data;
        }
        
        foreach ($flow_data['steps'] as &$step) {
            if ($step['type'] === 'fill' && isset($step['config']['text'])) {
                $text = $step['config']['text'];
                
                if (strpos($text, '{{USERNAME}}') !== false) {
                    $step['config']['text'] = $credentials['username'];
                }
                
                if (strpos($text, '{{PASSWORD}}') !== false) {
                    $step['config']['text'] = $credentials['password'];
                }
            }
        }
        
        return $flow_data;
    }
    
    /**
     * Adjust timeouts based on environment
     */
    private function adjust_timeouts($flow_data) {
        $environment = wp_get_environment_type();
        $timeout = $this->config['environments'][$environment]['timeout'] ?? 30000;
        
        $flow_data['settings']['timeout'] = $timeout;
        
        return $flow_data;
    }
    
    /**
     * Add tracking information
     */
    private function add_tracking($flow_data, $flow_id) {
        $flow_data['tracking'] = [
            'flow_id'     => $flow_id,
            'environment' => wp_get_environment_type(),
            'timestamp'   => current_time('c'),
            'user_id'     => get_current_user_id(),
            'site_id'     => get_current_blog_id(),
        ];
        
        return $flow_data;
    }
    
    /**
     * Validate flow data
     */
    private function validate($flow_data) {
        // Ensure all URLs are absolute
        foreach ($flow_data['steps'] as &$step) {
            if ($step['type'] === 'navigate') {
                $url = $step['config']['url'] ?? '';
                
                if ($url && !filter_var($url, FILTER_VALIDATE_URL)) {
                    error_log("Flowguard: Invalid URL detected: {$url}");
                    $step['config']['url'] = home_url();
                }
            }
        }
        
        // Ensure timeout is reasonable
        $timeout = $flow_data['settings']['timeout'] ?? 30000;
        
        if ($timeout < 1000 || $timeout > 300000) {
            error_log('Flowguard: Timeout out of range, using default');
            $flow_data['settings']['timeout'] = 30000;
        }
        
        return $flow_data;
    }
}

// Initialize
new Flowguard_Config();

Future Filters ​

Additional filters planned for future versions:

  • flowguard_step_config - Modify individual step configuration
  • flowguard_flow_results - Transform results before saving
  • flowguard_settings_defaults - Change default settings
  • flowguard_validation_rules - Add custom validation
  • flowguard_timeout_value - Dynamic timeout calculation

Support ​

For questions about filters:

  1. Review WordPress Plugin API documentation
  2. Check the Flowguard source code
  3. Contact support for assistance