An Overview of Liquid: Shopify's Templating Language

An Overview of Liquid: Shopify's Templating Language

An Overview of LiquidIf you are new to the Shopify platform and read through our content, you might be wondering what all the references to Liquid actually refer to. In this article, we'll explain all you need to know about Liquid, how it fits into Shopify theme building, and the core concepts that will enable you to start building powerful and immersive ecommerce templates. Let's begin with a little history.

Liquid was developed by Shopify co-founder and CEO Tobias Lütke and is now available as an open source project on GitHub. Today, it's used in many different software projects, from content management systems to flat file site generators — and of course, Shopify.

Liquid: language or engine?

Some refer to Liquid as a template language, while others may call it a template engine. It doesn't really matter which label you apply — in many ways both are right. Personally, I like to call it a template language. It has a syntax (like traditional programming languages), has concepts such as output, logic, and loops, and it interacts with variables (data), just as you would with a web-centric language such as PHP.

However, that's really where the similarities end. There's a lot you can't do with Liquid — by design. For example, it has no concept of "state", it doesn't let you get deep under the covers of the platform, and can occasionally seem counter intuitive for seasoned coders. However, it has been very well thought out and what might at first seem like a limitation, is usually intended and for good reason.

You might also like: Creating Useful CSS Hooks in Liquid

Liquid's function

Liquid, like any template language, creates a bridge between an HTML file and a data store — in our context, the data is of course a Shopify store. It does this by allowing us to access variables from within a template with a simple to use, and readable, syntax.

In Shopify, each template allows us to access certain variables without having to do any heavy lifting. For example, the product.liquid template allows us access to all the details relating to the currently viewed product. Liquid, in turn, allows us to output this data without having to know anything about the actual product itself. These variables are known as template variables. You can also use Liquid to retrieve data that isn't made available to us. For example, you can ask Shopify to populate a variable you create with all the products in a particular collection.

Once we know the names of the variables we have access to, or create, we can use Liquid constructs such as "output" and "loops" to display the data in our templates.

The Shopify platform understands what data to retrieve, and how to display it depending on the Liquid code you have in your template. It might be a simple case of displaying the name of a product or something slightly more complex, such as showcasing a series of product images.

The great benefit of a template language such as Liquid is that you, as the designer, don't need to know anything about the data itself. As such, your templates are 100 percent agnostic and can be applied to multiple stores without any knowledge of the stores content.

Liquid's file extension and delimiters

Liquid files have the extension of .liquid. A .liquid file is a mix of standard HTML code and Liquid constructs. It's an easy to read syntax, and is easy to distinguish from HTML when working with a template file. This is made even easier thanks to the use of two sets of delimiters.

The double curly brace delimiters {{ }} denote output, and the curly brace percentage delimiters {% %} denote logic. You'll become very familiar with these as every Liquid construct begins with one or the other.

Another way of thinking of delimiters is as "placeholders". A placeholder can be viewed as a piece of code that will ultimately be replaced by data when the compiled template is sent to the browser. This data is determined entirely by the theme designer as a result of the Liquid code in the template. As such, Liquid templates, much like templates that inter splice PHP and HTML, serve as representations of what will be rendered.

Output

Let's examine the syntax for "output". As the name suggests, output in Liquid will literally output a piece of data from out store into the template.

Here's a quick example of an output placeholder that you will typically find in the product.liquid template:

<h2>{{ product.title }}</h2>

When rendered this would output the name of the currently viewed product in place of the {{ }}, for example:

<h2>American Diner Mug</h2>

Output, unless manipulated with a filter (which we will look at shortly) is simply a case of replacing the entire placeholder with a text string from your store.

Objects and properties

This example also introduces us to the Liquid dot syntax. This is common in many template and server side languages. Taking our shop.name example we can break it up into two parts.

