Zephyr Control Structures
Simple variable replacement is not enough for more complex, personalized templates. Engage by Sailthru supports several types of control structures, conditionals, and loops:
{if}
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 false
all evaluate to false
, and anything else evaluates totrue
.
{if name}
<p>Your name is {name}! </p>{/if}
{if}...{else}...{/if}
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)}! {else} Hi, friend! {/if}
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
variable.
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}
Usage:
{switch expression}
{case expression}case{/case}
{case expression}case{/case}
. . .
{/switch}
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}
{/switch}
{select}
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.
{select}
{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}
{/select}
{foreach}
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><table> {foreach content as c}
<tr> <td><a href={c.url}>{c.name}</a></td> </tr> {/foreach}
</table>
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).
<ul> {foreach content as i, c}
<li>Item #{i+1}: {c.url}</li> {/foreach}
</ul>
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} {break} {else} <a href="{c.url}">{c.title}</a> <br/> {/if} {/foreach}
Skipping over items that do not have a value for an "image" parameter using {continue}:
{foreach content as c} {if !c.image} {continue} {else} <a href={c.url}>{c.title}</a><br/> {/if} {/foreach}
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} {/foreach}
{* 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... *}
{/foreach}
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.