All Collections
Email
Campaign personalisation with Liquid
Using tags to put logic into your campaigns, templates and landing pages
Using tags to put logic into your campaigns, templates and landing pages

Tags are used when building logic to tell your content what to do.

Gareth Burroughes avatar
Written by Gareth Burroughes
Updated over a week ago

You can still use the data object contact.addressbooks. This object also refers to Lists. Address books was the previous name for Lists in Dotdigital.

You can show different content, depending on whether or not the contact's first name is Ben. This works in a similar way to dynamic content:

<!--{% if contact.data.firstname == 'ben' %}-->Hey Ben!<!--{% else %}-->Hello there!<!--{% endif %}-->

A more interesting example is using for-loops, for example:

{% for book in contact.lists %}####{{ list.name }} <br/>{% endfor %}

This gets the lists that a contact is in, and for each list, shows the name followed by a line break.

Supported tags

Important

If your Liquid tags contain HTML reserved characters, wrap all those tags and any nested tags, including any {% elseif %}, {% else %}, {% case %}, and {% when %} tags, in HTML comments. Otherwise, those characters are converted to HTML character entities, which may break your HTML. For example:

<!--{% if contact.data.age > 18 %}-->Access granted<!--{% else %}-->Access denied<!--{% endif %}-->

Don't wrap data objects such as ####{{ contact.data.firstname }} in HTML tags, otherwise this content is not rendered.

Variable names

Don't use the following variable names. These names won't work because they're reserved for system-defined values:

  • account

  • contact

  • token

  • campaign

Assign

The {% assign %} tag stores data in a variable for output (or logic) elsewhere in the campaign, template, or landing page.

Enter the name of your chosen variable after the {% assign %} tag. For example:

<!--{% assign fullname = contact.data.firstname | append: ' ' | append: contact.data.lastname %}-->####{{ fullname }}

Output: Beatrix Potter

Capture

The {% capture %} tag stores all content that is between a {% capture %} tag and an {% endcapture %} tag in a variable. Use this tag for longer variables than those stored in an {% assign %} tag. For example:

<!--{% capture fullname %}-->####{{contact.data.firstname}} ####{{contact.data.lastname}}<!--{% endcapture %}-->####{{ fullname }}

Output: Beatrix Potter

Comment

The contents of a {% comment %}{% endcomment %} block is not rendered. Use this block to make a note in your markup. A comment block begins with a {% comment %} tag and ends with an {% endcomment %} tag. For example:

{% comment %}This bit of markup does something clever to assign the right gender to the contact{% endcomment %}

Output: nothing

Raw

The contents of a {% raw %}{% endraw %} block is not evaluated as liquid markup when your campaign, template, or page is rendered. You can use this tag to include raw liquid markup. For example:

My {% raw %}####{{ contact.data.fullname }}{% endraw %} is ####{{ contact.data.fullname }}.

Output: My ####{{ contact.data.fullname }} is Michael Caine.

If (else and elseif)

{% if %}{% endif %} blocks provide basic conditional logic as to what content should be shown or not shown. An {% if %} tag contains a condition, and if that condition is met then the content in the {% if %}{% endif %} block is included in the campaign, template, or landing page. For example:

Hi there! <!--{% if contact.data.firstname == 'Barney' %}-->You're looking particularly awesome. <!--{% endif %}-->Isn't it a lovely day? Would you like a piece of cake?

Output (for Barney): Hi there! You're looking particularly awesome. Isn't it a lovely day? Would you like a piece of cake?
Output (for anyone else): Hi there! Would you like a piece of cake?

Elseif tags can be used inside an if block to add further conditional content if the first condition is not met. For example:

Hi there! <!--{% if contact.data.firstname == 'Barney' %}-->You're looking particularly awesome. <!--{% elseif contact.data.gender == 'Male' %}-->Isn't it a lovely day? <!--{% endif %}-->Would you like a piece of cake?

