Liquid Cheat Sheet

19 minute read comments

Liquid is an open-source template language created by Shopify in 2006. It is written in Ruby and it is used by many hosted web applications like Jekyll websites. Since my website is a Jekyll website, I thought that it would be very helpful to have something like a Liquid glossary at hand, just to know, how the Liquid syntax looks like and which commands are available.

Therefore I’ve created this Cheat Sheet, that gives an overview of Liquid commands one might encounter while developing a Jekyll website. It’s a conglomerate of the sources listed below. For a more complete overview, please visit, e.g., the Jekyll or Shopify documentation website.

Note, this is not the official Liquid logo. At the time I wrote this post, I actually couldn't find an official logo. This is just a self-composed placeholder.

The Liquid template language and its main components

Webpages can contain both static and dynamic content. Static content is content, that remains always the same on multiple pages (i.e., content won’t change just by re-visiting a page or switching to another one). Dynamic content changes from one page to the next.

A template language enables the re-use of the static elements that define the layout of a webpage, while dynamically populating the page with data from the website. The static elements are written in HTML, and the dynamic elements are written in Liquid. The Liquid elements in a file act as placeholders: When the code in the file is compiled, the placeholders are replaced by data from the website.

Acknowledgement: The information in this section was retrieved from the Shopify documentation website . Further information on template processing can be found in this Wikipedia article .

The Liquid syntax can be categorized into three main component types:

Liquid component Description   Example
tag Liquid tags contain some commands that are internally used within the Liquid template processing. {% some commands %}
object Liquid objects are output on your page {{ my_variable }}
filter Liquid filters change the output of a Liquid object or variable {{ "adam!" | capitalize | prepend: "Hello " }}

Some general commands

Command Description  
{% comment %}Some comment.{% endcomment %}
{% comment %}{% assign var = 9 %}{% endcomment %}
Comments: skips rendering the enclosed Liquid code and text  
{% include archive-single.html type=entries_layout %} Inserts rendered content of another template within the current template  
{% highlight %} Enables syntax highlighting. See examples here.  

To display raw Liquid expressions, enclose them by the raw/endraw tag:

Liquid raw tag

Variables

Command Description  
{% assign my_variable = 5 %} define a variable  
{% assign my_variable = site.my_collection | map: 'tags' | join: ',' | split: ',' | uniq %} defining a variable with some extra filters  
{{ my_variable }} outputs a variable or object on your page  
{% capture my_variable %}Some text{%endcapture%}
My variable: {{ my_variable }}.
> My variable: Some text
captures the enclosed string (which can also be a Liquid object) and assigns it to a variable (stored as a string)  

for loops

Command Description  
{% for tag in my_variable %}
  {% <h3>{{tag}}</h3> %}
  <ul>
  {% for page in site.my_collection %}
  {% if page.tags contains tag %}
    {% <li><a href="{{ site.baseurl }}{{ note.url }}">{{ note.title }}</a></li> %}
  {% end if %}
  {% endfor %}
  </ul>
{% endfor %}
for loop with an if condition  
{% break %} stops the iteration of a loop  
{% continue %} skips the iteration within a loop  
{% for item in array limit:2 %} limits the loop to the specified number of iterations  
{% for item in array offset:2 %} starts the loop at the specified offset index  
{% for i in (start..stop) %}

{% assign num = 4 %}
{% assign my_range = (1..num) %}
defines a range of numbers  
{% for item in array reversed %} reverses the order of the loop  

Cycling

Looping through a group of strings and outputs them in the order that they were passed as arguments. On each call, the next string argument is output:

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

cycle with “cycle group” parameters (for multiple cycle blocks):

{% cycle "first": "one", "two", "three"  %}
{% cycle "second": "one", "two", "three"  %}
{% cycle "second": "one", "two", "three"  %}
{% cycle "first": "one", "two", "three"  %}

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

if statements

Command Description  
{% if my_var == 5 %}
my_var is 5
{% elsif my_var == 10 %}
my_var is 10
{% else %}
my_var is not 5 and not 9
{% endif%}
if statement with elsif and else  
{% unless my_var == 9 %}
my_var is still not 9
{% endunless%}
the opposite of if (equivalent to !=)  
Boolean operators Description  
== equal  
!= not equal  
> greater than  
< less than  
>= greater than or equal to  
<= less than or equal to  
or logical or  
and logical and  
contains checks for the presence of a substring inside a string  
true logical true  
false logical false  

