Quaderno Templates: Syntax Reference

Based on Liquid for designers

There are two types of markup in Liquid: Output and Tag.

  • Output markup (which may resolve to text) is surrounded by
{{ matched pairs of curly brackets (ie, braces) }}
  • Tag markup (which cannot resolve to text) is surrounded by
{% matched pairs of curly brackets and percent signs %}

Output

Here is a simple example of Output:

Hello {{ contact.first_name }}
#=> Hello Terence

Advanced output: Filters

Output markup takes filters. Filters are simple methods that act on outputs. The first parameter is always the output of the left side of the filter. The return value of the filter will be the new left value when the next filter is run. When there are no more filters, the template will receive the resulting string.

1. Hello {{ 'tobi' | upcase }}
2. Hello tobi has {{ 'tobi' | size }} letters!
3. Hello {{ '*tobi*' | textilize | upcase }}
4. Hello {{ 'now' | date: "%Y %h" }}

Taking the third example there to demonstrate how the output flows, it follows these steps:

  1. '*tobi*' --(textify)-> <strong>tobi</strong> : textify takes Markdown and converts it to HTML, in this case turning the Markdown bold (denoted by the double * on either side of tobi) into the HTML <strong> tag.
  2. <strong>tobi</strong> --(upcase)-> <strong>TOBI</strong>: upcase simply up(per)case(s) the resulting string.
  3. And <strong>TOBI</strong> becomes your output in the final HTML document!

Standard Filters

There are many more of these powerful filters given to us for free as part of the Liquid syntax. Check them out!

  • date - reformat a date (syntax reference)
  • capitalize - capitalize words in the input sentence
  • downcase - convert an input string to lowercase
  • upcase - convert an input string to uppercase
  • first - get the first element of the passed in array
  • last - get the last element of the passed in array
  • join - join elements of the array with certain character between them
  • sort - sort elements of the array
  • map - map/collect an array on a given property
  • size - return the size of an array or string
  • escape - escape a string
  • escape_once - returns an escaped version of html without affecting existing escaped entities
  • strip_html - strip html from string
  • strip_newlines - strip all newlines (\n) from string
  • newline_to_br - replace each newline (\n) with html break
  • replace - replace each occurrence e.g. {{ 'foofoo' | replace:'foo','bar' }} #=> 'barbar'
  • replace_first - replace the first occurrence e.g. {{ 'barbar' | replace_first:'bar','foo' }} #=> 'foobar'
  • remove - remove each occurrence e.g. {{ 'foobarfoobar' | remove:'foo' }} #=> 'barbar'
  • remove_first - remove the first occurrence e.g. {{ 'barbar' | remove_first:'bar' }} #=> 'bar'
  • truncate - truncate a string down to x characters
  • truncatewords - truncate a string down to x words
  • prepend - prepend a string, e.g. {{ 'bar' | prepend:'foo' }} #=> 'foobar'
  • append - append a string, e.g. {{'foo' | append:'bar' }} #=> 'foobar'
  • minus - subtraction, e.g. {{ 4 | minus:2 }} #=> 2
  • plus - addition, e.g. {{ '1' | plus:'1' }} #=> '11'(strings), {{ 1 | plus:1 }} #=> 2
  • times - multiplication, e.g {{ 5 | times:4 }} #=> 20
  • divided_by - division, e.g. {{ 10 | divided_by:2 }} #=> 5
  • split - split a string on a matching pattern, e.g. {{ "a~b" | split:~ }} #=> ['a','b']
  • modulo - remainder, e.g. {{ 3 | modulo:2 }} #=> 1

Quaderno-specific filters

  • country_name - converts the country code to a name, in the user's language, e.g. {{ contact.country | country_name }} #=> España
  • money - converts the given number into a string based on the amount's currency, e.g. {{ document.total | money }} #=> 250 USD
  • precision - format a number to 2 decimal places, e.g. {{ item.quantity | precision }} #=> 12.00`

Tags

Tags are used for the logic in your template. New tags are very easy to code, but chances are that the built-in tags will suit for 99% of your usage.

Here is a list of currently supported tags:

  • assign - Assigns some value to a variable
  • capture - Block tag that captures text into a variable
  • case - Block tag, its the standard case...when block
  • comment - Block tag, comments out the text in the block
  • cycle - Cycle is usually used within a loop to alternate between values, like colors or DOM classes.
  • for - For loop
  • if - Standard if/else block
  • include - Includes another template; useful for partials
  • raw - temporarily disable tag processing to avoid syntax conflicts.
  • unless - Mirror of if statement

Comments

Comment is the simplest tag. It just swallows content. Use these tags to leave yourself notes - this can be very, very useful if you take a break from templating for a few days/weeks/months and then need to adjust something in the future!

We made 1 million dollars {% comment %} in losses {% endcomment %} this year

And nobody is any the wiser... Muahahaha

Note that when we are putting in editor comments in our code example on here, for clarity we mark them with a preceding # symbol.

If / Else

if / else is well-known from any programming language, and thankfully works much as it sounds in English.

Liquid allows you to write simple expressions in the if or unless (and optionally, elsif and else) clause, allowing you to say:

"if x, then show y"

And optionally you can even expand it to include an

"else show z"

or even keep the chain of "ifs" going with an

"elsif v, show w"

Here are some examples:

# This will show "Hello [User Name]" if the user has one, and otherwise it won't show anything.
{% if contact %}
  Hello {{ contact.first_name }}
{% endif %}


# This will greet either tobi, or subsequently bob, and nobody else.
{% if contact.first_name == 'tobi' %}
  Hello tobi
{% elsif contact.first_name == 'bob' %}
  Hello bob
{% endif %}


# This will show "Hello tobi or bob" if the user has either the name "tobi" or "bob", and otherwise will show nothing.
{% if contact.first_name == 'tobi' or contact.first_name == 'bob' %}
  Hello tobi or bob
{% endif %}


# Bob better hope he's got the luck of the Irish!
{% if contact.first_name == 'bob' and contact.country == 'IE' %}
  Hello old bob
{% endif %}


# This will show for anyone NOT called "tobi" (!= means "not equal to").
{% if contact.first_name != 'tobi' %}
  Hello non-tobi
{% endif %}


# Same as above, but using the "unless" syntax to make it a little clearer
{% unless contact.first_name == 'tobi' %}
  Hello non-tobi
{% endunless %}


# Check if the account has a VAT number (`null` means non-existent)
{% if account.vat_number != null %}
   Hooray! You're a super-legit busines!
{% endif %}


# Same as above (you can check if something exists by going "if x", but you don't want to do this with boolean - true/false - values generally!)
{% if account.vat_number %}
   Hooray! You're a super-legit busines!
{% endif %}


# Check for an empty array (list) of document items
{% if document.items == empty %}
   You didn't order anything!
{% endif %}


# Check if a number is greater than another number with the greater than symbol (`>`). You can also check for greater than or equal to (`>=`), less than (`<`) and less than or equal to (`<=`).
{% if document_item.quantity  > 100 %}
   You ordered all the things!
{% else %}
   Sorry, you are not my number 1 customer.
{% endif %}


# You can check if a list contains something like this:
# (document.tag_list = ['you', 'the', 'man', 'or', 'woman'])
{% if document.tag_list contains 'woman' %}
   No sexism here!
{% endif %}


# And you can check if a string contains something the same way.
# (account.full_name = 'Tony Stark')
{% if account.full_name contains 'Stark' %}
   Sorry Iron Man, we're #teamcap.
{% endif %}

Case Statement

If you need more conditions, you can use the case statement. This makes it easier to have a long chain of conditions without having to type elif so much. This is how it looks:

{% case condition %}
{% when 1 %}
hit 1
{% when 2 or 3 %}
hit 2 or 3
{% else %}
... else ...
{% endcase %}

Example:

{% case account.country %}
{% when 'US' %}
     USA! USA!
{% when 'ES' %}
    ¡Viva España!
{% else %}
     Go [insert your country here]! :D
{% endcase %}

For loops

Liquid allows for loops over collections. This saves you from the pain of repeating yourself in your template, as well as making it possible to template a document for a variable number of document items.

It looks like this:

# Selecting each item from the list, one by one, and displaying its description.
{% for item in document.items %}
  {{ item.description }}
{% endfor %}

During every for loop, the following helper variables are available for extra styling needs:

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.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:int lets you restrict how many items you get. offset:int lets you start the collection with the nth item.

# This example will limit your loop to running twice, starting at the third object (ignoring the first - offset - 2 items).
# (document.items = [1, 2, 3, 4, 5, 6] - the numbers representing item objects with all their attributes)
{% for item in array limit:2 offset:2 %}
  {{ item.description }}
{% endfor %}
# results in the descriptions of items 3 and 4 being displayed in the template.

Reversing the loop can also be done, if you're feeling fancy!

{% for item in document.items reversed %}
	{{ item.description }}
{% endfor %}

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 item in (1..item.quantity) %}
  {{ item.discount_rate }}
{% endfor %}
# results in the discount rates of items 1, 2, 3 and 4 being displayed.

Variable Assignment

You can store data in your own variables, to be used in output or other tags as desired. This is useful if you know you're going to need a certain piece of information many times.

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

{% assign special_tag = 'you' %}

{% for t in document.tag_list %}
	{% if t == special_tag %}
  		<p>Yes, that means you!</p>
	{% endif %}
{% endfor %}

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

{% assign special_tag = false %}


{% for t in document.tag_list %}
	{% if t == special_tag %}
  		{% assign special_tag = false %}
	{% endif %}
{% endfor %}

{% if special_tag %}
  <p>Boom!</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, then assigns the captured value to the given variable instead of rendering it to the screen.

{% capture item_info %}{{ item.description }} - {{ item.unit_price }}{% endcapture %}
# Now you have a ready-made string for insertion in your document!
<h1>And you ordered this super special item!</h1>
<strong>{{ item_info }}</strong>

More information

If you need more information, please refer to the official Liquid wiki and website. Those knowledgeable folks will steer you the right way!

Still need help? Contact Us Contact Us