Output (for Barney): Hi there! You're looking particularly awesome. Would you like a piece of cake?
Output (for all other males): Hi there! Isn't it a lovely day? Would you like a piece of cake?
Output (for anyone else): Hi there! Would you like a piece of cake?

Else statements can be used inside an if block to add default conditions if the none of the preceding conditions are met. For example:

Hi there! <!--{% if contact.data.firstname == 'Barney' %}-->You're looking particularly awesome. <!--{% elseif contact.data.gender == 'Male' %}-->Isn't it a lovely day? <!--{% else %}-->Would you like a piece of cake?<!--{% endif %}-->

Output (for Barney): Hi there! You're looking particularly awesome.
Output (for all other males): Hi there! Isn't it a lovely day?
Output (for anyone else): Hi there! Would you like a piece of cake?

In these examples, == is an operator that is used to test equivalence.

Unless

The unless block is the reverse of the if block, it shows its content if the condition evaluates to false. It begins with a {% unless %} tag and ends with an {% endunless %} tag. For example:

Yo, ####{{ contact.data.firstname }}!<!--{% unless contact.data.firstname == 'Ted' %}--> Haaaaave you met Ted?<!--{% endunless %}-->

Output (for Ted): Yo, Ted!
Output (for anyone else): Yo, Tracy! Haaaaave you met Ted?

Case

A case block is used in place of a series of if statements, where different content is to be shown based on the value of a single field. A case block starts with a case tag, ends with a endcase tag, uses when tags for each condition, and a else tag to denote the default content. For example:

<!--{% case contact.data.firstname %}-->  <!--{% when 'Simon' %}-->    A lager, sir?  <!--{% when 'Tink' %}-->    Lager top for the gentleman?  <!--{% when 'Simone' %}-->    Can I get you a glass of red?  <!--{% else %}-->    I ain't getting you a drink!<!--{% endcase %}-->

Output (for Simon): A lager, sir?
Output (for Tink): Lager top for the gentleman?
Output (for Simone): Can I get you a glass of red?
Output (for anyone else): I ain't getting you a drink!

Iteration logic

For

A {% for %}{% endfor %} block iterates through the contents of an array. For example:

{% for book in contact.lists %}####{{ list.name }}<br/>{% endfor %}

Output: All lists that a contact is in, with each list item separated by a line break.

A for loop stores each item of an array in a variable, in this case the book variable. Rather than referring to contact.lists[n].name, we now refer to list.name.

Tip

By using a sort filter, we can specify the order that the iterations occur in. For example:

<!--{% assign mybooks = contact.lists | sort: 'name' %}-->{% for list in mylists %}####{{ list.name }}<br>{% endfor %}

Output: All the lists that a contact is in, in alphabetical order, with each list item separated by a line break.

Reverse order

You can reverse the direction that a {% for %}{% endfor %} block iterates through an array by using the reversed parameter. For example:

<!--{% assign mylists = contact.lists | sort: 'name' %}-->{% for list in mylists reversed %}####{{ list.name }}<br>{% endfor %}

Output: All the lists that a contact is in, in reverse alphabetical order.

Limited iterations

You can limit the number of times a for loop will iterate by using the limit parameter. For example:

<!--{% assign mylists = contact.lists | sort: 'name' %}-->{% for list in mylists limit: 3 %}####{{ list.name }}<br>{% endfor %}

Output: The first three lists that a contact is in, ordered alphabetically.

Offset iterations

You can decide to not start at the first item in an array. Use the offset parameter to skip a number of items in an array. For example:

<!--{% assign mybooks = contact.lists | sort: 'name' %}-->{% for list in mylists limit: 3 offset: 2 %}####{{ list.name }}<br>{% endfor %}

Output: The third, fourth and fifth lists that the contact is in, ordered alphabetically.

Ranged iterations