Liquid maths

Command Description and example  
divided_by dividing a number

{% assign var = 10 %}
{{ 20 | divided_by: var }}
 
modulo returns the remainder of a division operation

{{ 5 | modulo: 2 }}
 
times multiplying a number

{{ assign var2 = var | times: 1.0 }}
 
minus substracting a number

{{ 5 | minus: 1 }}
 
plus adding a number

{{ 5 | plus: 1 }}
 
increment Creates and outputs a new number variable (initial value 0). On each call, it increases its value by 1 and outputs the new value.

{% increment my_counter %}
{% increment my_counter %}
{% increment my_counter %}

You can also increment predefined variables. Each call increases its value by 1 and outputs the new value:

{% assign my_counter = 5 %}
{% increment my_counter %}
 
decrement similar to increment, but decreasing the corresponding variable by 1

{% decrement my_counter %}
 
round rounds an input to the nearest integer (or to the optional passed number of decimal places)

{{ 5.78 | round }}
{{ 5.785 | round: 2 }}
 
floor rounds an input down to the nearest whole number

{{ 5.78 | floor }}
 
ceil rounds an input up to the nearest whole number

{{ 5.78 | ceil }}
 
abs returns the absolute value of a number

{{ -5 | abs }}
 
size returns the number of characters/items in a string/array

{{ "some string" | size }}

You can use it with dot notation when you need to use the filter inside a tag:

{% if site.pages.size > 10 %}
 
number_of_words counts the number of words in some text (Jekyll specific)

{{ "Hello world!" | number_of_words }}
 
at_most limits a number to a maximum value

{{ 4 | at_most: 5 }}
 
at_least limits a number to a minimum value

{{ 4 | at_least: 5 }}
 
to_integer converts a string or boolean to integer (Jekyll specific)

{{ some_var | to_integer }}
 

Special filters

Filter Description and example  
downcase transforms each character in a string lowercase

{{ "Men from Mars" | downcase }}
> men from mars
 
upcase transforms each character in a string uppercase

{{ "Men from Mars" | upcase }}
> MEN FROM MARS
 
capitalize transforms each character in a string capitalized and converts the remaining characters to lowercase

{{ "Men from Mars" | capitalize }}
> Men from mars
 
truncatewords Shortens a string down to the number of words passed as an argument. If the specified number of words is less than the number of words in the string, an ellipsis (…) or custom ellipsis (e.g., --) is appended to the string.

{{ "One two three four." | truncatewords: 3 }}
> One two three...
{{ "One two three four." | truncatewords: 3, "--" }}
> One two three--
{{ "One two three four." | truncatewords: 3, "" }}
> One two three
 
truncate Shortens a string down to the number of cahracters passed as an argument. If the specified number of characters is less than the length of the string in the string, an ellipsis (…) or custom ellipsis (e.g., , and so on) is appended to the string and is included in the character count.

{{ "One two three four." | truncate: 10 }}
> One two...
{{ "One two three four." | truncate: 18, ", and so on" }}
> One two, and so on
{{ "One two three four." | truncate: 7, "" }}
> One two
 
slice Returns a substring of one character or series of array items beginning at the index specified by the first argument. An optional second argument specifies the length of the substring or number of array items to be returned. String or array indices are numbered starting from 0.

{{ "Water" | slice: 0 }}
> W
{{ "Water" | slice: 3 }}
> e
{{ "Water" | slice: 2,4 }}
> ter
 
strip removes all whitespace (tabs, spaces, and newlines) from both the left and right sides of a string (does not affect spaces between words)

!{{ " This is some text " | strip }}.
> !This is some text.
 
rstrip removes all whitespace from both the right side of a string

!{{ " This is some text " | rstrip }}.
> ! This is some text.
 
lstrip removes all whitespace from both the left side of a string

!{{ " This is some text " | lstrip }}.
> !This is some text .
 
strip_newlines removes newline characters from a string

{{ string | strip_newlines }}
 
newline_to_br inserts an HTML line break (<br />) in front of each newline (\n) in a string

{{ string | newline_to_br }}
 
compact removes any nil values from an array

Example.
 
strip_html removes any HTML tags from a string

