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
andtags
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 theproducts
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
andoffset
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 sidejs
using thejson
filterconst 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.