# Automation & Funnel Filters These filter hooks let you customize automation funnels — trigger registration, block definitions, processing limits, delays, and sequence behavior. ## Funnel Registration ### `fluentcrm_funnel_triggers` Filter the array of all registered funnel trigger definitions. Use this to add custom automation triggers. **Parameters** - `$triggers` Array - Default `[]` **Usage:** ```php add_filter('fluentcrm_funnel_triggers', function($triggers) { $triggers['my_custom_trigger'] = [ 'category' => 'Custom', 'label' => __('My Custom Trigger', 'fluent-crm'), 'description' => 'Fires when a custom event occurs' ]; return $triggers; }); ``` ::: tip This runs anywhere the trigger catalogue is assembled — the funnel editor, the dashboard, the MCP context tools and the Pro data exporter. Register triggers unconditionally rather than gating on the current screen. ::: **Source:** `app/Http/Controllers/FunnelController.php`, `app/Http/Controllers/DashboardController.php`, `app/Modules/MCP/Tools/FunnelTools.php`, `app/Modules/MCP/Tools/ContextTools.php`, `fluentcampaign-pro/app/Hooks/Handlers/DataExporter.php` --- ### `fluentcrm_funnel_blocks` Filter all funnel step block definitions available in the funnel editor. **Parameters** - `$blocks` Array - Default `[]` - `$funnel` [Funnel Model](/database/models/funnel) **Usage:** ```php add_filter('fluentcrm_funnel_blocks', function($blocks, $funnel) { $blocks['my_action'] = [ 'category' => 'Custom', 'label' => __('My Custom Action', 'fluent-crm'), 'description' => 'Does something custom', 'type' => 'action' ]; return $blocks; }, 10, 2); ``` ::: warning `$funnel` is `null` when the MCP context tools build the block catalogue with no funnel in scope, and a plain `stdClass` cast rather than a Funnel model when the Pro data exporter calls it. Guard before reading properties off it. ::: **Source:** `app/Http/Controllers/FunnelController.php`, `app/Modules/MCP/Tools/ContextTools.php`, `fluentcampaign-pro/app/Hooks/Handlers/DataExporter.php` --- ### `fluentcrm_funnel_block_fields` Filter custom field definitions for funnel step blocks in the editor UI. **Parameters** - `$fields` Array - Default `[]` - `$funnel` [Funnel Model](/database/models/funnel) **Usage:** ```php add_filter('fluentcrm_funnel_block_fields', function($fields, $funnel) { $fields['my_action'] = [ 'title' => 'My Action Settings', 'fields' => [ 'message' => [ 'type' => 'text', 'label' => 'Message' ] ] ]; return $fields; }, 10, 2); ``` **Source:** `app/Http/Controllers/FunnelController.php`, `fluentcampaign-pro/app/Hooks/Handlers/DataExporter.php` --- ### `fluent_crm_funnel_context_smart_codes` Filter the smart codes available in the funnel email composer for a specific trigger context. **Parameters** - `$smartCodes` Array - Default `[]` - `$triggerName` String - The funnel trigger name - `$funnel` [Funnel Model](/database/models/funnel) **Usage:** ```php add_filter('fluent_crm_funnel_context_smart_codes', function($smartCodes, $triggerName, $funnel) { if ($triggerName === 'my_custom_trigger') { $smartCodes[] = [ 'key' => '{{trigger.order_id}}', 'title' => 'Order ID' ]; } return $smartCodes; }, 10, 3); ``` **Source:** `app/Http/Controllers/FunnelController.php` --- ### `fluent_crm/funnel_icons` Filter the funnel trigger category icons (SVG paths or Element Plus icon class strings). **Parameters** - `$icons` Array - Associative array of `slug => icon` **Usage:** ```php add_filter('fluent_crm/funnel_icons', function($icons) { $icons['my_category'] = '...'; return $icons; }); ``` **Source:** `app/Hooks/Handlers/AdminMenu.php` --- ### `fluent_crm/funnel_label_color` Filter the array of available label colors for funnel steps. **Parameters** - `$colors` Array - Color hex values **Usage:** ```php add_filter('fluent_crm/funnel_label_color', function($colors) { $colors[] = '#FF5733'; return $colors; }); ``` **Source:** `app/Services/Helper.php` --- ## Processing & Limits ### `fluent_crm/funnel_subscriber_statuses` Filter which funnel-subscriber statuses the processor picks up each cycle. Only rows on a `published` funnel of type `funnels` whose `next_execution_time` is due are considered — this filter narrows that set by status. **Parameters** - `$statuses` Array - Default `['active']` **Usage:** ```php add_filter('fluent_crm/funnel_subscriber_statuses', function($statuses) { $statuses[] = 'paused'; return $statuses; }); ``` **Source:** `app/Services/Funnel/FunnelProcessor.php` --- ### `fluent_crm/funnel_processor_batch_limit` Filter the maximum number of funnel subscribers processed in a single processor run. **Parameters** - `$limit` INT - Default `200`. Values below `1` are clamped to `1`. **Usage:** ```php add_filter('fluent_crm/funnel_processor_batch_limit', function($limit) { return 500; }); ``` **Source:** `app/Services/Funnel/FunnelProcessor.php` --- ### `fluent_crm/funnel_processor_max_processing_seconds` Filter the hard time limit (seconds) for the funnel processor per run. **Parameters** - `$seconds` INT - Default `55`. Values below `1` are clamped to `1`. **Usage:** ```php add_filter('fluent_crm/funnel_processor_max_processing_seconds', function($seconds) { return 30; }); ``` **Source:** `app/Services/Funnel/FunnelProcessor.php` --- ### `fluent_crm/funnel_seq_delay_in_seconds` Filter the computed delay (in seconds) for a funnel sequence step. This applies to wait/delay steps, custom field date-based delays, and more. **Parameters** - `$waitTimeSeconds` INT - Computed delay in seconds - `$settings` Array - Step settings - `$sequence` Object - Sequence data - `$funnelSubId` INT - Funnel subscriber ID; may be `0`/empty for a step evaluated outside a contact's run **Usage:** ```php add_filter('fluent_crm/funnel_seq_delay_in_seconds', function($waitTime, $settings, $sequence, $funnelSubId) { // Add an extra 1-hour buffer to all delays return $waitTime + 3600; }, 10, 4); ``` **Source:** `app/Services/Funnel/FunnelHelper.php` --- ## Trigger Gates & Sequence Hooks ### `fluentcrm_funnel_will_process_{$triggerName}` Dynamic filter to gate whether a funnel should be triggered for a specific event. Return `false` to prevent the funnel from firing. **Parameters** - `$willProcess` Boolean - Default `true` - `$funnel` [Funnel Model](/database/models/funnel) - `$subscriberData` Array - Contact data - `$originalArgs` Array - Original trigger arguments **Usage:** ```php add_filter('fluentcrm_funnel_will_process_user_registration', function($willProcess, $funnel, $subscriberData, $originalArgs) { // Only process for specific roles if ($subscriberData['role'] !== 'subscriber') { return false; } return $willProcess; }, 10, 4); ``` **Source:** Every trigger class that implements a `willProcess()` gate — `app/Services/Funnel/Triggers/`, `app/Services/ExternalIntegrations/FluentCart/Triggers/`, and the Pro integration triggers under `fluentcampaign-pro/app/Services/Integrations/` --- ### `fluentcrm_funnel_editor_details_{$triggerName}` Dynamic filter to enrich the [Funnel](/database/models/funnel) object before it is returned to the editor. Use this to inject extra properties or computed data. **Parameters** - `$funnel` [Funnel Model](/database/models/funnel) **Usage:** ```php add_filter('fluentcrm_funnel_editor_details_my_trigger', function($funnel) { $funnel->extra_options = ['option1', 'option2']; return $funnel; }); ``` **Source:** `app/Hooks/Handlers/FunnelHandler.php`, `app/Http/Controllers/FunnelController.php` --- ### `fluentcrm_funnel_sequence_saving_{$actionName}` Dynamic filter to transform or validate a funnel sequence step before it is saved. The `{$actionName}` is the step's action type slug. **Parameters** - `$sequence` Array - Sequence step data - `$funnel` [Funnel Model](/database/models/funnel) **Usage:** ```php add_filter('fluentcrm_funnel_sequence_saving_my_action', function($sequence, $funnel) { // Validate or transform the sequence settings $sequence['settings']['validated'] = true; return $sequence; }, 10, 2); ``` **Source:** `app/Services/Funnel/FunnelHelper.php`, `app/Http/Controllers/FunnelController.php` --- ### `fluent_crm/webhook_ssl_verify` Control whether SSL is verified for the **Send Test Webhook** request fired from the funnel editor. ::: warning This does not affect live webhook sends. The HTTP webhook automation action verifies SSL through Fluent Forms' `ff_webhook_ssl_verify` filter, which defaults to `false`. Filter that hook instead if you need to change verification for real automation traffic. ::: **Parameters** - `$verify` Boolean - Default `true` **Usage:** ```php add_filter('fluent_crm/webhook_ssl_verify', function($verify) { return false; // Skip verification when testing against a self-signed endpoint }); ``` **Source:** `app/Http/Controllers/FunnelController.php` --- ## Conditions & A/B Testing ### `fluentcrm_automation_condition_groups` Filter the available condition groups for automation rules. Fired by the Pro conditional block and by the abandoned-cart automation triggers, including the FluentCart abandoned-cart driver that ships in core. ::: tip This hook only registers the group in the UI. At run time, a group that is not one of the built-in ones is evaluated through [`fluentcrm_automation_conditions_assess_{$groupName}`](#fluentcrm-automation-conditions-assess-groupname) — implement that too, or your group always passes. ::: **Parameters** - `$groups` Array - condition group definitions - `$funnel` [Funnel Model](/database/models/funnel) **Usage:** ```php add_filter('fluentcrm_automation_condition_groups', function($groups, $funnel) { $groups[] = [ 'value' => 'my_custom_group', 'label' => 'My Custom Conditions' ]; return $groups; }, 10, 2); ``` **Source:** `fluentcampaign-pro/app/Services/Funnel/Conditions/FunnelCondition.php`, `fluentcampaign-pro/app/Modules/AbandonCart/Woo/AbandonCartAutomationTrigger.php`, `app/Modules/AbandonCart/Drivers/FluentCart/FluentCartAutomationTrigger.php` --- ### `fluentcrm_automation_custom_conditions` Filter custom condition options for automation rules. **Parameters** - `$conditions` Array - condition definitions - `$funnel` [Funnel Model](/database/models/funnel) **Usage:** ```php add_filter('fluentcrm_automation_custom_conditions', function($conditions, $funnel) { $conditions['has_membership'] = [ 'label' => 'Has Active Membership', 'type' => 'yes_no_check' ]; return $conditions; }, 10, 2); ``` **Source:** `fluentcampaign-pro/app/Services/Funnel/Conditions/FunnelCondition.php` --- ### `fluentcrm_automation_custom_condition_assert_{$propertyName}` Dynamic filter to evaluate a custom automation condition. Return `true` or `false` to pass or fail the condition. It is also consulted by the abandoned-cart runner when it re-evaluates conditions. ::: warning The default is `true`, so an unhandled property name passes the condition rather than failing it. When the abandoned-cart runner calls this filter, `$sequence` and `$funnelSubscriberId` are both `null` — guard for that before dereferencing them. ::: **Parameters** - `$result` Boolean - Default `true` - `$condition` Array - condition config - `$subscriber` [Subscriber Model](/database/models/subscriber) - `$sequence` FunnelSequence Model - `null` when called from the abandoned-cart runner - `$funnelSubscriberId` INT - funnel subscriber ID; `null` when called from the abandoned-cart runner **Usage:** ```php add_filter('fluentcrm_automation_custom_condition_assert_has_membership', function($result, $condition, $subscriber) { return user_has_membership($subscriber->user_id); }, 10, 3); ``` **Source:** `fluentcampaign-pro/app/Services/Funnel/Conditions/FunnelCondition.php`, `app/Modules/AbandonCart/AbandonCartRunner.php` --- ### `fluentcrm_automation_conditions_assess_{$groupName}` Dynamic filter that evaluates one **condition group** of an automation conditional split for a contact. Return `true` to pass the group, `false` to fail it. The dynamic portion, `$groupName`, is the `value` the group was registered under on [`fluentcrm_automation_condition_groups`](#fluentcrm-automation-condition-groups). The built-in groups — `subscriber`, `custom_fields`, `segment`, `activities`, `event_tracking` and `other` — are assessed internally and never reach this filter (single conditions inside `other` go through [`fluentcrm_automation_custom_condition_assert_{$propertyName}`](#fluentcrm-automation-custom-condition-assert-propertyname) instead, keyed by the condition's `data_key`). Everything else is dispatched here, which is how the Pro integrations (WooCommerce, EDD, LearnDash, LifterLMS, TutorLMS, PMPro, RCP, Wishlist Member, AffiliateWP) and the core FluentCart integration plug in their purchase/enrollment conditions. Within one condition set every group must pass (AND); multiple condition sets are OR-ed, and the contact goes down the "No" path of the split only when every set fails. ::: warning The default is `true`, so a group name nobody handles passes silently. And as with `fluentcrm_automation_custom_condition_assert_{$propertyName}`: when the abandoned-cart runner calls this filter, `$sequence` and `$funnelSubscriberId` are both `null` — guard for that before dereferencing them. Most implementations register with `10, 3` and ignore the last two arguments entirely. ::: **Parameters** - `$result` Boolean - Default `true` - `$group` Array - the conditions of this group, each carrying `data_key`, `operator` and `value` (plus `property`, `extra_value` and `data_value` where set) - `$subscriber` [Subscriber Model](/database/models/subscriber) - `$sequence` FunnelSequence Model - the conditional split step; `null` when called from the abandoned-cart runner - `$funnelSubscriberId` INT - funnel subscriber ID; `null` when called from the abandoned-cart runner **Usage:** ```php add_filter('fluentcrm_automation_conditions_assess_my_group', function($result, $group, $subscriber) { foreach ($group as $condition) { if (!my_plugin_condition_matches($condition, $subscriber)) { return false; } } return true; }, 10, 3); ``` **Source:** `fluentcampaign-pro/app/Services/Funnel/Conditions/FunnelCondition.php`, `app/Modules/AbandonCart/AbandonCartRunner.php` --- ### `fluent_crm/funnel_ab_test_is_b` Determines whether a contact falls into the B variant of an automation A/B test. The unfiltered value is a weighted coin flip using the step's `path_a` / `path_b` split percentages (both default `50`). ::: warning The third argument changed — breaking FluentCampaign Pro 3.1.10 and earlier passed `$sequence` **twice**, so the contact was unreachable and per-contact bucketing was impossible. The duplicate has been dropped: the third argument is now the subscriber, and the funnel-subscriber id was added as a fourth. A callback that read the third argument as a sequence must be updated. ::: **Parameters** - `$isB` Boolean - whether this contact gets variant B - `$sequence` FunnelSequence Model - the A/B test step; read `$sequence->settings` for the split percentages - `$subscriber` [Subscriber Model](/database/models/subscriber) - the contact being bucketed - `$funnelSubscriberId` INT - the funnel subscriber row id **Usage:** ```php add_filter('fluent_crm/funnel_ab_test_is_b', function($isB, $sequence, $subscriber) { // Stable bucketing: the same contact always lands in the same variant return (crc32($subscriber->email) % 100) >= (int) ($sequence->settings['path_a'] ?? 50); }, 10, 3); ``` **Source:** `fluentcampaign-pro/app/Services/Funnel/Conditions/FunnelABTesting.php` --- ### `fluent_crm/event_tracking_condition_groups` Filter condition groups available for event tracking automation triggers. **Parameters** - `$groups` Array - condition groups **Usage:** ```php add_filter('fluent_crm/event_tracking_condition_groups', function($groups) { $groups[] = [ 'value' => 'event_custom', 'label' => 'Custom Event Conditions' ]; return $groups; }); ``` **Source:** `fluentcampaign-pro/app/Services/Funnel/Triggers/TrackingEventRecordedTrigger.php` --- ### `fluent_crm/http_webhook_body` Filter the request body sent to external webhooks in HTTP webhook automation actions. Smart codes in the configured body have already been parsed for the contact when this runs. ::: tip An empty body short-circuits the step before this filter — the step is marked `skipped` with a "No valid body data found" note. Use this filter to enrich a body, not to create one from nothing. On a `GET` step, the returned array becomes the query string rather than a request body. ::: **Parameters** - `$body` Array - request body, never empty - `$sequence` FunnelSequence Model - the webhook step - `$subscriber` [Subscriber Model](/database/models/subscriber) **Usage:** ```php add_filter('fluent_crm/http_webhook_body', function($body, $sequence, $subscriber) { $body['custom_field'] = $subscriber->custom_values['my_field'] ?? ''; return $body; }, 10, 3); ``` **Source:** `fluentcampaign-pro/app/Services/Funnel/Actions/HTTPSendDataAction.php`