{{ "This <em>is</em> some <strong>text</strong>." | strip_html }}
> This is some text.
 
url_encode converts URL-unsafe characters in a string into percent-encoded characters

{{ "john@liquid.com" | url_encode }}
> john%40liquid.com
 
url_decode decodes a string that has been encoded as a URL or by url_encode

{{ "Hey%21" | url_decode }}
> Hey!
 
split divides a string into an array using the argument as a separator

{% assign var = "One, two, three, four" | split: ", " %}
{{ var }}
> One two thre four
 
replace replaces every occurrence of the first argument in a string with the second argument

{{ "Take my car and bring it to my home" | replace: "my", "your" }}
> Take your car and bring it to your home
 
replace_first replaces only the first occurrence of the first argument in a string with the second argument

{{ "Take my car and bring it to my home" | replace_first: "my", "your" }}
> Take your car and bring it to my home
 
append appends a string (can also be a variable) to another string

``{% raw %}{{ “/my_url”
append: “.html” }}<br>> /my_url.html`
prepend adds the specified string to the beginning of another string

{{ "apples, oranges and bananas" | prepend: "Some fruit: " }}
> Some fruit: apples, oranges and bananas
 
concat concatenates multiple arrays

{% assign fruits = "apples, oranges, peaches" | split: ", " %}
{% assign vegetables = "carrots, turnips, potatoes" | split: ", " %}
{% assign all = fruits | concat: vegetables %}

{{ all }}> apples oranges peaches carrots turnips potatoes
 
remove removes every occurrence of the specified substring from a string

{{ "I strained to see the train through the rain" | remove: "rain" }}
> I sted to see the t through the
 
remove_first removes only the first occurrence of the specified substring from a string

{{ "I strained to see the train through the rain" | remove_first: "rain" }}
> I sted to see the train through the rain
 
join combines the items in an array into a single string using the argument as a separator

{% assign array = "add, Zack, Orpheus, Albert, Stephen, snake" | split: ", " %}
{{ array | join: ", " }}
> add and Zack and Orpheus and Albert and Stephen and snake
 
map creates an array of values by extracting the values of a named property from another object

{% assign all_categories = site.pages | map: "category" %}
 
where creates an array including only objects with a given property value (or any true value by default)

{% assign tag_postcards = tags | where: "type", "postcard" %}
 
uniq removes any duplicate items in an array

{{ my_array | uniq | join: ", " }}
 
sort sorts items in an array in case-sensitive order

{% assign array = "add, Zack, Orpheus, Albert, Stephen, snake" | split: ", " %}
{{ array | sort | join: ", " }}
> Albert, Orpheus, Stephen, Zack, add, snake
 
sort_natural sorts items in an array in case-insensitive order

{% assign array = "Zack, Orpheus, Albert, Stephen" | split: ", " %}
{{ array | sort_natural | join: ", " }}
> Albert, Orpheus, Stephen, Zack
 
first returns the first item of an array

{{ "One two three four" | split: " " | first }}
> One
{% assign var = "One, two, three, four" | split: ", " %}
{{ var.first }}
> One
 
last returns the last item of an array

{{ "One two three four" | split: " " | last }}
> four
{% assign var = "One, two, three, four" | split: ", " %}
{{ var.last }}
> four
 

Dates

The date filter converts a given timestamp into another date format. The format for this syntax follows the guidelines of strftime. E.g.,

{{ post.date | date: "%a, %b %d, %y" }}

     Thur, Aug 17, 21

{{ post.date | date: "%Y" }}

     2021

{{ "May 4, 2020" | date: "%a, %b %d, %y" }}

     Thur, May 4, 20

You can also work with the current time and date:

{{ "now" | date: "%Y-%m-%d %H:%M" }}

     2021-08-11 20:15

Info: now returns the current time and date each time when your Jekyll website is built. You can use this, e.g., for implementing an automatic “This website/page was updated on …” information on your website or page.

The following date filters are Jekyll specific ones:

Command output
{{ site.time | date_to_xmlschema }} 2008-11-07T13:07:54-08:00
{{ site.time | date_to_rfc822 }} Mon, 07 Nov 2008 13:07:54 -0800
{{ site.time | date_to_string }} 07 Nov 2008
{{ site.time | date_to_string: "ordinal", "US" }} Nov 7th, 2008
{{ site.time | date_to_long_string }} 07 November 2008
{{ site.time | date_to_long_string: "ordinal" }} 7th November 2008

Jekyll specific filters

The following filters are special Jekyll filters:

Filter Description and example  
where Selects all objects in an array where the key has the given value.
{{ site.members | where:"graduation_year","2014" }}
 
where_exp Selects all objects in an array where the expression is true.
{{ site.members | where_exp:"item", "item.graduation_year == 2014" }}
{{ site.members | where_exp:"item", "item.graduation_year < 2014" }}
{{ site.members | where_exp:"item", "item.projects contains 'foo'" }}
 
find Returns the first object in an array for which the queried attribute has the given value or return nil if no item in the array satisfies the given criteria.
{{ site.members | find: "graduation_year", "2014" }}
 
find_exp Returns the first object in an array for which the given expression evaluates to true or return nil if no item in the array satisfies the evaluated expression.
{{ site.members | find_exp:"item", "item.graduation_year == 2014" }}
 
group_by Groups an array’s items by a given property.
{{ site.members | group_by:"graduation_year" }}
 
group_by_exp Groups an array’s items using a Liquid expression.
{{ site.members | group_by_exp: "item", "item.graduation_year | truncate: 3, ''" }}
 
array_to_sentence_string Converts an array into a sentence (e.g. useful for listing tags). Optional argument for connector.
{{ page.tags | array_to_sentence_string }}
 
markdownify Converts a Markdown-formatted string into HTML.
{{ page.excerpt | markdownify }}
 
smartify Converts “quotes” into smart quotes.
{{ page.title | smartify }}
 
slugify Converts a string into a lowercase URL slug.
{{ "The _config.yml file" | slugify }}
> the-config-yml-file
slugify accepts the following extra filter options, each specifying what to filter:
     none (no characters)
     raw (spaces)
     default (spaces and non-alphanumeric characters)
     pretty (spaces and non-alphanumeric characters except for ._~!$&'()+,;=@)
     ascii (spaces, non-alphanumeric, and non-ASCII characters)
     latin (like default, except Latin characters are first transliterated)
 
normalize_whitespace Replaces any occurrence of whitespace with a single space.
{{ "a \n b" | normalize_whitespace }}
 

Linking with Jekyll’s link tag ensures valid URLs of your Jekyll pages (posts, pages, collection items, files) even if the permalink style to include them changes (or gets deactivated). The file extension must be included in the link tag declaration as well as its relative path starting from the root directory, e.g.,

{% link _posts/2016-07-26-name-of-post.md %}

There is an extra tag for linking to posts: The post_url tag will generate the correct permalink URL for the post you specify, so you can leave the preceding _posts/. Also, you don’t have to append the file extension. E.g.:

{% post_url 2010-07-21-name-of-post %}

Note, that if you organize your posts in subdirectories, you need to include the subdirectory path to the post (e.g., {% post_url /subdir/2010-07-21-name-of-post %}).

Advantage: The major benefit of link and post_url tags is link validation: If the link doesn’t exist, Jekyll won’t build your site and you are alerted to a broken link, that you can then fix.

Be aware: What you can’t do with link and post_url tags, is adding filters to the link tags. E.g., you can’t {% link mypage.html | append: "#section1" %} (- )to link to sections on a page, use regular HTML or Markdown linking techniques).

Jekyll’s site and page variables

The following variables are global variables recognized by your Jekyll website:

Global variable Description  
site Access to site wide information and configuration settings from _config.yml.  
page Access to page specific information and settings from its front matter. Also custom variables set via the front matter will be available from this variable.  

Site variables

Variable Description
site.time The current time (when you run the jekyllcommand).
site.pages A list of all pages.
site.posts A reverse chronological list of all posts.
site.related_posts If the page being processed is a post, this contains a list of up to ten related posts. By default, these are the ten most recent posts. For high quality but slow to compute results, run the jekyll command with the –lsi (latent semantic indexing) option (works not on GitHub Pages)
site.static_files A list of all static files (i.e. files not processed by Jekyll’s converters or the Liquid renderer). Each file has five properties: path, modified_time, name, basename and extname.
site.html_pages A subset of site.pages listing those which end in .html.
site.html_files A subset of site.static_files listing those which end in .html.
site.collections A list of all the collections (including posts).
site.data A list containing the data loaded from the YAML files located in the _data directory.
site.documents A list of all the documents in every collection.
site.categories.CATEGORY The list of all posts in category CATEGORY.
site.tags.TAG The list of all posts with tag TAG.
site.url Contains the url of your site as it is configured in the _config.yml. For example, if you set url: http://mysite.com in your configuration file, then it will be accessible in Liquid as site.url (leave off trailing forward slashes, i.e., do: url: http://mysite.com, don’t http://mysite.com/). For the development environment, there is an exception: If you are running jekyll serve in a development environment, site.url will be set to the value of host, port, and SSL-related options. This defaults to url: http://localhost:4000
site.baseurl Name of the sub-directory the site is served from. It’s not needed for most sites and can be omitted (only necessary when hosting your site in a sub-directory, e.g., as project sites on GitHub).
site.[CONFIGURATION_DATA] All the variables set via the command line and your _config.yml are available through the site variable. For example, if you have foo: bar in your configuration file, then it will be accessible in Liquid as site.foo. Jekyll does not parse changes to _config.yml in watch mode, you must restart Jekyll to see changes to variables.

Page variables

Variable Description
page.content The content of the page, rendered or un-rendered depending upon what Liquid is being processed and what page is.
page.title The title of the page.
page.excerpt The un-rendered excerpt of a document.
page.url The URL of the post without the domain, but with a leading slash, e.g. /2008/12/14/my-post.html
page.date The date assigned to the post. This can be overridden in a post’s front matter by specifying a new date/time in the format YYYY-MM-DD HH:MM:SS (assuming UTC), or YYYY-MM-DD HH:MM:SS +/-TTTT (to specify a time zone using an offset from UTC. e.g. 2008-12-14 10:30:00 +0900).
page.id An identifier unique to a document in a collection or a post (useful in RSS feeds).
page.categories The list of categories to which the post belongs. Categories are derived from the directory structure above the _posts directory. For example, a post at /work/code/_posts/2008-12-24-closures.md would have this field set to ['work', 'code']. These can also be specified in the front matter.
page.collection The label of the collection to which this document belongs. e.g. posts for a post, or puppies for a document at path _puppies/rover.md. If not part of a collection, an empty string is returned.
page.tags The list of tags to which this post belongs. These can be specified in the front matter.
page.dir The path between the source directory and the file of the post or page, e.g. /pages/. This can be overridden by permalink in the front matter.
page.name The filename of the post or page, e.g. about.md.
page.path The path to the raw post or page. Example usage: Linking back to the page or post’s source on GitHub. This can be overridden in the front matter.
page.next The next post relative to the position of the current post in site.posts. Returns nil for the last entry.
page.previous The previous post relative to the position of the current post in site.posts. Returns nil for the first entry.

When to use the {{page.baseurl}} tag


Linking to files in your main GitHub page:

When you are running a main website as a GitHub user page (<username>.github.io), no extra URL tag is necessary to define links:

Markdown:

[about page](/about.html)

HTML:

<a href="/about.html">about page</a>


Linking to a file on GitHub project pages:

When you serve your website from a subdirectory (e.g., as a project page on GitHub, say, /project_A), you need to define this subdirectory in the site.baseurl variable in the _config.yml (leave off trailing forward slashes, e.g., do: baseurl: /project_A, don’t: baseurl: /project_A/). All relative links (which are generally the most commonly used links) then have to be defined as follows:

Markdown:

[about page](/project_A/about.html)
[about page]({{ site.baseurl }}/about.html)
[about page]({{ '/about.html' | relative_url }})

HTML:

<a href="/project_A/about.html">about page</a>
<a href="{{ site.baseurl }}/about.html">about page</a>
<a href="{{ '/about.html' | relative_url }}">about page</a>

If you link to resources that require the full URL, use:

Markdown:

[about page](http://mysite.com/project_A/about.html)
[about page]({{ site.url }}{{ site.baseurl }}/about.html)
[about page]({{ '/about.html' | absolute_url }})

HTML:

<a href="http://mysite.com/project_A/about.html">about page</a>
<a href="{{ site.url }}{{ site.baseurl }}/about.html">about page</a>
<a href="{{ '/about.html' | absolute_url }}">about page</a>

References


Comments

Commenting on this post is currently disabled.

Comments on this website are based on a Mastodon-powered comment system. Learn more about it here.