The first element preceding the . is the object. In this case, it is the shop object. This is a variable that represents all the data relating to the shop that we have defined in the Shopify admin. These data items include:

  • shop.address
  • shop.collections_count
  • shop.currency
  • shop.description
  • shop.domain
  • shop.email
  • shop.enabled_payment_types
  • shop.metafields
  • shop.money_format
  • shop.money_with_currency_format
  • shop.name
  • shop.password_message
  • shop.permanent_domain
  • shop.products_count
  • shop.types
  • shop.url
  • shop.vendors
  • shop.locale

The items following the . represent properties of the shop object. A property could be as simple as the name of the store (as per our example above) or it could be a list of items, such as the kinds of payment types enabled in the store.

Collection properties

You will notice from the list above that a number of the properties are plural, e.g:

  • shop.enabled_payment_types
  • shop.metafields
  • shop.types

These properties represent Liquid collections. Instead of returning a string of data such as the name of the shop they will return an array of data — in other words a list of items we can access via a Liquid loop.

When first using Shopify and Liquid, it's easy to get confused by collections — I certainly did. I will therefore refer to "product collections" and "Liquid collections". The former being a logical grouping of products defined in the Shopify admin, and the latter being a list of items we can access in Liquid code.

Finally, it's worth saying that each one of the list items in our Liquid collection can also have properties. A good example of this is product.images. This represents a list of all the images that have been added to a particular product.

Each of the images in the list has multiple properties associated with it:

  • image.alt
  • image.attached_to_variant?
  • image.id
  • image.product_id
  • image.position
  • image.src
  • image.variants

In order to access these properties, we have to use a Liquid loop.

Liquid loops

Loops are used extensively in Shopify themes, and are thankfully very easy to understand. If you have done any form of basic programming, the concept of loops will likely be very familiar to you.

Using a loop, often known as a for loop, allows us to output the same piece of code a known number of times in our template. As mentioned above, a typical example would be to output all the images associated with a product.

Let's have a look at an example using the product.images Liquid collection I discussed earlier.

Our aim with this loop is to output all of the images for a particular product. Here's a very simplistic loop that will output each image inline:

{% for image in product.images %}
<img src="{{ image | img_url: 'medium' }}">
{% endfor %}

Let's break it down into steps to fully understand it.

Step 1

{% for image in product.images %}

The first line introduces us to the second style of delimiter, the curly brace percentage syntax {% %}. Here, we are using a Liquid for loop. Loops work with Liquid collections, and allow us to iterate over each item in our list in turn. If the product we are currently viewing had six images associated with it, our for loop would loop six times, if it had 10 then it would loop 10 times, and so on. Only once every list item has been looked at (or unless we instruct it otherwise), will the next part of the template be considered.

It's worth noting that unless we specifically ask how big our loop will be, we don't know how many loops will occur — only that Liquid will go ever each item in our list, in turn. The loop will finish after the last iteration, and it's at this point that the template will carry on with it's processing.

In order to access the properties of each list item, we designate a variable to represent the current item in the loop. In our example above it is image. Whilst this is an obvious choice, and will help other designers understand your logic in the future, it can literally be anything. For example, we could use alltheimagesintheworld, in which case it would look as follows:

{% for alltheimagesintheworld in product.images %}

This is of course a silly example to make a point — image makes much more sense, but I just wanted to emphasize the fact that this variable has no relation to the Liquid collection.

Step 2

<img src="{{ image | img_url: 'medium' }}" />

The second line of our code example consists of part HTML and part Liquid. You'll also notice that the src attribute is populated with a Liquid output tag.

This introduces us to the concept of filters which are denoted by the | (pipe) character — we'll look at these in more detail shortly. In our example, the filter is taking the image variable (the current item in our loop) and is creating a fully qualified URL to the "medium" size version of the image, which was created when the product image was added in the Shopify admin.

We'll look at filters, denoted by the | character, next but suffice to say that this short construct will populate the src attribute with the fully qualified URL to the "medium" version of the current image in our list. The filter does all the work of creating the src attribute for us.

