Difference between revisions of "Liquid Tag Reference"

From Spiffy Stores Knowledge Base

 
(22 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
Liquid Tags provide the logic and control flow in your template. They allow you to display data conditionally and to dynamically change the way the template is rendered according to the data in the Liquid variables.
 
Liquid Tags provide the logic and control flow in your template. They allow you to display data conditionally and to dynamically change the way the template is rendered according to the data in the Liquid variables.
  
=== Comments ===
+
=== Comment ===
 
 
 
A comment is the simplest of tags. It just swallows content.
 
A comment is the simplest of tags. It just swallows content.
 
 
<pre>
 
<pre>
 
Hi fred {% comment %} you stink {% endcomment %}
 
Hi fred {% comment %} you stink {% endcomment %}
 
</pre>
 
</pre>
 +
=== Echo ===
 +
Output an expression in the rendered HTML. This is identical to wrapping an expression in <nowiki>{{ and }}</nowiki>, but works inside '''liquid''' tags and supports Filters.
 +
<pre>
 +
{% liquid
 +
if product.featured_image
 +
  echo product.featured_image | img_tag
 +
else
 +
  echo 'product-1' | placeholder_svg_tag
 +
endif %}
 +
</pre>
 +
=== Liquid ===
 +
The '''liquid''' tag allows you to write multiple tags within a single set of delimiters.
 +
<pre>
 +
{% liquid
 +
  case section.blocks.size
 +
  when 1
 +
    assign column_size = ''
 +
  when 2
 +
    assign column_size = 'one-half'
 +
  when 3
 +
    assign column_size = 'one-third'
 +
  else
 +
    assign column_size = 'one-quarter'
 +
  endcase %}
 +
</pre>
 +
Use the '''echo''' tag to output an expression within a '''<nowiki>{% liquid %}</nowiki>''' tag.
  
 
=== Variable Assignment ===
 
=== Variable Assignment ===
 
 
You can store data in your own variables, to be used in output or other tags as desired.
 
You can store data in your own variables, to be used in output or other tags as desired.
  
 
The simplest way to create a variable is with the '''assign''' tag, which has a pretty straightforward syntax:
 
The simplest way to create a variable is with the '''assign''' tag, which has a pretty straightforward syntax:
 
 
<pre>
 
<pre>
 
{% assign name = 'freestyle' %}
 
{% assign name = 'freestyle' %}
Line 21: Line 43:
 
{% endif %}{% endfor %}
 
{% endif %}{% endfor %}
 
</pre>
 
</pre>
 
 
Another way of doing this would be to assign true/false values to the variable:
 
Another way of doing this would be to assign true/false values to the variable:
 
 
<pre>
 
<pre>
 
{% assign freestyle = false %}
 
{% assign freestyle = false %}
Line 33: Line 53:
 
{% endif %}
 
{% endif %}
 
</pre>
 
</pre>
 
 
If you want to combine a number of strings into a single string and save it to a variable, you can do that with the '''capture''' tag. This tag is a block which "captures" whatever is rendered inside it and assigns it to the given variable instead of rendering it to the screen. Here's how it works:
 
If you want to combine a number of strings into a single string and save it to a variable, you can do that with the '''capture''' tag. This tag is a block which "captures" whatever is rendered inside it and assigns it to the given variable instead of rendering it to the screen. Here's how it works:
 
 
<pre>
 
<pre>
 
   {% capture attribute_name %}{{ item.title }}-{{ i }}-color{% endcapture %}
 
   {% capture attribute_name %}{{ item.title }}-{{ i }}-color{% endcapture %}
Line 100: Line 118:
 
'>=' - Greater Than or Equal
 
'>=' - Greater Than or Equal
 
'<=' - Less Than or Equal
 
'<=' - Less Than or Equal
'contains' - String contains substring
+
'contains' - String contains substring, or Array contains element
 
</pre>
 
</pre>
  
Line 233: Line 251:
  
 
=== Cycle ===
 
=== Cycle ===
 
+
Often you have to cycle through an number of alternative values. Liquid has built-in support for such operations using the '''cycle''' tag.
Often you have to cycle through an number of alternative values. Liquid has built-in support for such operations using the '''Cycle''' tag.
 
 
 
 
<pre>
 
<pre>
 
{% cycle 'one', 'two', 'three' %}
 
{% cycle 'one', 'two', 'three' %}
Line 242: Line 258:
 
{% cycle 'one', 'two', 'three' %}
 
{% cycle 'one', 'two', 'three' %}
 
</pre>
 
</pre>
 
+
This produces
''...will result in...''
 
 
 
 
<pre>
 
<pre>
 
one
 
one
Line 251: Line 265:
 
one
 
one
 
</pre>
 
</pre>
 
 
If no name is supplied for the cycle group then its assumed that multiple calls with the same parameters are one group.
 
If no name is supplied for the cycle group then its assumed that multiple calls with the same parameters are one group.
  
 
If you want to have total control over cycle groups you can optionally specify the name of the group. This can even be a variable.
 
If you want to have total control over cycle groups you can optionally specify the name of the group. This can even be a variable.
 
 
<pre>
 
<pre>
 
{% cycle 'group 1': 'one', 'two', 'three' %}
 
{% cycle 'group 1': 'one', 'two', 'three' %}
Line 262: Line 274:
 
{% cycle 'group 2': 'one', 'two', 'three' %}
 
{% cycle 'group 2': 'one', 'two', 'three' %}
 
</pre>
 
</pre>
 
+
This produces
''...will result in...''
 
 
 
 
<pre>
 
<pre>
 
one
 
one
Line 272: Line 282:
 
</pre>
 
</pre>
  
 +
=== Increment ===
 +
Create a new number variable, and increases its value by 1 every time '''increment''' is called on the variable. The counter's initial value is 0.
 +
 +
Here, an increment counter is used to create a unique numbered class for each list item.
 +
<pre>
 +
<ul>
 +
  <li class="item-{% increment counter %}">apples</li>
 +
  <li class="item-{% increment counter %}">oranges</li>
 +
  <li class="item-{% increment counter %}">peaches</li>
 +
  <li class="item-{% increment counter %}">plums</li>
 +
</ul>
 +
</pre>
 +
The output from this is
 +
<pre>
 +
<ul>
 +
  <li class="item-0">apples</li>
 +
  <li class="item-1">oranges</li>
 +
  <li class="item-2">peaches</li>
 +
  <li class="item-3">plums</li>
 +
</ul>
 +
</pre>
 +
Variables created using increment are separate from variables created using assign or capture.
 +
 +
In the example below, a variable named ''my_number'' is created using '''assign'''. The '''increment''' tag is then used several times on a variable with the same name. Note that the '''increment''' tag does not affect the value of ''my_number'' that was created through assign.
 +
<pre>
 +
{% assign my_number = 10 %}
 +
 +
{% increment my_number %}
 +
{% increment my_number %}
 +
{% increment my_number %}
 +
 +
{{ my_number }}
 +
</pre>
 +
The output generated is
 +
<pre>
 +
0
 +
1
 +
2
 +
 +
10
 +
</pre>
 +
 +
=== Decrement ===
 +
Create a new number variable, and decreases its value by 1 every time '''decrement''' is called on the variable. The counter's initial value is -1.
 +
<pre>
 +
{% decrement variable %}
 +
{% decrement variable %}
 +
{% decrement variable %}
 +
</pre>
 +
This produces
 +
<pre>
 +
-1
 +
-2
 +
-3
 +
</pre>
 +
Like '''increment''', variables declared using '''decrement''' are independent from variables created using '''assign''' or '''capture'''.
 
=== For Loops ===
 
=== For Loops ===
 
 
Liquid allows for loops over collections. This allows you to loop over things like line-items in an order.
 
Liquid allows for loops over collections. This allows you to loop over things like line-items in an order.
 
 
<pre>
 
<pre>
 
   {% for item in order.line-items %}
 
   {% for item in order.line-items %}
Line 281: Line 345:
 
   {% endfor %}
 
   {% endfor %}
 
</pre>
 
</pre>
 
 
If the collection is empty, then you can use an optional '''else''' tag to provide alternative output.
 
If the collection is empty, then you can use an optional '''else''' tag to provide alternative output.
 
 
<pre>
 
<pre>
 
   {% for item in order.line-items %}
 
   {% for item in order.line-items %}
Line 291: Line 353:
 
   {% endfor %}
 
   {% endfor %}
 
</pre>
 
</pre>
 
 
The order of the loop may be reversed by adding the flag ''reversed''.
 
The order of the loop may be reversed by adding the flag ''reversed''.
 
 
<pre>
 
<pre>
 
   {% for item in order.line-items reversed %}
 
   {% for item in order.line-items reversed %}
Line 299: Line 359:
 
   {% endfor %}
 
   {% endfor %}
 
</pre>
 
</pre>
 
 
During every '''for''' loop, the following helper variables are available for additional control over the results.
 
During every '''for''' loop, the following helper variables are available for additional control over the results.
 
 
<pre>
 
<pre>
 
  forloop.length    # => length of the entire for loop
 
  forloop.length    # => length of the entire for loop
Line 313: Line 371:
 
  forloop.last      # => is this the last iteration?
 
  forloop.last      # => is this the last iteration?
 
</pre>
 
</pre>
 
 
There are several attributes you can use to influence which items you receive in your loop
 
There are several attributes you can use to influence which items you receive in your loop
  
Line 326: Line 383:
 
   # results in 3,4
 
   # results in 3,4
 
</pre>
 
</pre>
 
 
Instead of looping over an existing collection, you can define a range of numbers to loop through. The range can be defined by both literal and variable numbers:
 
Instead of looping over an existing collection, you can define a range of numbers to loop through. The range can be defined by both literal and variable numbers:
 
 
<pre>
 
<pre>
 
   # if item.quantity is 4...
 
   # if item.quantity is 4...
Line 336: Line 391:
 
   # results in 1,2,3,4
 
   # results in 1,2,3,4
 
</pre>
 
</pre>
 
 
The number of times that you loop through a '''for''' loop can be changed by using the '''break''' and '''continue''' statements.
 
The number of times that you loop through a '''for''' loop can be changed by using the '''break''' and '''continue''' statements.
  
 
You can leave a '''for''' loop entirely by using '''break'''.
 
You can leave a '''for''' loop entirely by using '''break'''.
 
 
<pre>
 
<pre>
 
{% for item in collection %}
 
{% for item in collection %}
Line 348: Line 401:
 
{% endfor %}
 
{% endfor %}
 
</pre>
 
</pre>
 
 
You can stop processing a particular iteration of the loop, and continue processing the next iteration with '''continue'''.
 
You can stop processing a particular iteration of the loop, and continue processing the next iteration with '''continue'''.
 
 
<pre>
 
<pre>
 
{% for item in collection %}
 
{% for item in collection %}
Line 397: Line 448:
 
     {% endif %}
 
     {% endif %}
 
   {% endtablerow %}
 
   {% endtablerow %}
 +
</pre>
 +
 +
=== Special Literals ===
 +
 +
We've already seen a number of special literals that can be used in comparison operations. The full list of special lierals is a follows.
 +
 +
* 'nil'
 +
* 'null'
 +
* 'true'
 +
* 'false'
 +
* 'blank'
 +
* 'empty'
 +
* 'now'
 +
 +
The 'now' literal can be used with Date Filters to reference the current date and time. The date and time is always returned using the time zone of the store, as specified in the Toolbox Preferences -> Standards & formats.
 +
 +
<pre>
 +
{% capture day_name %}{{ 'now' | date: "%A" }}{% endcapture %}
 +
{% capture current_time %}{{ 'now' | date: "%H:%M" }}{% endcapture %}
 +
<p>Today is {{ day_name }}, and the time is {{ current_time }}.</p>
 +
 +
=>
 +
 +
Today is Sunday, and the time is 13:09.
 
</pre>
 
</pre>
  
 
=== Including Snippets ===
 
=== Including Snippets ===
 
 
Liquid code can include code fragments or snippets from the theme's <code>snippets</code> folder or from the global snippets library. The theme's <code>snippets</code> folder is searched first before a search is made of the global library. This means that you can use any of the snippets from the global library, but override the snippet by creating a snippet of the same name in the theme's <code>snippet</code> folder.
 
Liquid code can include code fragments or snippets from the theme's <code>snippets</code> folder or from the global snippets library. The theme's <code>snippets</code> folder is searched first before a search is made of the global library. This means that you can use any of the snippets from the global library, but override the snippet by creating a snippet of the same name in the theme's <code>snippet</code> folder.
  
Line 408: Line 482:
  
 
All snippets are named as follows
 
All snippets are named as follows
 
 
<pre>
 
<pre>
 
_snippet_name.liquid
 
_snippet_name.liquid
 
</pre>
 
</pre>
 
 
A snippet is included into Liquid code by using the '''include''' tag.
 
A snippet is included into Liquid code by using the '''include''' tag.
 
 
<pre>
 
<pre>
 
{% include 'snippet_name' %}
 
{% include 'snippet_name' %}
 
</pre>
 
</pre>
 
 
Note that the leading '_' character is not required on the <code>include</code> tag.
 
Note that the leading '_' character is not required on the <code>include</code> tag.
  
Line 424: Line 494:
  
 
For example, assume we have a snippet called <code>_widget.liquid</code>.
 
For example, assume we have a snippet called <code>_widget.liquid</code>.
 
 
<pre>
 
<pre>
 
<p>The widget shape is {{ widget }}. It is {{ colour }}.</p>
 
<p>The widget shape is {{ widget }}. It is {{ colour }}.</p>
 
</pre>
 
</pre>
 
 
Within a template we can include the following code:
 
Within a template we can include the following code:
 
 
<pre>
 
<pre>
 
{% assign colour = 'yellow' %}
 
{% assign colour = 'yellow' %}
Line 439: Line 506:
 
{% include 'widget' with 'triangle' %}
 
{% include 'widget' with 'triangle' %}
 
</pre>
 
</pre>
 
 
This will render as
 
This will render as
 
 
<pre>
 
<pre>
 
<p>The widget shape is . It is yellow.</p>
 
<p>The widget shape is . It is yellow.</p>
Line 448: Line 513:
 
<p>The widget shape is triangle. It is green.</p>
 
<p>The widget shape is triangle. It is green.</p>
 
</pre>
 
</pre>
 +
A snippet may also be included for use with a collection, with the snippet being rendered once for each member of the collection.
 +
<pre>
 +
{% include 'product' for products %}
 +
</pre>
 +
Each snippet is rendered with a local variable with the same name as the snippet being set to the value of each of the elements in the collection in turn. In the above example, the snippet is named ''product'', and therefore a local variable named ''product'' is initialized with a value from the collection ''products'' each time the snippet is rendered.
 +
 +
=== Render ===
 +
Use the '''render''' tag to render a snippet from the <code>snippets</code> folder of a theme. This tag replaces the deprecated '''include''' tag.
 +
<pre>
 +
{% render 'snippet-name' %}
 +
</pre>
 +
Note that you don't need to write the file's ''.liquid'' extension.
 +
 +
When a snippet is rendered, the code inside it does not automatically have access to the variables assigned using variable tags within the snippet's parent template. Similarly, variables assigned within the snippet can't be accessed by the code outside of the snippet. This encapsulation increases performance and helps make theme code easier to understand and maintain.
 +
 +
'''Note:''' When a snippet is rendered using the render tag, the deprecated '''include''' tag may not be used within the snippet.
 +
 +
==== Passing variables to a snippet ====
 +
Variables assigned using variable tags can be passed to a snippet by listing them as parameters on the '''render''' tag.
 +
<pre>
 +
{% assign my_variable = 'apples' %}
 +
{% render 'name', my_variable: my_variable, my_other_variable: 'oranges' %}
 +
</pre>
 +
Global objects don't need to be passed down. They are accessible from all files.
 +
 +
'''Caution:''' Assigning a variable within the snippet that is also assigned in the parent template does not overwrite its value in the parent template.
 +
==== The with parameter ====
 +
A single object can be passed to a snippet by using the '''with''' and '''as''' parameters:
 +
<pre>
 +
{% assign featured_product = all_products['product_handle'] %}
 +
{% render 'product' with featured_product as product %}
 +
</pre>
 +
In the example above, the product variable in the snippet will hold the value of ''featured_product'' in the parent template.
 +
==== The for parameter ====
 +
A snippet can be rendered once for each value of an enumerable object by using the '''for''' and '''as''' parameters:
 +
<pre>
 +
{% assign variants = product.variants %}
 +
{% render 'variant' for variants as variant %}
 +
</pre>
 +
In the example above, the snippet will be rendered once for each variant of the product, and the variant variable will hold a product variant object within the snippet.
 +
 +
When using the '''for''' parameter, the '''forloop''' object is accessible from within the snippet.
  
 
=== Specifying an Alternative Layout ===
 
=== Specifying an Alternative Layout ===
 
 
By default, all Liquid templates are rendered using the '''theme.liquid''' layout file.
 
By default, all Liquid templates are rendered using the '''theme.liquid''' layout file.
  
Line 456: Line 562:
  
 
The following tag can be inserted into a template to indicate that the layout file '''mobile.liquid''' should be used to render that template.
 
The following tag can be inserted into a template to indicate that the layout file '''mobile.liquid''' should be used to render that template.
 
 
<pre>
 
<pre>
 
{% layout 'mobile' %}
 
{% layout 'mobile' %}
 
</pre>
 
</pre>
 +
If you don't want any layout to be used for a template, then use
 +
<pre>
 +
{% layout 'none' %}
  
If you don't want any layout to be used for a template, then use
+
or
  
 +
{% layout none %}
 +
</pre>
 +
You may also specify the layout name using a variable, where the value of the variable is the name of the layout that you wish to use.
 
<pre>
 
<pre>
{% layout 'none' %}
+
{% layout settings.customer_layout %}
 
</pre>
 
</pre>
 
 
You can include the '''layout''' tag within conditional logic tags to selectively use different layouts for the template file.
 
You can include the '''layout''' tag within conditional logic tags to selectively use different layouts for the template file.
  
See your tutorial on [[Creating a custom landing page]].
+
See our tutorial on [[Creating a custom landing page]].
  
 
=== Creating Custom Forms ===
 
=== Creating Custom Forms ===

Latest revision as of 09:36, 3 November 2020

Liquid Tags provide the logic and control flow in your template. They allow you to display data conditionally and to dynamically change the way the template is rendered according to the data in the Liquid variables.

Comment

A comment is the simplest of tags. It just swallows content.

Hi fred {% comment %} you stink {% endcomment %}

Echo

Output an expression in the rendered HTML. This is identical to wrapping an expression in {{ and }}, but works inside liquid tags and supports Filters.

{% liquid
if product.featured_image
  echo product.featured_image | img_tag
else
  echo 'product-1' | placeholder_svg_tag
endif %}

Liquid

The liquid tag allows you to write multiple tags within a single set of delimiters.

{% liquid
  case section.blocks.size
  when 1
    assign column_size = ''
  when 2
    assign column_size = 'one-half'
  when 3
    assign column_size = 'one-third'
  else
    assign column_size = 'one-quarter'
  endcase %}

Use the echo tag to output an expression within a {% liquid %} tag.

Variable Assignment

You can store data in your own variables, to be used in output or other tags as desired.

The simplest way to create a variable is with the assign tag, which has a pretty straightforward syntax:

{% assign name = 'freestyle' %}
{% for t in collections.tags %}{% if t == name %}
  <p>Freestyle!</p>
{% endif %}{% endfor %}

Another way of doing this would be to assign true/false values to the variable:

{% assign freestyle = false %}
{% for t in collections.tags %}{% if t == 'freestyle' %}
  {% assign freestyle = true %}
{% endif %}{% endfor %}
{% if freestyle %}
  <p>Freestyle!</p>
{% endif %}

If you want to combine a number of strings into a single string and save it to a variable, you can do that with the capture tag. This tag is a block which "captures" whatever is rendered inside it and assigns it to the given variable instead of rendering it to the screen. Here's how it works:

  {% capture attribute_name %}{{ item.title }}-{{ i }}-color{% endcapture %}

  <label for="{{ attribute_name }}">Colour:</label>
  <select name="attributes[{{ attribute_name }}]" id="{{ attribute_name }}">
    <option value="red">Red</option>
    <option value="green">Green</option>
    <option value="blue">Blue</option>
  </select>

Arrays

If a liquid expression returns an array of objects, then you can access the members of the array using an index notation.

For example to access the third element of an array of products

{{ collection.products[2].title }}

All array elements are accessed using a zero-based index, so the first element of the array is always index 0.

Additionally, three special methods are available for arrays.

'size' - Returns the number of elements in the array
'first' - Returns the first element in the array
'last' - Returns the last element in the array
{{ collection.products.first }}
{{ collection.products.last }}
You have {{ cart.items.size }} items in your cart

Raw Tags

If you need to include code in your template that you don't want interpreted by the Liquid parser, then you need to enclose it with raw tags.

These tags will allow you to incorporate code such as JavaScript templates that use the same curly braces as Liquid.

{% raw %}{{ 3 | plus: 4}}{% endraw %} is usually equal to 7.

The code between the raw tags is protected, so the result is

{{ 3 | plus: 4}} is usually equal to 7.

If / Else

The conditional expressions formed with if/else should be a familiar construction from most programming languages. Liquid allows you to write simple expressions in the if.

The conditions that can be used to test for logical conditions are:

'==' - Equal
'!=' - Not Equal
'<>' - Not Equal
'<' - Less Than
'>' - Greater Than
'>=' - Greater Than or Equal
'<=' - Less Than or Equal
'contains' - String contains substring, or Array contains element

You can perform comparisons against a number of special literals:

'nil' - The object does not exist
'null' - The object does not exist
'true' - The object is true
'false' - The object is false
'blank' - The object is a blank string
'empty' - The object (array or string) is empty

Compound expressions may be formed by the use of or and and expressions.

{% if user %}
  Hi {{ user.name }}
{% endif %}

{% if user.name == 'fred' %}
  hi fred
{% endif %}

{% if user.name != 'fred' %}
  you aren't fred
{% endif %}

{% if user.name == 'fred' or user.name == 'dirk' %}
  hi dirk or fred
{% endif %}

{% if user.name == 'fred' and user.last_name == 'bloggs' %}
  hi fred bloggs
{% endif %}

{% if user.creditcard == null %}
  user has no credit
{% endif %}

{% if user.payments == empty %}
  you never paid !
{% endif %}

{% if user.age > 18 %}
  Login here
{% else %}
  Sorry, you are too young
{% endif %}

{% if user.name contains 'y' %}
  Sorry, we don't allow users with a 'y' in their name!  
{% endif %}

Multiple if statements can be chained together using if/elsif/else statements. For example,

{% if product.price > 1000 %}
  Free shipping
{% elsif product.price == 1000 %}
  Half-price shipping
{% elsif product.price > 500 %}
  Bonus gift
{% else %}  
  Shipping is $10
{% endif %}

Unless / Else

The conditional expressions formed with Unless/Else are the reverse of the usual If/Else logic. An Unless/Else block is written using exactly the same expressions and conditions as an If/Else block, but the test logic is reversed.

{% unless user.name == 'fred' %}
  you aren't fred
{% endunless %}

{% unless user.age > 18 %}
  Sorry, you are too young
{% else %}
  Login here
{% endunless %}

IfChanged Block

The ifchanged block tag is used within a loop. It checks its own rendered contents against its previous state and only displays its content if the value has changed.

For example, in order to show the date only when a post is published on a new day (always displaying the time):

{% ifchanged %}
  <div class="date">{{ article.published_at | date: '%B %d'  }}</div>
{% endifchanged %}
<div class="time">{{ article.published_at | date: '%I:%M %p'  }}</div>

Case Statement

If you need more than one condition you can use the case statement. Multiple when conditions may be included by separating each condition by an or keyword or a comma.

{% case line_item.quantity %}
  {% when 0 %}
  none
  {% when 1 %}
  one
  {% when 2 %}
  two
  {% when 3, 4 %}
  either 3 or 4
  {% when 5 or 6 or 7 %}
  either 5, 6 or 7
  {% else %}
  a few more...
{% endcase %}

Example:

{% case template %}
	
{% when 'label' %}
     // {{ label.title }}
{% when 'product' %}
     // {{ product.vendor | link_to_vendor }} / {{ product.title }}
{% else %}
     // {{page_title}
{% endcase %}

Cycle

Often you have to cycle through an number of alternative values. Liquid has built-in support for such operations using the cycle tag.

{% cycle 'one', 'two', 'three' %}
{% cycle 'one', 'two', 'three' %}
{% cycle 'one', 'two', 'three' %}
{% cycle 'one', 'two', 'three' %}

This produces

one
two
three
one

If no name is supplied for the cycle group then its assumed that multiple calls with the same parameters are one group.

If you want to have total control over cycle groups you can optionally specify the name of the group. This can even be a variable.

{% cycle 'group 1': 'one', 'two', 'three' %}
{% cycle 'group 1': 'one', 'two', 'three' %}
{% cycle 'group 2': 'one', 'two', 'three' %}
{% cycle 'group 2': 'one', 'two', 'three' %}

This produces

one
two
one
two

Increment

Create a new number variable, and increases its value by 1 every time increment is called on the variable. The counter's initial value is 0.

Here, an increment counter is used to create a unique numbered class for each list item.

<ul>
  <li class="item-{% increment counter %}">apples</li>
  <li class="item-{% increment counter %}">oranges</li>
  <li class="item-{% increment counter %}">peaches</li>
  <li class="item-{% increment counter %}">plums</li>
</ul>

The output from this is

<ul>
  <li class="item-0">apples</li>
  <li class="item-1">oranges</li>
  <li class="item-2">peaches</li>
  <li class="item-3">plums</li>
</ul>

Variables created using increment are separate from variables created using assign or capture.

In the example below, a variable named my_number is created using assign. The increment tag is then used several times on a variable with the same name. Note that the increment tag does not affect the value of my_number that was created through assign.

{% assign my_number = 10 %}

{% increment my_number %}
{% increment my_number %}
{% increment my_number %}

{{ my_number }}

The output generated is

0
1
2

10

Decrement

Create a new number variable, and decreases its value by 1 every time decrement is called on the variable. The counter's initial value is -1.

{% decrement variable %}
{% decrement variable %}
{% decrement variable %}

This produces

-1
-2
-3

Like increment, variables declared using decrement are independent from variables created using assign or capture.

For Loops

Liquid allows for loops over collections. This allows you to loop over things like line-items in an order.

  {% for item in order.line-items %}
    {{ item.description }}
  {% endfor %}

If the collection is empty, then you can use an optional else tag to provide alternative output.

  {% for item in order.line-items %}
    {{ item.description }}
  {% else %}
    <p>This collection is empty!</p>
  {% endfor %}

The order of the loop may be reversed by adding the flag reversed.

  {% for item in order.line-items reversed %}
    {{ item.description }}
  {% endfor %}

During every for loop, the following helper variables are available for additional control over the results.

 forloop.length     # => length of the entire for loop
 forloop.index      # => index of the current iteration
 forloop.index0     # => index of the current iteration (zero based)
 forloop.rindex     # => how many items are still left?
 forloop.rindex0    # => how many items are still left? (zero based)
 forloop.odd        # => is this iteration odd (zero based)?
 forloop.even       # => is this iteration even (zero based)?
 forloop.first      # => is this the first iteration?
 forloop.last       # => is this the last iteration?

There are several attributes you can use to influence which items you receive in your loop

  • limit lets you restrict how many items you get
  • offset lets you start the collection with the nth item.
  # array = [1,2,3,4,5,6]
  {% for item in array limit:2 offset:2 %}
    {{ item }}
  {% endfor %}
  # results in 3,4

Instead of looping over an existing collection, you can define a range of numbers to loop through. The range can be defined by both literal and variable numbers:

  # if item.quantity is 4...
  {% for i in (1..item.quantity) %}
    {{ i }}
  {% endfor %}
  # results in 1,2,3,4

The number of times that you loop through a for loop can be changed by using the break and continue statements.

You can leave a for loop entirely by using break.

{% for item in collection %}
  {% if item.condition %}
    {% break %}
  {% endif %}
{% endfor %}

You can stop processing a particular iteration of the loop, and continue processing the next iteration with continue.

{% for item in collection %}
  {% if item.other_condition %}
    {% continue %}
  {% endif %}
{% endfor %}

Tables

Liquid can also create table rows and cells for you, although you still need to wrap a table tag around the tablerow tag.

  <table>
    {% tablerow item in items cols: 3 limit: 12 %}
      {{ item.variable }}
    {% endtablerow %}
  </table>

You can also find out whether a table cell is the first or last column in a row or directly query the column number.

 tablerowloop.length       # => length of the entire for loop
 tablerowloop.index        # => index of the current iteration
 tablerowloop.index0       # => index of the current iteration (zero based)
 tablerowloop.rindex       # => how many items are still left?
 tablerowloop.rindex0      # => how many items are still left? (zero based)
 tablerowloop.first        # => is this the first iteration?
 tablerowloop.last         # => is this the last iteration?
 tablerowloop.odd          # => is this iteration odd (zero based)?
 tablerowloop.even         # => is this iteration even (zero based)?
 tablerowloop.col          # => index of column in the current row
 tablerowloop.col0         # => index of column in the current row (zero based)
 tablerowloop.col_first    # => is this the first column in the row?
 tablerowloop.col_last     # => is this the last column in the row?
  {% tablerow item in items cols: 3 %}
    {% if col_first %}
      First column: {{ item.variable }}
    {% else %}
      Different column: {{ item.variable }}
    {% endif %}
  {% endtablerow %}

Special Literals

We've already seen a number of special literals that can be used in comparison operations. The full list of special lierals is a follows.

  • 'nil'
  • 'null'
  • 'true'
  • 'false'
  • 'blank'
  • 'empty'
  • 'now'

The 'now' literal can be used with Date Filters to reference the current date and time. The date and time is always returned using the time zone of the store, as specified in the Toolbox Preferences -> Standards & formats.

{% capture day_name %}{{ 'now' | date: "%A" }}{% endcapture %} 
{% capture current_time %}{{ 'now' | date: "%H:%M" }}{% endcapture %}
<p>Today is {{ day_name }}, and the time is {{ current_time }}.</p>

=>

Today is Sunday, and the time is 13:09.

Including Snippets

Liquid code can include code fragments or snippets from the theme's snippets folder or from the global snippets library. The theme's snippets folder is searched first before a search is made of the global library. This means that you can use any of the snippets from the global library, but override the snippet by creating a snippet of the same name in the theme's snippet folder.

Details of all the global snippets can be found here: Using global Liquid snippets.

These snippets can be used to include code in a layout, template or another snippet.

All snippets are named as follows

_snippet_name.liquid

A snippet is included into Liquid code by using the include tag.

{% include 'snippet_name' %}

Note that the leading '_' character is not required on the include tag.

When a snippet is included into another piece of Liquid code, it will be rendered using all of the currently assigned variables. An optional with parameter allows you to assign a value to a variable bound to the snippet's name within the snippet's context.

For example, assume we have a snippet called _widget.liquid.

<p>The widget shape is {{ widget }}. It is {{ colour }}.</p>

Within a template we can include the following code:

{% assign colour = 'yellow' %}
{% include 'widget' %}
{% include 'widget' with 'round' %}
{% include 'widget' with 'square' %}
{% assign colour = 'green' %}
{% include 'widget' with 'triangle' %}

This will render as

<p>The widget shape is . It is yellow.</p>
<p>The widget shape is round. It is yellow.</p>
<p>The widget shape is square. It is yellow.</p>
<p>The widget shape is triangle. It is green.</p>

A snippet may also be included for use with a collection, with the snippet being rendered once for each member of the collection.

{% include 'product' for products %}

Each snippet is rendered with a local variable with the same name as the snippet being set to the value of each of the elements in the collection in turn. In the above example, the snippet is named product, and therefore a local variable named product is initialized with a value from the collection products each time the snippet is rendered.

Render

Use the render tag to render a snippet from the snippets folder of a theme. This tag replaces the deprecated include tag.

{% render 'snippet-name' %}

Note that you don't need to write the file's .liquid extension.

When a snippet is rendered, the code inside it does not automatically have access to the variables assigned using variable tags within the snippet's parent template. Similarly, variables assigned within the snippet can't be accessed by the code outside of the snippet. This encapsulation increases performance and helps make theme code easier to understand and maintain.

Note: When a snippet is rendered using the render tag, the deprecated include tag may not be used within the snippet.

Passing variables to a snippet

Variables assigned using variable tags can be passed to a snippet by listing them as parameters on the render tag.

{% assign my_variable = 'apples' %}
{% render 'name', my_variable: my_variable, my_other_variable: 'oranges' %}

Global objects don't need to be passed down. They are accessible from all files.

Caution: Assigning a variable within the snippet that is also assigned in the parent template does not overwrite its value in the parent template.

The with parameter

A single object can be passed to a snippet by using the with and as parameters:

{% assign featured_product = all_products['product_handle'] %}
{% render 'product' with featured_product as product %}

In the example above, the product variable in the snippet will hold the value of featured_product in the parent template.

The for parameter

A snippet can be rendered once for each value of an enumerable object by using the for and as parameters:

{% assign variants = product.variants %}
{% render 'variant' for variants as variant %}

In the example above, the snippet will be rendered once for each variant of the product, and the variant variable will hold a product variant object within the snippet.

When using the for parameter, the forloop object is accessible from within the snippet.

Specifying an Alternative Layout

By default, all Liquid templates are rendered using the theme.liquid layout file.

In some cases, it is useful to be able to select that a different layout file is to be used to render a particular template. The layout tag can achieve this.

The following tag can be inserted into a template to indicate that the layout file mobile.liquid should be used to render that template.

{% layout 'mobile' %}

If you don't want any layout to be used for a template, then use

{% layout 'none' %}

or

{% layout none %}

You may also specify the layout name using a variable, where the value of the variable is the name of the layout that you wish to use.

{% layout settings.customer_layout %}

You can include the layout tag within conditional logic tags to selectively use different layouts for the template file.

See our tutorial on Creating a custom landing page.

Creating Custom Forms

The form tag can be used to define a custom form in a page.liquid template. You must use the argument contact when defining the form.

{% form 'contact' %}
...
{% endform %}

A full description, with examples, on how to create custom forms can be found in the How to create and customize a Contact Form tutorial.

Further Reference