Zola Tutorial 2: Shortcodes
· 19 min read · Views --
Last updated on

Zola Tutorial 2: Shortcodes

Author: Alex Xiang


Zola Tutorial 2: Shortcodes

Concept

Zola borrows the idea of shortcodes from WordPress. In Zola, a shortcode is a reusable template fragment that can be used inside Markdown files. Shortcode templates are usually placed under templates/shortcodes.

Shortcodes are often useful in two situations:

  • Inserting complex HTML. Markdown is good for writing, but not always convenient for embedding styled HTML.
  • Repeating data-driven tasks.

Creating A Shortcode

For example, create youtube.html under templates/shortcodes:

<div {% if class %}class="{{class}}"{% endif %}>
 <iframe
 src="https://www.youtube.com/embed/{{id}}{% if autoplay %}?autoplay=1{% endif %}"
 webkitallowfullscreen
 mozallowfullscreen
 allowfullscreen>
 </iframe>
</div>

This template renders an embedded YouTube video. It has a required id parameter and an optional class parameter. The file name, youtube, becomes the shortcode name, and Markdown files can reference it by that name.

Because Zola may wrap inline HTML nodes such as <a> or <span> into <p>, wrap the fragment in <div> if you do not want that behavior.

Now look at a shortcode implemented as Markdown. Create book.md under templates/shortcodes:

{% set data = load_data(path=path) -%}
{% for book in data.books %}
### {{ book.title }}

{{ book.description | safe }}
{% endfor %}

This book shortcode accepts a path parameter pointing to a .toml file. load_data reads the file, gets the book list, and renders it.

Shortcodes are rendered before Markdown parsing, so they do not know the structure of the final page content. If you need page or section data, Zola provides global functions such as get_page, get_section, get_taxonomy, and get_taxonomy_term. Be careful: these functions are available during zola serve, but not during zola build.

Using Shortcodes

There are two kinds of shortcode:

  • Shortcodes without a body, such as the YouTube example above.
  • Shortcodes with a body, such as a styled quote block.

For both types, parameters must be named, and all parameters used in the template must be passed. Even if there are no parameters, parentheses are still required after the shortcode name.

Shortcode names and parameter names must follow naming rules: numbers, letters, and underscores. Although parameter names can be numeric, they are usually not practical inside templates.

Parameter values can be:

  • string: wrapped in double quotes, single quotes, or backticks.
  • bool: true or false.
  • float: floating-point number.
  • integer: integer.
  • array: array containing any type except another array.

If a parameter value has invalid syntax, it is ignored.

Inside a shortcode, you can use page or section depending on where the shortcode is used. You can also use config. These names override passed parameters, so do not use them as parameter names.

Shortcodes Without A Body

For a shortcode without a body, call it like a Tera function. Example usage for the youtube shortcode:

Here is a YouTube video:

{{ youtube(id="dQw4w9WgXcQ") }}

{{ youtube(id="dQw4w9WgXcQ", autoplay=true) }}

An inline {{ youtube(id="dQw4w9WgXcQ", autoplay=true, class="youtube") }} shortcode

If you need to show text that looks like a shortcode inside a document and do not want Zola to render it, use escape syntax such as {{/* and */}} around the example.

Shortcodes With A Body

Suppose we have a quote.html shortcode template:

<blockquote>
 {{ body }} <br>
 -- {{ author}}
</blockquote>

In Markdown, use it like this:

As someone said:

{% quote(author="Vincent") %}
A quote
{% end %}

The shortcode body is automatically passed into the template as the body parameter.

Shortcodes Without Parameters

Parentheses are required for every shortcode. If a shortcode name is not followed by parentheses, it is rendered as normal text, without warning.

For example, aside.html has no parameters:

<aside>
 {{ body }}
</aside>

Use it like this:

Readers can refer to the aside for more information.

{% aside() %}
An aside
{% end %}

Shortcode Context

Besides passed parameters, a shortcode can use several variables.

nth

nth is the number of times this shortcode has been executed in the current Markdown file. For example, with true_statement.html:

<p id="number{{ nth }}">{{ value }} is equal to {{ nth }}.</p>

Usage:

{{ true_statement(value=1) }}
{{ true_statement(value=2) }}

This is useful when implementing note boxes or labels that need automatic numbering.

lang

lang is the current language. It is useful for multilingual sites:

![Book cover in {{ lang }}](cover.{{ lang }}.png)

page Or section

Compared with normal templates, shortcodes have fewer available variables. Some variables are empty because Markdown rendering finishes before section processing:

  • translations
  • backlinks
  • pages

One useful page property is colocated_path, which lets you pass a resource name without repeating the full path. For example, it can be used with load_data or resize_image:

{% set resized = resize_image(format="jpg", path=page.colocated_path ~ img_name, width=width, op="fit_width") %}
<img alt="{{ alt }}" src="{{ resized.url | safe }}" />

Examples

YouTube

Parameters

  • id: the video id, mandatory.
  • playlist: the playlist id, optional.
  • class: a class added to the <div> around the iframe.
  • autoplay: when set to true, the video autoplays on load.

Template

<div {% if class %}class="{{class}}"{% endif %}>
 <iframe src="https://www.youtube-nocookie.com/embed/{{id}}{% if playlist %}?list={{playlist}}{% endif %}{% if autoplay %}?autoplay=1{% endif %}" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
</div>

Usage

{{ youtube(id="dCKeXuVHl1o") }}

{{ youtube(id="dCKeXuVHl1o", playlist="RDdQw4w9WgXcQ") }}

{{ youtube(id="dCKeXuVHl1o", autoplay=true) }}

{{ youtube(id="dCKeXuVHl1o", autoplay=true, class="youtube") }}
<div>
{% for asset in page.assets -%}
 {%- if asset is matching("[.](jpg|png)$") -%}
 {% set image = resize_image(path=asset, width=240, height=180) %}
 <a href="{{ get_url(path=asset) }}" target="_blank">
 <img src="{{ image.url }}" />
 </a>
 {%- endif %}
{%- endfor %}
</div>