Loops
#for
for renders its body once for each item of an array.
<ul>{% for tag in product.tags %}<li>{{ tag }}</li>{% endfor %}</ul>{"data": {"product": {"tags": ["new", "sale"]}}, "allow": ["product"]}<ul><li>new</li><li>sale</li></ul>The collection is a single value: a variable path or a range. It cannot take filters; assign a filtered list to a variable first.
{% assign sorted = settings.names | sort %}{% for name in sorted %}{{ name }} {% endfor %}{"settings": {"names": ["Grace", "Ada"]}}Ada Grace #An empty collection: else
An else inside a loop renders when there is nothing to loop over.
{% for item in settings.items %}{{ item }}{% else %}Your basket is empty.{% endfor %}{"settings": {"items": []}}Your basket is empty.#What can be looped over
| Value | Iterations |
|---|---|
| Array | each item, in order |
Range (a..b) | each integer |
| Map | [key, value] pairs, sorted by key; read item[0] and item[1] |
nil, missing | none (renders else) |
| String, number, boolean | none (renders else) |
{% for pair in settings.sizes %}{{ pair[0] }}={{ pair[1] }} {% endfor %}{"settings": {"sizes": {"m": 10, "l": 4, "s": 0}}}l=4 m=10 s=0 #limit, offset, reversed
Modifiers come after the collection, in any order: offset skips items, limit caps how many remain, and reversed reverses the selection.
{% for n in (1..10) offset: 2 limit: 3 %}{{ n }}{% endfor %} {% for n in (1..10) limit: 3 reversed %}{{ n }}{% endfor %}345 321offset is applied first, then limit, then reversed. A negative offset is treated as zero; a negative limit means no limit. Both accept a variable or a filter expression: limit: settings.count | plus: 1.
#Ranges
A range loops over integers. Each end is a number or a variable.
{% for i in (1..settings.stars) %}★{% endfor %}{% for i in (settings.stars..4) %}☆{% endfor %}{"settings": {"stars": 3}}★★★☆☆Ranges are limited in size like any other value; see limits.
#forloop
Inside a loop, forloop describes the current iteration.
| Property | Value |
|---|---|
forloop.index | position, starting at 1 |
forloop.index0 | position, starting at 0 |
forloop.rindex | positions remaining, ending at 1 |
forloop.rindex0 | positions remaining, ending at 0 |
forloop.first | true on the first iteration |
forloop.last | true on the last iteration |
forloop.length | number of iterations (after offset, limit) |
forloop.parentloop | the enclosing loop's forloop, or nil |
{% for t in settings.tags %}{{ t }}{% unless forloop.last %}, {% endunless %}{% endfor %} ({{ settings.tags.size }}){"settings": {"tags": ["red", "green", "blue"]}}red, green, blue (3)In a nested loop, forloop.parentloop reaches the outer loop:
{% for row in (1..2) %}{% for col in (1..3) %}{{ forloop.parentloop.index }}{{ forloop.index }} {% endfor %}{% endfor %}11 12 13 21 22 23 #break and continue
break stops the loop; continue skips to the next item. They act on the innermost loop. Using them outside a loop is an error.
{% for n in (1..10) %}{% if n == 3 %}{% continue %}{% endif %}{% if n > 5 %}{% break %}{% endif %}{{ n }}{% endfor %}1245#cycle
cycle prints the next of its values each time it runs, starting over after the last. Each cycle tag keeps its own position.
{% for n in (1..5) %}<tr class="{% cycle "odd", "even" %}">{% endfor %}<tr class="odd"><tr class="even"><tr class="odd"><tr class="even"><tr class="odd">#Loop variables
The loop variable exists only inside its loop. Variables you assign inside a loop remain after it; see Scope.
Next: Composition.