If you want to iterate for a set number of times through a piece of text/markup, but it is not tied to a particular array you can do this using a range. For example to iterate through a piece of code five times you can use this:

<!--{% assign stars = 5 %}--><!--{% for i in (1..stars) %}-->&#8902;<!--{% endfor %}-->

Output: Five stars (&#8902; is code for a star)

Your ranged iteration does not need to start at "1" for example:

{% for value in (68..72) %}####{{ value }}{% endfor %}

Output: 68 69 70 72

Break

The break tag causes a loop to stop iterating, even if it has not reached the final iteration. For example, this loop skips numbers that are divisible by 7:

<!--{% for i in (1..10) %}-->  <!--{% assign remainder = i | modulo:7 %}-->  <!--{% if remainder == 0 %}--> <!--{% break %}--> <!--{% endif %}-->  ####{{ i }}<!--{% endfor %}-->

Output: 1 2 3 4 5 6.

Continue

The continue tag causes a loop to jump to the next iteration without completing the current one. For example, this loop skips the numbers that are divisible by 3:

<!--{% for i in (1..10) %}-->  <!--{% assign remainder = i | modulo:3 %}-->  <!--{% if remainder == 0 %}--> <!--{% continue %}--> <!--{% endif %}-->  ####{{ i }}<!--{% endfor %}-->

Output: 1 2 4 5 7 8 10

Cycle

The cycle tag is used within loops. The parameter for a cycle tag is a list of options; each time a loop iterates, it takes the next option in the list, returning to the first. For example:

{% for i in (1..20) %}<p style="color:{% cycle '#FF0000', '#00FF00', '#0000FF' %};"> ####{{ i }}</p>{% endfor %}

Forloop

A forloop is not a tag, but an object that you can reference from a for block. Use a forloop object to find out where in the series of iterations we currently are. For example:

<!--{% for i in (1..10) %}--><!--{% if forloop.last %}--> and <!--{% endif %}-->####{{ i }}<!--{% unless forloop.last %}-->, <!--{% endunless %}--><!--{% endfor %}-->

Output: 1, 2, 3, 4, 5, 6, 7, 8, 9, and 10

The following elements of the forloop object can be referenced:

forloop.first

Returns 'true' if this is the first iteration through the loop; otherwise it returns 'false'.

forloop.index

Returns the current index of the loop. i.e. the number of iterations that have been started, starting at 1 for the first iteration.

forloop.index0

Returns the current index of the loop starting at zero. i.e. the number of iterations that have ended.

forloop.last

Returns 'true' if this is the last iteration through the loop; otherwise it returns 'false'.

forloop.rindex

Returns the loop index starting in reverse order (so 1 for the last iteration, 2 for the penultimate iteration and so on).

forloop.rindex0

Returns the loop index starting in reverse order starting at zero (so 0 for the last iteration, 1 for the penultimate iteration and so on).

forloop.length

Returns the total number of iterations the loop will go through.

Operators for logical statements

When using logical tags such as if, else and unless the following operators can be used used:

  • == → Is equal to

  • != → Is not equal to

  • > → Is greater than

  • < → Is less than

  • >= → Is greater than or equal to

  • <= → Is less than or equal to

  • contains → Contains

Conditions can be chained together using or and and.

Examples

<!--{% if contact.data.firstname == 'ben' %}-->Hey Ben<!--{% endif %}-->

Conditions can also be combined:

<!--{% if contact.data.firstname == 'ben' and contact.data.age < 12 %}-->Hey young Ben<!--{% endif %}-->

And then using the contains operator you could do:

<!--{% if contact.data.firstname contains 'B' %}-->You are truly awesome; your name contains a B<!--{% endif %}-->

True and false values

If you use a non-boolean data type in a boolean context, for example, a conditional tag, then Liquid decides whether it is true or false. Data types that return as true or false are known as truthy and falsy, respectively.

In Liquid, all values are truthy except for nil and false.

Did this answer your question?