Step 3

{% endfor %}

The final line of our example is our closing endfor statement. This tells the template to carry on after all the loops have been executed.

If we had three images in our product.images object the final output would look something like this:

<img src="//cdn.shopify.com/s/files/1/0222/9076/products/il_fullxfull.296506684_medium.jpg?v=1368007899" alt="" />
<img src="//cdn.shopify.com/s/files/1/0222/9076/products/moustache-mugs_by_peter-bruegger_1_ medium.jpg?v=1370429684" alt=" />
<img src="//cdn.shopify.com/s/files/1/0222/9076/products/tumblr_lhr5huUxXL1qfhlb1o1_500_ medium.jpg?v=1370429684" alt=" />

Loops are really useful and something you will encounter daily in your theme development. Outputting images and product variants are two commonly found examples.

You might also like: 4 Advanced Shopify Theming Techniques to Add to Your Workflow

Liquid filters

Another very powerful feature of Liquid is output filters which I used in the code example above. Filters serve three main purposes:

  • They manipulate output data in some way
  • They allow our themes to be agnostic
  • They save theme designers time by reducing the amount of code we need to write

Filters are always used in conjunction with a Liquid output. Let's have a look some filters starting with the date filter.

When outputting a blog post, you'll likely want to let the reader know when it was published:

<p class="date-time">{{ article.published_at | date: '%d %B %Y' }}</p>

As before you'll notice the | character (often referred to as a pipe) in the middle of the output tag. On the left side of the pipe, we have the article object with its associated published_at property and on the right we have the date filter with an argument to denote the date format — in this case '%d %B %Y'.

Without the filter, Shopify would simply output the date the blog article was published at in the format it is stored in the database — which may not be humanly readable. However by adding in the | and including the date filter, we can manipulate the format so it outputs in a format we want.

Put simply, filters allow us to take a piece of data from our store and change it. What we start with on the left hand side gets "piped" through our filter and emerges on the right hand sized changed. It's this final manipulated data that is then output in the template.

Here's another example:

{{ 'style.css' | asset_url | stylesheet_tag }}

Here we are using two filters with the ultimate aim of creating a fully formed style element in a layout file.

We start on the left with the name of the our CSS file, which resides in the assets folder. Next we apply our first filter — in this case the asset_url filter. This is an incredibly useful filter and one you'll use a lot. I've mentioned before how Shopify themes, thanks to Liquid, are agnostic. They don't need to have any knowledge of the store they are working against and the same theme can be applied to multiple stores. However this can cause issues when trying to reference assets as we need a way of knowing where a certain asset (image, JS file, CSS file) is on the network.

Thankfully the asset_url comes to our rescue. By using this filter, Shopify will return the fully qualified path to the assets folder for the theme and append the name of our asset at the end. Just remember it won't actually check that the file exists — it's up to us to ensure that the first part of the tag, in our case 'style.css' is in the assets folder.

Here's how that might look when output:

//cdn.shopify.com/s/files/1/0222/9076/assets/style.css

The final filter in the chain, stylesheet_tag, takes the URL and wraps it in a style element which is then output in our layout file. Here's the final result:

<link href= "//cdn.shopify.com/s/files/1/0222/9076/t/10/assets/style.css?756" rel="stylesheet" type="text/css" media="all" />

Each filter takes the output from its preceding filter and in turn modifies it. When there are no further filters to pass data into, the result is output as HTML into the template.

There are many really useful filters, here are just a few you'll find yourself using:

  • asset_url
  • stylesheet_tag
  • script_tag
  • date
  • pluralize
  • replace
  • handle
  • money
  • money_with_currency
  • img_url
  • link_to

Liquid logic

The final aspect of Liquid we need to look at is logic, here's an example:

{% if product.availabe %}
<h2>Price: £99.99</h2>
{% else %}
<h2 class="sold-out">Sorry - sold out</h2>
{% endif %}

