Liquid templating reference

Implementing your own design

This is reference on how to use Liquid templating when developing your own design templates.

More on theme files and file structure

The Code Editor

When working with templates you need to have the code editor open along with a preview of the shop. You can toggle the code editor by clicking on the Editor button in Theme settings and open the preview in a separate window or browser tab. When you save any changes the preview is reloaded automatically.

Liquid templates

All files ending with .liquid can contain code that is evaluated server-side. Liquid templates are based on Django which was created around 2003. There’s lot of information on the internet on how to develop using Liquid so we’ll just skim through the basics.

NOTE The implementation of Liquid filters and tags vary somewhat between all engines.

Code blocks

Code is evaluated server side in code blocks surrounded by handlebars {{ ... }} or {% ... %}. The first form is used when you want to output text, the latter form is used when you want to evaluate code without any output.

Example of code evaluation and output

{% let x = 10 %}
{% if x > 5 %}
   {% if product != blank %}
      <div data-product="{{ product.handle }}">{{ product.title }}</div>
   {% endif %}
{% endif %}

Comments

Comments are meant for documentation but can also be useful when developing and testing.

Example of a comment

{% comment %}
This is a comment block which also can be used to turn of blocks of code.
{% let x = 1000 %} // this line is not evaluated 
{% endcomment %}

Raw

The raw keyword is useful for outputting text that could otherwise interfere with liquid.

Variable assignment

Variables can be created in two ways.

  • Use {% assign <variable> = <assignment> %} when declaring variables that should have global scope.
  • Use {% let <variable> = <assignment> %} when declaring variables that should have local scope.

NOTE You can also create variables/objects in for-loop declarations (and other code constructs).

Example of local and global variables

{% let localX = 123 %}
{% assign globalX = 123 %}

Local variables are only accessible inside the code block and file they are declared in. Global variables are accessible from the point of declaration to the end of execution.

NOTE let assignments inherits its value from parent scope but cannot modify it.

Example comparison let and assign

{% let x = 10 %}
{% assign y = 10 %}
{% for z in (10..1) %}
x = {{ x }}  
y = {{ y }}
{% let x = z %}
{% assign y = z %}
{% endfor %}
x is {{ x }} // x = 10
y is {{ y }} // y = 1

Capture blocks

A capture block allows you to assign rendered output into a variable. It is handy for combining strings and variables when rendering html output.

Example of a capture block

{% let x = 10 %}
{% let y = 20 %}
{% capture attrs %}href="link-{{x | plus:y}}.html" data-from="{{x}}" data-to="{{y}}"{% endcapture %}
<a {{ attrs }}>This is a link<a/>

Control flow

Conditional code blocks are executed when using if elsif else statements.

Example of if, elsif, else statements

{% if x > 10 %}
   {{ x }} is larger than 10
{% elsif x > 5 %}
   {{ x }} is larger than 5
{% else %}
   {{ x }} is less than 6
{% endif %}

Logical operators

Operator Operation
== equals
!= does not equal
> greater than
< less than
>= greater than or equal to
<= less than or equal to
or logical or
and logical and

You can also invert the expression by using an unless statement, sometimes that makes more sense.

Example of an unless statement

{% unless x > 10 %}
   {{ x }} is less than 10
{% elsunless x > 5 %}
   {{ x }} is smaller than 5
{% else %}
   {{ x }} is larger than 6
{% endunless %}

When you need multiple statements on the same variable you may use a case when block.

Example of a case block

{% case x %}
  {% when 10 %}
     x is 10
  {% when 9 %}
     x is 9
  {% else %}
     x is not 10 or 9
{% endcase %}

For-loops

Iterating code can be done using for loop blocks. For loops can iterate over arrays, hashes, and ranges of integers.

Example of a for loop iterating over an array

{% for product in collection.products %}
   {{product.title}}
{% endfor %}

NOTE A local variable product was assigned from the products array iteration.

You can also iterate over a range of numbers instead of arrays.

Example of a for loop using break

{% for i in (1..10) %}
  {% if i > 8 %}
     {% break %}
  {% else %}
    {{ i }}
  {% endif %}
{% endfor %}

TIP Use break to exit the loop before completion.

You may also use limit and offset arguments.

Example of a for loop using limit and offset

{% for i in (1..10) offset:5 limit:3 %}
    {{ i }}
{% endfor %}

TIP Use limit and offset parameters to constraint the looping.

You can reverse iterate by including the reversed parameter.

Example of a reversed for loop iteration

{% for i in (1..10) reversed %}
    {{ i }}
{% endfor %}

For loops create some additional variables that can be handy.

Forloop variables

Variable Description
forloop.index index of the current iteration, starting with 1
forloop.index0 zero based index of the current iteration, starting with 0
forloop.length number of iterations
forloop.rindex remaining iterations, ending on 1
forloop.rindex0 remaining iterations, ending on 0
forloop.first true on first iteration
forloop.last true on last iteration

Filters

Filters can transform variables (input) and can be used for performing math operations, string conversions, array manipulations and much more. A filter is applied by using a pipe character | followed by the filter name an optional colon : with one or more comma separated arguments.

Example using a filter

{{ 'Hello World' | slice: 1,5 | uppercase }}

List of liquid filters

Template objects

When working with templates the system creates objects that you can use depending on what context you are in.

Let’s assume you are working with the product template product.liquid (in a ‘product context’), when using that template you have access to the current product object and you can inspect it using {{ product | print_r}}.

