Conditions & Logic Reference
Flow Manager provides two families of step types for controlling execution:
- Conditions evaluate a test and route the flow to different outputs based on the result.
- Logic elements control how data moves through the flow — looping, batching, delaying, splitting, and merging branches.
All condition and logic step handles, field names, and output handles used here are sourced from craft-plugin v2.2.1.
Conditions
Condition steps evaluate a test against the current flow context and route execution to one of their named output handles. Every condition routes to a false (or equivalent negative) output on any runtime error — the flow never throws from inside a condition.
If / Else
Handle: if-else
The general-purpose single-condition branch. Evaluates a context field against an expected value using one of twelve operators and routes to true or false.
Fields:
| Field | Type | Description |
|---|---|---|
field | text | Dot-notation path to the context field (e.g. order.total). |
operator | select | One of equals, not_equals, greater_than, less_than, greater_or_equal, less_or_equal, contains, not_contains, is_empty, is_not_empty, starts_with, ends_with. |
value | text | The value to compare against. Twig tokens supported. Not required for is_empty / is_not_empty. |
Outputs: true, false
Example: Route VIP customers (group vip) to a premium action; all others continue to the standard email.
Compare Values
Handle: compare-values
Compares two Twig-rendered values using a numeric or string operator. When both rendered values are numeric, PHP float comparison is used; otherwise string comparison applies.
Fields:
| Field | Type | Description |
|---|---|---|
valueA | text | First value. Twig tokens supported. Required. |
operator | select | eq, neq, gt, gte, lt, lte |
valueB | text | Second value. Twig tokens supported. Required. |
Outputs: true, false
Example: Check whether {{ order.total }} is greater than a discount threshold stored in a context variable.
Filter
Handle: filter
Gate that evaluates multiple field rules with AND / OR logic. Routes to true when the ruleset passes, false otherwise. An empty rules list always passes.
Fields:
| Field | Type | Description |
|---|---|---|
logic | select | and (all rules must pass) or or (any rule can pass). Default: and. |
rules | table | Each row: field (dot-notation path), operator (equals, not_equals, greater_than, less_than, contains, is_empty, is_not_empty), value (Twig supported). |
Outputs: true, false
Example: Continue only when customer.group equals vip AND order.total is greater than 100.
Switch
Handle: switch
Routes to one of four numbered case outputs, or a default, based on an exact string match against a context field. The first matching case wins.
Fields:
| Field | Type | Description |
|---|---|---|
field | text | Dot-notation path to the context field (e.g. order.status). |
cases | table | Each row: output (case_1–case_4), value to match against (Twig supported). |
Outputs: case_1, case_2, case_3, case_4, default
Example: Route order statuses processing, shipped, completed, cancelled to separate notification actions; anything else falls to default.
Number Range
Handle: number-range
Evaluates whether a numeric context value falls within a configured range. The value is rendered as a Twig expression (wrapped in {{ }}).
Fields:
| Field | Type | Description |
|---|---|---|
value | text | Context field path or Twig expression (e.g. order.total). |
min | number | Lower bound. |
max | number | Upper bound. |
inclusive | lightswitch | Include min/max values in the range. Default: true. |
Outputs: in_range, out_of_range
Example: Apply a mid-tier discount when order total is between 50 and 200.
String Contains
Handle: string-contains
Text matching with five operators. By default case-insensitive; enable case sensitivity per step.
Fields:
| Field | Type | Description |
|---|---|---|
input | text | The string to search in. Twig tokens supported. |
operator | select | contains, starts_with, ends_with, regex, equals |
searchValue | text | The value to search for. Twig tokens supported. |
caseSensitive | lightswitch | Default: false. Has no effect on regex — include flags in the pattern. |
Outputs: match, no_match
Note on regex: Supply a full PHP pattern with delimiters (e.g. /^SKU-\d+$/i). If no delimiter is detected, the value is wrapped in /…/. Twig is applied to the input before the pattern is tested.
Example: Route orders where the SKU matches /^BUNDLE-/i to a bundle-processing action.
Date Compare
Handle: date-compare
Compares two dates using before, after, same_day, or between. All date values are rendered via Twig before parsing; now is a valid literal.
Fields:
| Field | Type | Description |
|---|---|---|
dateA | text | First date. Twig tokens supported (e.g. {{ order.dateCreated }}). |
operator | select | before, after, same_day, between |
dateB | text | Second date / lower bound for between. |
dateC | text | Upper bound date; required only when operator is between. |
Outputs: true, false
Example: Route to an expired-subscription branch when {{ subscription.expiresAt }} is before now.
List Contains
Handle: list-contains
Checks whether a rendered item value is present in a comma-separated list. Both the list and the item are Twig-rendered and trimmed before comparison (exact string match).
Fields:
| Field | Type | Description |
|---|---|---|
list | text | Comma-separated values. Twig tokens supported. |
item | text | The value to look for. Twig tokens supported. |
Outputs: found, not_found
Example: Check if {{ order.shippingCountry }} is in SK, CZ, HU, AT, PL.
Random Chance
Handle: random-chance
Routes a configurable percentage of executions to selected; the rest go to not_selected. Uses random_int(1, 100) — cryptographically random, not seedable.
Fields:
| Field | Type | Description |
|---|---|---|
percentage | number | 1–100. The probability (%) of routing to selected. Default: 50. |
Outputs: selected, not_selected
Example: Send 20% of post-purchase customers a new email template for an A/B test.
Time Window
Handle: time-window
Checks whether the current wall-clock time falls within a configured time range and optional day-of-week schedule.
Fields:
| Field | Type | Description |
|---|---|---|
startTime | text | Start of window in HH:MM 24-hour format (e.g. 09:00). |
endTime | text | End of window in HH:MM 24-hour format (e.g. 17:00). |
timezone | text | IANA timezone (e.g. UTC, Europe/Bratislava). Default: UTC. |
daysOfWeek | text | Comma-separated day numbers: 1=Monday … 7=Sunday. Leave empty for all days. Default: 1,2,3,4,5. |
Outputs: in_window, outside_window
Overnight windows: When startTime > endTime (e.g. 22:00–06:00) the step correctly identifies the overnight span.
Runtime errors (invalid timezone, unparseable time) route to outside_window.
Example: Only route to the SMS action when the current time is within Mon–Fri 09:00–17:00 Europe/Bratislava.
User In Group
Handle: user-in-group
Checks whether a Craft user belongs to a specific user group by handle. The user is looked up via User::find()->id($userId).
Fields:
| Field | Type | Description |
|---|---|---|
userId | text | The Craft user ID to check. Twig tokens supported. |
groupHandle | text | The user group handle (e.g. editors). |
Outputs: in_group, not_in_group
A missing user or empty userId / groupHandle routes to not_in_group.
Customer Order Count
Handle: customer-order-count
Compares a customer's total order count against a threshold using one of five operators. Order count is resolved via OrdersService::getOrderCountByCustomerId().
Fields:
| Field | Type | Description |
|---|---|---|
customerId | text | Customer ID. Twig tokens supported. |
operator | select | gt (>), gte (>=), lt (<), lte (<=), eq (==) |
threshold | number | Order count to compare against. Default: 1. |
Outputs: meets_threshold, below_threshold
Examples:
- Identify first-time buyers:
operatoreq,threshold1. - VIP routing:
operatorgte,threshold10.
Customer In Segment
Handle: customer-in-segment
Checks whether the customer in the flow context currently belongs to a given customer segment. Membership is resolved from live segment data, not cached — this reflects the segment's state at the moment the condition runs.
Fields:
| Field | Type | Description |
|---|---|---|
segmentHandle | text | The segment handle to check membership against. |
Outputs: in_segment, not_in_segment
A missing customer, missing segment, or unknown segmentHandle routes to not_in_segment.
Order Status Check
Handle: order-status-check
Checks whether an order's current status matches an expected value. Resolves the order from context first (avoids a DB query when the order context object matches the ID), then falls back to OrdersService::getOrderById().
Fields:
| Field | Type | Description |
|---|---|---|
orderId | text | The order ID to check. Twig tokens supported. |
expectedStatus | select | new, processing, shipped, completed, cancelled, refunded |
Outputs: matches, not_matches
Example: Only send a shipping notification when order status is shipped.
Has Field Value
Handle: has-field-value
Checks whether a rendered Twig expression produces a non-empty value. The expression is rendered and trimmed; an empty string routes to empty. The literal string "0" is treated as has_value.
Fields:
| Field | Type | Description |
|---|---|---|
variablePath | text | A Twig expression (e.g. {{ customer.email }}). |
Outputs: has_value, empty
Example: Skip the notification action when {{ order.shippingAddress }} is empty.
Entry Exists
Handle: entry-exists
Queries the Craft entries table and branches based on whether a matching entry is found. All filter values are Twig-rendered before the query is executed.
Fields:
| Field | Type | Description |
|---|---|---|
sectionHandle | text | Limit search to a section (e.g. blog). Leave empty for all sections. |
slug | text | Match by slug. Twig tokens supported. |
entryId | text | Match by ID. Twig tokens supported. |
title | text | Match by title. Twig tokens supported. |
At least one of slug, entryId, or title should be set to produce a useful query. All provided filters are applied together (AND).
Outputs: exists, not_found
Example: Skip content creation when an entry with the target slug already exists.
Logic Elements
Logic elements do not branch on a true/false test — they control the shape of execution: loops, delays, parallel branches, data transformation, and flow-control utilities.
For Each
Handle: for-each
Iterates over an array from the flow context. For each item, the connected item branch is executed with the current element exposed under the configured variable name. The empty output is used when the collection is absent or empty.
Fields:
| Field | Type | Default | Description |
|---|---|---|---|
collectionPath | text | — | Dot-notation path to a context array (e.g. order.items). |
itemVariable | text | currentItem | Variable name exposed to the item branch. |
maxIterations | number | 100 | Safety cap to prevent runaway loops. |
Outputs: item (per element), empty
Context variables set: _forEachItems, _forEachItemVariable, _forEachMaxIterations
Example: Loop through order.items and send an item-level restock alert for each.
Wait / Delay
Handle: wait-delay
Pauses flow execution for a specified duration and schedules resumption via the flow runner cron job. Returns NodeResult::paused() — the runner creates a scheduled action and picks it up when the delay expires.
Fields:
| Field | Type | Default | Description |
|---|---|---|---|
delayAmount | number | 1 | How long to wait. |
delayUnit | select | hours | minutes, hours, days, weeks |
Outputs: (none — execution pauses; resumes at the next connected node)
Example: Wait 24 hours after purchase before triggering a product review request.
Split
Handle: split
Forks execution into up to four parallel branches. Each branch receives the same context snapshot and runs independently.
Outputs: branch_1, branch_2, branch_3, branch_4
Example: After an order is placed, simultaneously send a confirmation email, notify the warehouse team, and create a CP notification.
Merge
Handle: merge
Joins multiple incoming parallel branches back into a single output. Can wait for all branches or proceed on the first arrival.
Fields:
| Field | Type | Description |
|---|---|---|
mode | select | all — wait for all branches; first — continue on first arrival. |
timeout | number | Seconds before releasing even if not all branches have arrived (used with all mode). |
Outputs: merged
Example: Recombine two Split branches before writing a summary CP notification.
A/B Test
Handle: ab-test
Routes executions into up to four variants (A/B/C/D) based on configurable weight percentages. Weight distribution is cumulative; uses random_int.
Fields:
| Field | Type | Description |
|---|---|---|
variants | table | Each row: variant label and integer weight. Weights are summed and used as the denominator. |
Outputs: a, b, c, d
Example: Split 70% of post-purchase customers to email template A, 30% to template B.
Batch
Handle: batch
Splits a collection into smaller sub-arrays and processes each chunk sequentially via the batch output. Signals done when all chunks have been processed.
Fields:
| Field | Type | Description |
|---|---|---|
collectionPath | text | Dot-notation path to the source array. |
batchSize | number | Number of items per chunk. |
Outputs: batch (per chunk), done
Example: Process 500 newsletter subscribers in batches of 50 to stay within mail provider rate limits.
Filter Collection
Handle: filter-collection
Splits a collection into filtered (items matching a Twig condition) and rejected (items that do not match).
Fields:
| Field | Type | Description |
|---|---|---|
sourceVariable | text | Context variable holding the source array. |
condition | text | Twig expression evaluated per item (item available as item). |
filteredVariable | text | Context variable name for the matching items. |
rejectedVariable | text | Context variable name for the non-matching items. |
Outputs: filtered, rejected
Example: Split order items into in-stock and out-of-stock groups before separate notification branches.
Map
Handle: map
Transforms each element of a collection by rendering a Twig template with the item exposed as a variable. Produces a new array of transformed values.
Fields:
| Field | Type | Description |
|---|---|---|
collectionPath | text | Dot-notation path to the source array. |
itemVariable | text | Variable name for the current item inside the template. Default: item. |
template | text | Twig template rendered for each item. |
outputVariable | text | Context variable name to store the mapped array. |
Outputs: mapped, empty
Example: Extract email addresses from a list of customer objects: {{ item.email }}.
Reduce
Handle: reduce
Aggregates a collection into a single value using a built-in operation or a custom Twig template.
Fields:
| Field | Type | Description |
|---|---|---|
collectionPath | text | Dot-notation path to the source array. |
operation | select | sum, count, min, max, concat, custom |
fieldPath | text | Sub-field within each item to operate on (for sum, min, max). |
separator | text | Separator for concat. Default: , . |
template | text | Twig accumulator template for custom (item exposed as item, accumulator as carry). |
outputVariable | text | Context variable name for the result. |
Outputs: reduced, empty
Example: Sum all item.price values to compute a cart total.
Deduplicate
Handle: deduplicate
Uses a cache-based check to ensure a unique key is only processed once within a configurable time window. Routes to new on first occurrence and duplicate on subsequent ones.
Fields:
| Field | Type | Description |
|---|---|---|
key | text | Twig expression rendered to produce the deduplication key (e.g. {{ order.id }}). |
ttl | number | Cache TTL in seconds. Default: 3600. |
Outputs: new, duplicate
Example: Prevent the same order ID from triggering a confirmation email twice within one hour.
Accumulator
Handle: accumulator
Buffers incoming executions using a cache counter until a threshold is reached, then releases. Routes to collecting while building up, and to threshold_reached when the count hits the target. The counter resets on threshold.
Fields:
| Field | Type | Description |
|---|---|---|
key | text | Twig expression for the accumulator key (scopes the counter). |
threshold | number | How many executions to collect before releasing. |
ttl | number | Cache TTL in seconds. Counter resets if TTL expires before threshold is reached. |
Outputs: collecting, threshold_reached
Example: Collect 10 abandoned cart events before sending a digest email to the operations team.
Rate Limit
Handle: rate-limit
Enforces a global execution ceiling across all invocations within a time window. Unlike Throttle (per key), Rate Limit is a shared counter for the entire step.
Fields:
| Field | Type | Description |
|---|---|---|
maxExecutions | number | Maximum allowed executions within the window. |
windowSeconds | number | Length of the rolling window in seconds. |
Outputs: allowed, limited
Example: Cap outbound API calls to a third-party service at 100 per hour regardless of how many orders trigger the flow.
Throttle
Handle: throttle
Per-key rate limiting. Each unique rendered key gets its own counter. Useful for per-customer or per-entity limits.
Fields:
| Field | Type | Description |
|---|---|---|
key | text | Twig expression rendered to produce the throttle key (e.g. {{ customer.id }}). |
maxExecutions | number | Allowed executions per window for a single key. |
windowSeconds | number | Rolling window in seconds. |
Outputs: allowed, throttled
Example: Allow each customer to receive at most one promotional email per 24-hour window.
Priority Queue
Handle: priority-queue
Evaluates a score expression and routes to high, medium, or low output based on configurable numeric thresholds.
Fields:
| Field | Type | Description |
|---|---|---|
scoreExpression | text | Twig expression rendering a numeric score. |
highThreshold | number | Score >= this value → high. |
mediumThreshold | number | Score >= this value (and below highThreshold) → medium. Below → low. |
Outputs: high, medium, low
Example: Score orders by total value and route high-value orders to expedited fulfilment.
Audience check
- Customer/storefront: Conditions and logic elements run server-side in the Craft queue. Customers do not interact with them directly; the results determine which emails, notifications, or CP actions they receive.
- Admin/Craft CP: Steps are configured in Flow Manager → flow editor (yStore → Marketing → Flow Manager). Each step type is available in the step picker under "Conditions" or "Logic" categories. Runtime results are visible in Flow Health.
- Developer/integrator: Custom conditions and logic elements can be registered by implementing
ExecutableConditionInterfaceorExecutableLogicInterfaceand extendingAbstractConditionDefinition/AbstractLogicDefinition. Register via theRegisterFlowStepsevent on theFlowService. Source namespace:yui\craft\flow\conditionsandyui\craft\flow\logic.