Skip to main content

For Loops

You already know that you can use the for tag (also called a for loop) to iterate (aka, loop) over arrays and objects. A common use case for a for loop is listing each item a customer purchased in a transactional email. In this section, we’ll take a deeper dive into for loops so you can use them with greater precision to get better results with your emails.

Looping over objects and arrays

Arrays contain an ordered list of string or number values or an ordered list of objects (a collection of key/value pairs). Great news—you’ve already learned how to loop over an array of objects! Here’s the example you practiced on in the Intermediate Tags lesson:

{% for senior_pets in products.new_products.senior_pets %}
  - {{ senior_pets.title }} x {{ senior_pets.price }}
{% endfor %}
- bowl elevator x 15.00
- stair steps x 25.00
- carry sling x 30.00
- senior vitamins x 10.00

Products.new_products is an array, and each product—senior_pets—is an object that contains key/value pairs. In this case, senior_pets is just the name we’ve assigned the object; the first item in the for loop syntax just defines the context, so something like “for <x> in <y>” just defines the objects in the array as “<x>”.

For loops can also iterate over an array of string or number values. Let’s look at a loop over an array of strings:

{% assign items = "leash, bowl, collar" | split: ", " %}
{% for item in items %}{{ item }}{% endfor %}

The for loop iterates through the array and outputs a list of its values. The second, third, and fourth lines of code above are the for loop tag.

A little detour to look at that first line of code, just so you know what you’re looking at:

  • We’ve used the assign tag to store a value in our code. In this case, the data type of the value type is a string.
  • But we know that the values need to be in a specific order so the for loop can iterate over them. So we’ve used the split filter to convert that string into an array—an ordered list of info. 
    • What about that comma and space between the quotation marks? That’s the delimiter the split filter will use to recognize and the individual bits of info in the string—when it sees the comma and space between the items in “leash, bowl, collar” it knows to split the string at those points

Looping over hashes

We talked about the concept of hashing as part of encryption schemes earlier in this module. The term “hash” can also refer to a data structure in Ruby (Liquid’s parent language) that is essentially—although not exactly—the same as a JavaScript object. You can use Liquid to iterate over hashes, and the syntax is slightly different. Here’s a primer on how to loop over hashes.

For loop helper tags

The for tag has several “helper” tags: else, break and continue. They give you more control over loops and more options for using them.

The else tag defines an alternative output if you loop over an empty array—instead of a blank line. Here’s how it looks:

{% assign items = empty %}
{% for item in items %}  {{ item }}{% else %}This array is empty.{% endfor %}
This array is empty.

Since the loop cannot run over the empty array, it displays the alternative output. You might use else to avoid extra lines in your emails when keys are unexpectedly empty.    

While available in certain liquid versions, the break and continue tags are not currently available in

Break and continue allow you to stop looping or skip a value. To use them, nest an if/else or elsif/else tag within your for tag. Let’s start by looking at break:

{% assign items = "leash, bowl, collar" | split: ", " %}
{% for item in items %}
    {% if item == "bowl" %}
       {% break %}    
    {% else %}{{ item }}   
    {% endif %}
{% endfor %}

Let’s walk through what the Liquid code is doing:

Line 1: Assign creates a new key and stores its value. This value is an array.

Line 2: Loop over these keys, starting at the first one in the array.

Line 3: This opens the condition tag, which checks the item value against the condition.

Line 4: If the condition in Line 3 is met, stop (break). The loop is over.

Line 5: If the condition in Line 3 is not met, display the key’s value.

Line 6: Close the elsif/if tag.

Line 7: Close the for tag.

When the code runs, it checks the first value in the array to see if it equals “bowl”. If it doesn’t, the code loops over that value and displays it. Then the code runs again, starting at the second value in the array. It will keep looping until it finds “bowl” or reaches the end of the array. In this example, the code can only loop once, because “bowl” is the second value in the array.

Now let’s try the continue tag. It skips over a value in an array that meets a condition. We’ll use the same example as before: 

{% assign items = "leash, bowl, collar" | split: ", " %}
{% for item in items %}
    {% if item == "bowl" %}    
       {% continue%}   
    {% else %}  
       {{ item }}  
    {% endif %}
{% endfor %}

Here, when the next value in the array equals “bowl”, the code skips that value and starts again with the next value in the array’s sequence. It loops until it reaches the last value in the array.

The break and continue tags have a lot of handy uses when personalizing emails. Say a customer has bought a bowl, and you want to recommend related products without repeating the product they already bought—the continue tag makes it happen!  

For loop parameters: limit, offset, and reversed

There are three parameters that you can use with for loops: reversed, limit, and offset. Just as we discussed when describing localization tools, parameter in this context means an extra instruction that customizes the for loop to your needs.  

Reversed begins the loop at the last item in the array’s sequence, rather than the first.

{% assign items = "leash, bowl, collar" | split: ", " %}
{% for item in items reversed %}{{ item }}{% endfor %}

Notice that reversed is not separated with a pipe character–these parameters are not filters

Limit allows you to specify a number of iterations, rather than iterating until a break condition is met or the last item in the array

{% assign items = "leash, bowl, collar" | split: ", " %}
{% for item in items limit:2 %}  {{ item }}{% endfor %}

Limit must be followed by a colon and an integer (no spaces). The integer tells the for loop how many iterations to complete. Because we limited this loop to two iterations, only the first two values in the array are output.

Offset allows you to begin a loop at a specific index, or point in the sequence, rather than at 0, the first item in the sequence.

{% assign items = "leash, bowl, collar" | split: ", " %}
{% for item in items offset:2 %}  {{ item }}{% endfor %}

You must follow offset with a colon and an integer (no spaces). The integer represents the position in the array at which the loop should start. Here, we’ve entered 2, so the loop will skip the first two positions in the array, start at the third position, and run until the end of the array. 

You can combine reversed, offset, and limit in the same line of code, like this: 

{% for item in items reversed limit:3 offset:2 %}

However, if you include reversed, it must come before limit and offset. The order of limit and offset doesn’t matter.

Up Next: Using Liquid in