All docs / Developer Guide

Custom Merge Fields

Add custom dynamic values to InfusedWoo automation recipe action fields.

Custom Merge Fields

Merge fields are dynamic placeholders (e.g., {{WPUser:first_name}}) that resolve to real values when a recipe runs. You can add custom merge fields in three ways, from simplest to most powerful.

Method 1: Filter Hook (Simplest — No Class Needed)

Use the built-in FilterHook merge group. Just register a WordPress filter:

/**
 * Users can now use {{FilterHook:my_order_count}} in any recipe action field.
 */
add_filter('my_order_count', function($value, $trigger) {
    if (!empty($trigger->user_email)) {
        $user = get_user_by('email', $trigger->user_email);
        if ($user) {
            return (string) wc_get_customer_order_count($user->ID);
        }
    }
    return '0';
}, 10, 2);

How users access it:

  1. In the merge field picker, select the “Custom Filter Hook (Developers Only)” category
  2. Type my_order_count in the text field
  3. Click Insert

The merge field {{FilterHook:my_order_count}} will resolve to the customer’s order count at runtime.

Note: This method requires users to manually type the filter name. For a better UX, use Method 2 or 3.

Method 2: Intercept via Filter (Any Group)

Use the infusedwoo_merge_value filter to handle merge fields for a custom group:

/**
 * Handle {{MyPlugin:setting_name}} merge fields.
 */
add_filter('infusedwoo_merge_value', function($value, $group, $key, $fallback) {
    if ($group !== 'MyPlugin') return $value;

    switch ($key) {
        case 'site_name':
            return get_bloginfo('name');
        case 'membership_level':
            // Use global trigger context if available
            global $trig_main_class_iwar;
            // ... resolve value
            return $resolved_value;
        default:
            return $fallback;
    }
}, 10, 4);

How users access it: Users type {{MyPlugin:site_name}} directly into any merge-field-enabled text input.

Note: This method works at runtime but the group won’t appear in the merge field picker dropdown (users must type it manually). For full picker integration, use Method 3.

Method 3: Trigger-Specific Merge Fields (Full Integration)

If you’re creating a custom trigger, you can define merge fields that appear in the picker:

class IW_MyCustom_Trigger extends IW_Automation_Trigger {
    /**
     * Register handler: group key => [display name, method name]
     */
    public $merge_handlers = array(
        'MyData' => array('My Plugin Data', 'merge_handler_mydata')
    );

    /**
     * Define available fields for the admin picker.
     */
    function merge_fields() {
        return array('MyData' => array(
            'customer_score'  => 'Customer Score',
            'referral_code'   => 'Referral Code',
            'points_balance'  => 'Points Balance',
        ));
    }

    /**
     * Resolve the merge field value at runtime.
     */
    function merge_handler_mydata($key) {
        $email = $this->user_email;
        $user = get_user_by('email', $email);
        if (!$user) return '';

        switch ($key) {
            case 'customer_score':
                return get_user_meta($user->ID, 'customer_score', true);
            case 'referral_code':
                return get_user_meta($user->ID, 'referral_code', true);
            case 'points_balance':
                return get_user_meta($user->ID, 'points_balance', true);
        }
        return '';
    }

    // ... rest of trigger methods
}

How users access it:

  1. In the merge field picker, the “My Plugin Data” category appears in the dropdown
  2. Fields like “Customer Score” and “Referral Code” are listed with their merge tokens
  3. Click to insert {{MyData:customer_score}}

Merge Field Syntax

{{Group:Key}}               Basic usage
{{Group:Key|default}}       With fallback value (used if key resolves to empty)
{{Group:Key|modifier}}      With modifier (md5, sha1, to_curr)

Adding Custom Modifiers

Modifiers transform the resolved value (applied after the pipe):

add_filter('infusedwoo_merge_modifiers', function($modifiers) {
    $modifiers['uppercase'] = 'strtoupper';
    $modifiers['base64']    = 'base64_encode';
    $modifiers['urlencode'] = 'rawurlencode';
    return $modifiers;
});

Users can then use: {{WPUser:first_name|uppercase}} which resolves to JOHN.

Built-In Merge Field Groups

These groups are always available (your custom merge fields add to these):

GroupKey PrefixDescription
WPUser{{WPUser:...}}WordPress user profile fields
InfContact{{InfContact:...}}Keap contact fields
Woocommerce{{Woocommerce:...}}WooCommerce general data
WCOrder{{WCOrder:...}}Order data (order triggers only)
WCSubscription{{WCSubscription:...}}Subscription data
WPUserMeta{{WPUserMeta:any_key}}Any WP user meta (free entry)
WCOrderMeta{{WCOrderMeta:any_key}}Any order meta (free entry)
Utility{{Utility:...}}Dates, timestamps, random strings
FilterHook{{FilterHook:any_filter}}Custom WordPress filters
GET{{GET:param_name}}URL query parameters

Complete Plugin Example

Here’s a full mu-plugin that adds custom merge fields via filter hook:

<?php
/**
 * Plugin Name: My Store Merge Fields
 * Description: Adds custom merge fields to InfusedWoo automation recipes
 */

// Method 1: Simple filter hooks
add_filter('total_orders', function($value, $trigger) {
    $user = get_user_by('email', $trigger->user_email);
    return $user ? (string) wc_get_customer_order_count($user->ID) : '0';
}, 10, 2);

add_filter('avg_order_value', function($value, $trigger) {
    $user = get_user_by('email', $trigger->user_email);
    if (!$user) return '0';
    $total = (float) wc_get_customer_total_spent($user->ID);
    $count = wc_get_customer_order_count($user->ID);
    return $count > 0 ? number_format($total / $count, 2) : '0';
}, 10, 2);

// Method 2: Custom group via filter
add_filter('infusedwoo_merge_value', function($value, $group, $key, $fallback) {
    if ($group !== 'Loyalty') return $value;

    global $trig_main_class_iwar;
    // Find current trigger context -- this is a simplified example
    // In practice, the trigger object is passed internally

    switch ($key) {
        case 'tier':
            return get_option('default_loyalty_tier', 'Bronze');
        case 'discount':
            return get_option('loyalty_discount', '10%');
    }
    return $fallback;
}, 10, 4);

Users can use:

  • {{FilterHook:total_orders}} —> “15”
  • {{FilterHook:avg_order_value}} —> “47.50”
  • {{Loyalty:tier}} —> “Gold”
  • {{Loyalty:discount}} —> “15%”