How can we help?

Dynamic content with {foreach} statements

Overview

{foreach} statements allow you to loop through an array of data and render the results in a message. They're commonly used to display similar and related products after someone browses or purchases an item, or puts a product in their cart. {foreach} statements are used in conjunction with GET methods that return data arrays.

The following properties and constructs are supported for use with {foreach}:

  • Properties: @index, @iteration, @first, @last, @show, @total
  • Constructs: {break}, {continue}

Loop through a simple array

Our first example demonstrates how to loop through an array of product color names and render them in the message. Below is the code we'll build upon.

  • {$colors = ['red','blue','green','purple']}
    
    {foreach $colors as $color}
    {$color}<br>
    
    {/foreach}
  • red<br>
    blue<br>
    green<br>
    purple<br>
  • red
    blue
    green
    purple

You can test this code yourself by pasting it into your message HTML or Sculpt Block and previewing it. The preview will run the Smarty functions and show you the rendered output.

Code breakdown

1. First we'll set a variable with the value being an array of product colors. Normally you'd access data arrays with a GET method, but for this example we'll place the data array in the message. The example below sets a variable called colors for the array of colors.

{$colors = ['red','blue','green','purple']}

2. Then we'll set a variable for each item in the array and start the {foreach} loop. The example below sets a variable called color for each item in the array.

{foreach $colors as $color}

3. Next we'll write HTML that will render each item followed by a line break.

{$color}<br>

4. Finally, we'll close the {foreach}

{/foreach}

Render loop in a bulleted list

If we want to render the colors as a bulleted list, we can add some additional HTML. Notice how we'll place the opening and closing <ul> tags outside of the {foreach} statement. The <li> and </li> tags are placed inside of the {foreach} because that 's the code we want to render for every loop.

  • {$colors = ['red','blue','green','purple']}
    
    <ul>
        {foreach $colors as $color}
        <li>{$color}</li>
        {/foreach}
    </ul>
  • <ul>
       <li>red</li>
       <li>blue</li>
       <li>green</li>
       <li>purple</li>
    </ul>
    • red
    • blue
    • green
    • purple

Render loop in a table

Let's extend the example by placing the data inside a table. Notice how we place the <table> tag outside of the {foreach}. The <tr> and <td> tags are inside the {foreach} because that is the code we want to render for every loop.

  • {$colors = ['red','blue','green','purple']}
    
    <table>
        {foreach $colors as $color}
        <tr>
            <td>{$color}</td>
        </tr>
        {/foreach}
    </table>
  • <table>
       <tr>
        <td>red</td>
       </tr>
       <tr>
        <td>blue</td>
       </tr>
       <tr>
        <td>green</td>
       </tr>
       <tr>
        <td>purple</td>
       </tr>
    </table>
  • red
    blue
    green
    purple

Loop through supplement data

In the previous examples we looped through an array of data set within the message code. Now let's take an example of an array of data that's stored as a supplement. This tactic could be used to display similar or related products to someone's browsing behavior or cart activity.

We've created a supplement called pants and have included the following fields:

  • Item
  • Seasonal collection
  • Price

You can put the sample data in CSV format and use the API to upload into your system for testing.

Here's an example of the HTML & Smarty, the supplement data in JSON format, and how the rendered output will look.

  • {$clothing=$utils->getSupplementRecords('pants')}
    {foreach $pants as $pants}
        <strong>{$pants.collection} {$pants.item}</strongbr>
        ${$pants.price}<br>
    {/foreach}
  • [
        {
          "model": "joggers",
          "collection": "spring",
          "price": 75,
          "id": "01"
        },
        {
          "model": "sweatpants",
          "collection": "winter",
          "price": 60,
          "id": "02"
        },
        {
          "model": "rise_jeans",
          "collection": "fall",
          "price": 100,
          "id": "03"
        },
        {
          "model": "capris",
          "collection": "spring",
          "price": 85,
          "id": "04"
        },
        {
          "model": "cargos",
          "collection": "fall",
          "price": 100,
          "id": "05"
        },
        {
          "model": "old_school",
          "collection": "fall",
          "price": 95,
          "id": "06"
        }
      ]
  • Joggers
    $75
    Spring collection

    Sweatpants
    $60
    Winter collection

    Rise Jeans
    $100
    Fall collection

    Capris
    $85
    Spring collection

    Cargos
    $100
    Fall collection

    Old School
    $95
    Fall collection

Code breakdown

In order to render this data in a message, we need to make it available by using a GET method. For supplement data we use the getSupplementRecords method.

{$clothing=$utils->getSupplementRecords('pants')}

Next we'll set a variable for each record in the array and start the {foreach} loop. We can use any name, but for this example we'll use the name clothing.

{foreach $clothing as $pants}

Now we can reference each of the variables in the array. We'll write the HTML and the Smarty variables we want to render for each loop. The loop will run until there are no more records left in the array.

 <strong>{$pants.collection} {$pants.item}</strong><br>
${$pants.price}<br>
{/foreach}

Note that each variable is prepended with the name of the variable we set in the {foreach} statement.

Limit the number of records using an {if} statement