In this snippet, we are controlling the output to our template using a simple if, else, endif statement. In many ways if statements are like questions. Depending on the answer to the question a different piece of markup will be output — or in some cases no markup at all.

In the above example, if the answer to our if statement question is true (product.available returns true or false), we render the words "This product is available", if it's false our template carries on and outputs the text following our {% else %} clause — in this case "Sorry, this product is sold out".

Another way of looking at logic is that it allows us to control the flow of a template and ultimately make decisions on which data is displayed. It's worth noting that unlike output tags the inclusion of logic tags in your templates does not result in anything being directly rendered — rather they allow us to control exactly what is rendered.

You will find yourself using if statements a lot in Shopify theme development. Here's another example:

{% if cart.item_count > 0 %}
<p>You have {{ cart.item_count }} item(s) in your cart</p>
{% else %}
<p>There's nothing in your cart :( Why not have a <a href= "/products">look at our product range</a></p>
{% endif %}

This snippet demonstrates how you can either display the number of items in a visitors cart or output a link to your products.

Operators

You'll notice in this example we are using the greater than > operator. As the cart.item_count variable returns the number of items in the current users cart we can check to see if it is greater than zero, i.e. it has items in it.

If this returns true we can output the message with the current item count, if not we can output:

<p>There's nothing in your cart :( Why not have a <a href= "/products">look at our product range</a></p> instead.

We could actually refactor our example with a filter. By using the pluralize filter we can output item or items depending on the number of items in the cart. The bonus here is that we don't have to know the count in order for Shopify to output the right designation:

{% if cart.item_count > 0 %}
<p>You have {{ cart.item_count }} {{ cart.item_count | pluralize: 'item', 'items' }} in your cart</p>
{% else %}
<p>There's nothing in your cart :( Why not have a <a href= "/products">look at our product range</a></p>
{% endif %}

You'll notice that the refactored example now includes the pluralize filter which takes two parameters. The first is the singular word and the second the plural.

Whilst we have used the > operator in the above example there are a wide range of comparison operators in Liquid including:

  • == equal to
  • != not equal to
  • > greater than
  • < less than
  • >= bigger or equal
  • <= less or equal
  • or this or that
  • and must be this and that
  • contains includes the substring if used on a string, or element if used on an array

Liquid cheat sheet

If you are anything like me, you'll have a hard time committing all these Liquid filters, operators, and structures to memory. Thankfully, we recently released a brand new Shopify Liquid Cheat Sheet for you. It's an indispensable resource, which I strongly encourage you to bookmark and become familiar with.

Summary

We've covered a lot of ground in this article but hopefully it has given you a solid introduction to Liquid. Here's a reminder of what we covered:

  • Liquid is a template language that allows us to display data in a template.
  • Liquid has constructs such as output, logic, loops and deals with variables.
  • Liquid files are a mixture of HTML and Liquid code, and have the .liquid file extension.
  • Liquid files used in a Shopify theme are agnostic and have no concept of the store they are currently being used in.
  • The two types of delimiters used in Liquid.
  • How to output data from a store in a template.
  • How to manipulate data with filters.
  • How to loop over a Liquid collection to output multiple items.
  • The use of logic in a template.
  • The different types of operators used for comparison.

You can learn more about Liquid concepts and how to use it in your own theme development in the Shopify docs.

Want to learn more about building themes for Shopify or your clients? Check out our comprehensive list of articles on Shopify Theme Development as well as our tutorials on Learning Liquid for Shopify.

You might also like: Shopify Tutorial: The product.liquid template

Photo of Keir Whitaker

About the Author

Keir is based in the UK and works on the Partner Growth Team at Shopify. You'll often find him at conferences and running workshops on Shopify theme building. You can subscribe to his newsletter, read his latest articles on Medium, listen to his podcast, and follow him on Twitter.

Grow your business with the Shopify Partner Program

Learn more