{foreach:values:text:valdelimiter:outputdelimiter}

Description

Iterates over a list of values, substituting each into a template fragment. It splits values by valdelimiter (default -), substitutes each non-empty value into text, and joins the results with outputdelimiter (default: nothing). Inside text the current value is _#1 — or its modern synonym _#loop (both are the value itself, not an index). Empty values are skipped.

JSON mode: when valdelimiter is the literal word json, values is read as JSON instead of being split by a character. A JSON array iterates into _#1; a JSON object names the variable after its key (a color key gives _#color); nested arrays produce the cartesian product with positional aliases _#loop0, _#loop1, …

Per-item conditions (gotcha): a nested if/ifeq that depends on the current value must be wrapped in deferred-eval braces and reference the value as _##1 (double hash). Deferred-eval braces postpone evaluation until each iteration; without them the inner expression runs once, before the loop, so every row gets the same answer — e.g. you get NO|NO|NO instead of NO|YES|NO. See the two per-item condition examples below for the exact syntax.

Parameters

values required

The list of items foreach walks through. By default items are separated by a dash, so a-b-c is three items. Change the separator with the valdelimiter parameter (3rd), or set valdelimiter to json to pass a JSON array or object instead. Each item is exposed to the text template as _#1 (or its synonym _#loop). See the Examples below.

Allowed values Any string (the list of items).
text required

The template expanded once for each item. Reference the current value with _#1 or its synonym _#loop. For JSON-object input each key becomes a named placeholder (_#color, etc.); for multilevel JSON arrays use positional _#loop0, _#loop1, and so on. For a per-item condition, wrap it in deferred-eval braces and use _##1 (see the per-item-condition example below).

Allowed values Any string; may contain AA expressions and placeholders.
valdelimiter optional default -

The character (or string) separating items in the values parameter. Set it to a different character to split on that instead, or to the literal word json to parse values as a JSON array or object. See the Examples below.

Allowed values "-" (default) the value separator | "json" parse values as a JSON array/object | or any other single character
outputdelimiter optional default (empty string)

A string placed between each expansion of the text template, for example a comma-space for a list, a pipe with spaces, a space, or a newline. The delimiter goes only between items - there is no trailing separator after the last one. See the Examples below.

Allowed values Any string, e.g. comma-space, " | ", a space, or a newline.

Examples

{foreach:a-b-c:item _#1 }
Expecteditem a item b item c
Actualitem a item b item c
The simplest form: repeat a fragment for each value. The default value delimiter is the dash "-".
{foreach:Apple-Pear-Plum:[_#1]:-:}
Expected[Apple][Pear][Plum]
Actual[Apple][Pear][Plum]
Wrap each item in markup or brackets; with no output delimiter the pieces sit directly next to each other.
{foreach:red|green|blue:_#1:|:, }
Expectedred, green, blue
Actualred, green, blue
Split the input on a custom character ("|") and join the output with ", ".
{foreach:one-two-three:_#loop:-:, }
Expectedone, two, three
Actualone, two, three
_#loop is the modern synonym of _#1 - both are the current value (not its index). Use either.
{foreach:a--b-:_#1:-:|}
Expecteda|b
Actuala|b
Blank items between delimiters ("a--b-") are dropped, so you get a|b, not a||b|.
{foreach:["red","green","blue"]:_#1:json:, }
Expectedred, green, blue
Actualred, green, blue
Pass a JSON array and use the literal word "json" as the value delimiter.
{foreach:{"color":["red","green"]}:_#color:json:, }
Expectedred, green
Actualred, green
A JSON object names the variable after its key: {"color":["red","green"]} means you use _#color.
{foreach:[["A","B"],["1","2"]]:_#loop0=_#loop1:json:, }
ExpectedA=1, A=2, B=1, B=2
ActualA=1, A=2, B=1, B=2
Nested JSON arrays combine as a cartesian product; address each level with _#loop0, _#loop1, and so on.
{foreach:{sequence:num:2020:2022:1:-}:rok _#1:-:, }
Expectedrok 2020, rok 2021, rok 2022
Actualrok 2020, rok 2021, rok 2022
Feed another expression into foreach. Give {sequence:} a "-" delimiter so foreach can split it.
{foreach:a-b-c:{({ifeq:_##1:b:YES:NO})}:-:|}
ExpectedNO|YES|NO
ActualNO|YES|NO
Per-item condition. GOTCHA: {foreach:a-b-c:{ifeq:_#1:b:YES:NO}:-:|} wrongly gives NO|NO|NO (the ifeq runs once, before the loop). Fix = wrap in {(...)} AND use _##1, as shown - then NO|YES|NO.
{foreach:en-cz-de:{({ifeq:_##1:en:English:cz:Czech:de:German:Unknown})}:-:, }
ExpectedEnglish, Czech, German
ActualEnglish, Czech, German
Real-world value mapping with the same {(...)} + _##1 pattern: turn language codes into names.
{foreach:{ids:SLICE_ID::publish_date:-}:{({item:_##1:_#HEADLINE})}:-:, }
Expected(each item's headline, comma-joined - needs your slice; illustrative)
The #1 real-world use: get item IDs from a slice with {ids:...}, then load each with {item:_##1:...} (or {_:SliceName:_##1:...}) to render its fields. Deferred eval {(...)} + _##1 loads each ID in turn. Replace SLICE_ID and _#HEADLINE with your slice id and field alias.