Let's extend the previous example and add an {if} condition to render a filtered result that only shows pants that cost less than $90.

  • {$clothing=$utils->getSupplementRecords('pants')}
      {foreach $clothing as $pants}
      {if $pants.price < 90}
          <strong>{$pants.item} {$pants.collection}</strong><br>
          ${$pants.price}<br>
      {/if}
      {/foreach}
  • [
        {
          "model": "joggers",
          "collection": "spring",
          "price": 75,
          "id": "01"
        },
        {
          "model": "sweatpants",
          "collection": "winter",
          "price": 60,
          "id": "02"
        },
        {
          "model": "rise_jeans",
          "collection": "fall",
          "price": 100,
          "id": "03"
        },
        {
          "model": "capris",
          "collection": "spring",
          "price": 85,
          "id": "04"
        },
        {
          "model": "cargos",
          "collection": "fall",
          "price": 100,
          "id": "05"
        },
        {
          "model": "old_school",
          "collection": "fall",
          "price": 95,
          "id": "06"
        }
      ]
  • Joggers
    $75
    Spring collection

    Sweatpants
    $60
    Winter collection

    Capris
    $85
    Spring collection

Limit the number of records using a counter and {break}

By starting a counter and incrementing the number for each loop, we can limit the amount of records by setting a {break} if the counter reaches 4.

  • {$clothing=$utils->getSupplementRecords('pants')}
      {$counter = 0}  
    {foreach $clothing as $pants}
    {if $counter > 3 }{break}{/if} {if $pants.price < 90} <strong>{$pants.item} {$pants.collection}</strong><br> ${$pants.price}<br> {$counter = $counter+1} {/foreach}
  • [
        {
          "model": "joggers",
          "collection": "spring",
          "price": 75,
          "id": "01"
        },
        {
          "model": "sweatpants",
          "collection": "winter",
          "price": 60,
          "id": "02"
        },
        {
          "model": "rise_jeans",
          "collection": "fall",
          "price": 100,
          "id": "03"
        },
        {
          "model": "capris",
          "collection": "spring",
          "price": 85,
          "id": "04"
        },
        {
          "model": "cargos",
          "collection": "fall",
          "price": 100,
          "id": "05"
        },
        {
          "model": "old_school",
          "collection": "fall",
          "price": 95,
          "id": "06"
        }
      ]
  • Joggers
    $75
    Spring collection

    Sweatpants
    $60
    Winter collection

    Rise Jeans
    $100
    Fall collection

    Capris
    $85
    Spring collection

Limit the number of records using @iterationand {break}

Smarty has a built in counter that will count each loop as an iteration. We can use @iteration to {break} out of the loop when it reaches 4.

  • {$clothing=$utils->getSupplementRecords('pants')}
    {foreach $clothing as $pants}
    {if $pants@iteration > 3 }{break}{/if}
    <strong>{$pants.item} {$pants.collection}</strong><br>
    ${$pants.price}<br>
    {/foreach}
  • [
        {
          "model": "joggers",
          "collection": "spring",
          "price": 75,
          "id": "01"
        },
        {
          "model": "sweatpants",
          "collection": "winter",
          "price": 60,
          "id": "02"
        },
        {
          "model": "rise_jeans",
          "collection": "fall",
          "price": 100,
          "id": "03"
        },
        {
          "model": "capris",
          "collection": "spring",
          "price": 85,
          "id": "04"
        },
        {
          "model": "cargos",
          "collection": "fall",
          "price": 100,
          "id": "05"
        },
        {
          "model": "old_school",
          "collection": "fall",
          "price": 95,
          "id": "06"
        }
      ]
  • Joggers
    $75
    Spring collection

    Sweatpants
    $60
    Winter collection

    Rise Jeans
    $100
    Fall collection

    Capris
    $85
    Spring collection

Use {continue} to omit an iteration and continue with the next

You can skip specific iterations and {continue} looping through the remaining iterations that match your query.

  • {$contains.lookup_str = 'berry'}
    {$contains.caseSensitive = false}
    {$data.fruits = ["apple", "orange", "banana", "kiwi", "strawberry", "watermelon", "pear", "blackberry", "blueberry"]}
    {foreach $data.fruits as $berry}
        {$contains.string = $berry}
        {if $utils->strContains($contains.lookup_str, $contains.string, $contains.caseSensitive)}
          {$berry}<br>
        {else}
          {continue} {* not a berry, skip this loop, but do not break.*}
        {/if}
    {/foreach}
  • strawberry
    blackberry
    blueberry

Use both the key and the value

In some use cases it is nice to have access to both the key and the value.

  • {$big_object = ["item"=>"cargos", "price"=>"100", "junk"=>["foo"=>"bar", "biz"=>"baz"]]}
      {$include_array = ["item", "price"]}
      {foreach $big_object as $key => $value}
        {if in_array($key, $include_array)}
          {$small_object[$key] = $value}
        {/if}
      {/foreach}
      <h2>Debug Small Object</h2>
      <pre>{json_encode($small_object, 128)}</pre>
      <h2>Debug Big Object</h2>
      <pre>{json_encode($big_object, 128)}</pre>
  • Debug Small Object
    {
      "item": "cargos",
      "price": "100"
    }
    Debug Big Object
    {
      "item": "cargos",
      "price": "100",
      "junk": {
        "foo": "bar",
        "biz": "baz"
      }
    }

Use a {for} loop

In some use cases, it's useful to loop through a known number of iterations.

  • {$from = 0}
    {$to = 2}
    
    {for $i=$from to $to} i is: {$i}<br> {/for}
  • i is: 0
    i is: 1
    i is: 2

Comments

0 comments

Please sign in to leave a comment.