Some objects are always available (but lazy loaded on access) such as collections and products but there’s also a customer object which only exists when a customer has logged in.

These objects are made available server side when using liquid code but can be made available client side js using the json filter const p = {{ product | json}};.

Example of using a template object

{% comment %}
   We can reference a product object since we are in a product context.
{% endcomment %}

{% assign productTitle = product.title | upcase %}
{% assign onSale = false %}
{% if product.compareAtPrice > product.price %}
   {% assign onSale = true %}
{% endif %}

{{productTitle}} is {% unless onSale %}not {% endunless %}on sale! 

If you want to see all properties of an object you can do a recursive print out using {{ <object> | print_r }}.

Context dependent objects

Context dependent objects, the name of the object is the same as the current context i.e. page,product, cart, collection.

CMS

Object Theme template
{{ page }} page.liquid
{{ blog }} blog.liquid
{{ article }} article.liquid

eCommerce

Object Template
{{ product }} product.liquid
{{ collection }} collection.liquid
{{ cart }} cart.liquid

Global objects

There are global objects that can be reached from all contexts.

CMS

Object Description
{{ site }} Site information
{{ request }} Site visitor request object
{{ pages }} Lists all pages
{{ blogs }} Lists all blogs
{{ authors }} Lists all authors
{{ navigation }} Navigation lists
{{ countries }} List of all countries
{{ lang }} Current language

eCommerce

Object Description
{{ shop }} Shop information
{{ collections }} Lists of all product collections
{{ products }} List of all products
{{ vendors }} Lists of all vendors
{{ customer }} Logged in customer
{{ currency }} Current currency

Theme assets

Text files uploaded to a theme can be edited using the code editor. Binary files however, are uploaded to the themes media directory and are not editable.

Asset files are referenced by name using the asset_url filter like this {{ 'icons.svg' | asset_url }}.

Javascript

You can upload any javascript file to the assets folder and include that in your theme layout.

Example including a javascript tag

{{ 'asset.js' | script_tag }}

By adding the .liquid extension you can additionally use server-side scripting.

Example of including assets.js.liquid

<script src="{{ 'asset.js' | asset_url }}"></script>

Example of a assets.js.liquid file

var backgroundColor = "{{ settings.pageBackgroundColor | def: '#fff' }}";

TIP Set default values using the def filter to avoid errors caused by missing values.

NOTE Strings are returned as plain text so you need to include the surrounding apostrophes ".

Template snippets

Template snippets are handy for reusing blocks of code and included as partials from your theme files. You create a snippet by clicking on the create link found under the Snippets folder in the editor. To use a snippet you include the file with an optional argument that is passed to the snippet as a variable under its own name.

Example including a snippet

{% for var i in (1..10) %}
<div class="test">
  {% include 'mysnippet' with i %}
</div>
{% endfor %}

Example of a snippet file called mysnippet.liquid

{% comment %}
The variable i passed above is called 'mysnippet' here
{% endcomment %}
i is set to: {{ mysnippet }}

TIP You can also pass named variables to snippets.

Example of passing named variables

{% for var i in (1..10) %}
<div class="test">
  {% include 'mysnippet' i:i, show:true %}
</div>
{% endfor %}

NOTE Two variables are created and assigned values which can then be accessed by the snippet.

You can also combine with and named variables like this.

Example of using with and named variables

{% for var i in (1..10) %}
<div class="test">
  {% include 'mysnippet' with i show:true %}
</div>
{% endfor %}

TIP It’s good practice to set default values in the snippet.

Example of snippet variables and using default values

{% comment %}
The variable i passed above is called 'mysnippet' here and a named variable called 'show' has been created if set.
{% endcomment %}
{% let my_i = mysnippet | def:0 %}
{% let my_show = show | def:false %}

Image rescaling

Image rescaling is an important feature for theme developers when creating designs that adapts to different screen sizes, commonly known as responsive design. Cradle offers server side rescaling of images, with some tweaks, so that you can get optimal performance from your design.

Product images

Product images can be rescaled using the following code snippet.

Example of rescaling a products featured image

{{ product.featuredImage | product_img_url:200,200 }}

The product_img_url filter takes three arguments, width, height and an additional cropped or whitefit (optional). When the width or height is zero the image is scaled to maintain its original aspect ratio.

Example of rescaling a product image with fixed height

{{ product.featuredImage | product_img_url:0,200 }}

The above code would render an image with a fixed height of 200 pixels.

When rescaling with a fixed width and height it is useful to center crop the image. That can be done by adding cropped argument.

Example of rescaling a product image with fixed height

{{ product.featuredImage | product_img_url:200,200,'cropped' }}

If cropping is not an option you may try the whitefit argument instead which maintains the aspect ratio by including a white border.

Custom endpoints

You can create your own ajax endpoints by returning json in a template instead of html. Start by adding a new template in the code editor by clicking on the Create Template link.

As an example, if you want to create a product endpoint you select the product template and call it json. You then get a new template file called product.json.liquid.

Example of a custom product json endpoint

{% layout 'none' %}
{{ product | json }}

After saving the file you can call the endpoint with a javascript ajax GET request.

Example of calling a custom product json endpoint using fetch

fetch("{{product | url}}?template=json").then(res => {
    console.log(res.json());
});

TIP You select the name of the template by using ?template=json url-option.