Zephyr Control Structures

Welcome to our newly overhauled Zephyr pages! See our new Overview, Examples, and Index.
Feedback is welcome at bottom of each page.

Simple variable replacement is not enough for more complex, personalized templates. Sailthru supports several types of control structures, conditionals, and loops:


Usage: {if expression}result{/if}

You can set up conditional blocks based on a variable.

You can use {if}...{/if}to display something only based on a particular condition.

For if‘s purposes, 0""(empty string), null, and falseall evaluate to false, and anything else evaluates totrue.

{if name} 
<p>Your name is {name}! </p>


Usage: {if expression1}result 1{else if expression2}result 2{else}result 3{/if}

You can add any number of {else} expressions to an {if}.

In this example, result 1 will be the result if expression1 evaluates to true,result 2 will be the result if expression1 evaluates to false but expression2 evaluates to true, and result 3 will be the result if both expression1 and expression2 evaluate to false.

Another example would be to check if a user has a “first_name” variable on there profile. If so, show it. If not, check if there’s a “full_name” variable. If so, pull in the first element (i.e., the user’s first name) using the first() function [link]. Otherwise, show a default value:

{if profile.vars.first_name}
Hi, {first_name}!
{else if profile.vars.full_name}
Hi, {first(full_name)}!
Hi, friend!

Ternary Operator ? :

Usage: {expression1 ? expression2 : expression3}

Will return expression2 if expression1 evaluates to true, otherwise will return expression3.

Not technically a control structure, but you can use the ternary operator as a handy inline shortcut for if in many situations.

<p>Dear {gender == 'M' ? 'Mr.' : 'Ms.'} {last_name}, </p>

Alternate usage: expression1 ?: expression2

In abbreviated form, it will return expression1 if expression1 evaluates to true; otherwise it will return expression2. This is especially useful if you don’t know if a variable is set or not:

<p>Your current status is: {status ?: 'Unknown'} </p>
You are {is_special_subscriber ? 'definitely' : 'not'} one of our special subscribers.

The template will show the word “definitely” or “not” depending on the value of the is_special_subscriber



If the variable {name} is set to anything, it will get displayed.

<p>Dear {name?:'valued customer'},</p>

If it’s blank or null, the string valued customer

will get inserted instead.

Another example (if you collect a “first_name” custom field on your users and do not wish to have a default salutation to your users):

{first_name ? first_name + ", h" : "H"}i there!

If the first_name custom field is blank or null, “Hi there!” will display without any default salutation.

For multiple vars, you would concatenate within the expression: <p>Dear {first + " " + last ?: 'Friend'},</p>   



{switch expression}
{case expression}case{/case}
{case expression}case{/case}
. . .

Given a series of {case}s, picks the first one that matches the value.

{switch office} 
   {case 'NY'}Thanks for signing up at our New York office!{/case} 
   {case 'LA'}Thanks for checkin in with us in LA!{/case} 


Usage: {select}{case expression}case{/case}{case expression}case{/case} . . . {/select}

Given a series of {case}s, evaluates them all and picks the one with the highest numeric value. If there is a tie, the tie will go to the earlier {case}.

This is especially useful when combined with Horizon profiling functions like horizon_interest(). You can provide different content based on which of several interests is the strongest.

{case horizon_interest('menswear,fashion')}Check out our new suits!{/case} 
{case horizon_interest('purses')}Try out our new purses{/case} {case horizon_interest('jewelry')}Look at our jewelry selection!{/case} 


Usage: {foreach expression as variable} loop contents {/foreach}

Loop through a list or object, assigning a temporary variable to each item, such as items from a Content Feed:

<p>Your stories for today:</p>
 {foreach content as c}
 <td><a href={c.url}>{c.name}</a></td>

key-value {foreach}

Usage: {foreach expression as keyvar, valuevar} loop contents {/foreach}

You can also loop through both keys and values. If you loop through a list, the key will be the integer index of the item (starting at 0).

  {foreach content as i, c}
    <li>Item #{i+1}: {c.url}</li>

If you pass in an array for one of your variables, you can use a foreach to loop through it. Let’s say you passed in a JSON object for your variables that looked like this:

{"name":"Joe Schmoe", "gender":"male","order":[{"qty":1,"name":"Product A"},{"qty":3,"name":"Product B"}]}

You can also use {break} or {continue} within loops. When a {break} statement is evaluated as “true” wihin a loop, the loop will immediately terminate. When a {continue} statement is evaluated as “true” within a loop, the item will be skipped and the loop will move on to the next item.

Terminating a loop to pull at the seventh item to limit the number of items populated:

<p>Picked For You:</p>
{foreach content as i,c}
  {if i == 6}
      <a href="{c.url}">{c.title}</a>

Skipping over items that do not have a value for an “image” parameter using {continue}:

{foreach content as c}
{if !c.image}
   <a href={c.url}>{c.title}</a><br/>


Within a loop, you cannot add keys or elements to the iterated object or array. For example, the following code would result in an error:

{obj = { 'a' : 1, 'b' : 2 }}
{foreach obj as k, v}
  {obj.c = 3}

{* comments *}

Enclose Zephyr comments in {* braces with asterisks *}. Unlike HTML comments, Zephyr comments will not render and are not visible to end users.

{* start the main header block here *} 
{include 'header'} 

{* now loop through the content *} 
{foreach content as c} 
{* fill this in later... *} 

Note: Zephyr statements within HTML code comments will still render, so be sure to use the Zephyr commenting syntax as needed according to the description in the {* comments *} section above.