Zola borrows the concept of shortcodes from WordPress.
In our case, a shortcode corresponds to a template defined in the templates/shortcodes
directory that can be used in a Markdown file.
Broadly speaking, Zolaโs shortcodes cover two distinct use cases:
The latter may also be solved by writing HTML, however Zola allows the use of Markdown based shortcodes which end in .md
rather than .html
. This may be particularly useful if you want to include headings generated by the shortcode in the
table of contents.
If you want to use something similar to shortcodes in your templates, you can use Tera macros. They are functions or components that you can call to return some text.
Letโs write a shortcode to embed YouTube videos as an example.
In a file called youtube.html
in the templates/shortcodes
directory, paste the
following:
<div class=" " >
<iframe
src="https://www.youtube.com/embed/ ?autoplay=1 "
webkitallowfullscreen
mozallowfullscreen
allowfullscreen>
</iframe>
</div>
This template is very straightforward: an iframe pointing to the YouTube embed URL wrapped in a <div>
.
In terms of input, this shortcode expects at least one variable: id
. Because the other variables
are in an if
statement, they are optional.
Thatโs it. Zola will now recognise this template as a shortcode named youtube
(the filename minus the .html
extension).
The Markdown renderer will wrap an inline HTML node such as <a>
or <span>
into a paragraph.
If you want to disable this behaviour, wrap your shortcode in a <div>
.
A Markdown based shortcode in turn will be treated as if what it returned was part of the pageโs body. If we create
books.md
in templates/shortcodes
for example:
###
This will create a shortcode books
with the argument path
pointing to a .toml
file where it loads lists of books with
titles and descriptions. They will flow with the rest of the document in which books
is called.
Shortcodes are rendered before the pageโs Markdown is parsed so they donโt have access to the pageโs table of contents.
Because of that, you also cannot use the get_page
/get_section
/get_taxonomy
/get_taxonomy_term
global functions. It might work while
running zola serve
because it has been loaded but it will fail during zola build
.
There are two kinds of shortcodes:
In both cases, the arguments must be named and they will all be passed to the template. Parentheses are mandatory even if there are no arguments.
Lastly, a shortcode name (and thus the corresponding .html
file) as well as the argument names
can only contain numbers, letters and underscores, or in Regex terms [0-9A-Za-z_]
.
Although theoretically an argument name could be a number, it will not be possible to use such an argument in the template.
Argument values can be of one of five types:
true
or false
Malformed values will be silently ignored.
Both types of shortcode will also get either a page
or section
variable depending on where they were used
and a config
variable. These values will overwrite any arguments passed to a shortcode so these variable names
should not be used as argument names in shortcodes.
Simply call the shortcode as if it was a Tera function in a variable block.
Note that if you want to have some content that looks like a shortcode but not have Zola try to render it,
you will need to escape it by using {{/*
and */}}
instead of {{
and }}
.
Letโs imagine that we have the following shortcode quote.html
template:
<blockquote>
<br>
--
</blockquote>
We could use it in our Markdown file like so:
The body of the shortcode will be automatically passed down to the rendering context as the body
variable and needs
to be on a new line.
Note that for both cases that the parentheses for shortcodes are necessary. A shortcode without the parentheses will render as plaintext and no warning will be emitted.
As an example, this is how an aside
shortcode-with-body with no arguments would be defined in aside.html
:
<aside>
</aside>
We could use it in our Markdown file like so:
If you want to have some content that looks like a shortcode but not have Zola try to render it,
you will need to escape it by using {%/*
and */%}
instead of {%
and %}
. You wonโt need to escape
anything else until the closing tag.
Every shortcode can access some variables, beyond what you explicitly passed as parameter. These variables are explained in the following subsections:
nth
)lang
), unless called from the markdown
template filter (in which case it will always be the same value as default_language
in configuration, or en
when it is unset)colocated_path
When one of these variables conflict with a variable passed as argument, the argument value will be used.
nth
: invocation countEvery shortcode context is passed in a variable named nth
that tracks how many times a particular shortcode has
been invoked in the current Markdown file. Given a shortcode true_statement.html
template:
<p id="number "> is equal to .</p>
It could be used in our Markdown as follows:
This is useful when implementing custom markup for features such as sidenotes or end notes.
lang
: current languageNOTE: When calling a shortcode from within the markdown
template filter, the lang
variable will always be en
.
If you feel like you need that, please consider using template macros instead.
If you really need that, you can rewrite your Markdown content to pass lang
as argument to the shortcode.
Every shortcode can access the current language in the lang
variable in the context.
This is useful for presenting/filtering information in a shortcode depending in a per-language manner. For example, to display a per-language book cover for the current page in a shortcode called bookcover.md
:

page
or section
You can access a slighty stripped down version of the equivalent variables in the normal templates. The following attributes will be empty:
(Note: this is because the rendering of markdown is done before populating the sections)
A useful attribute to page
in shortcodes is colocated_path
.
This is used when you want to pass the name of some assets to shortcodes without repeating the full folders path.
Mostly useful when combined with load_data
or resize_image
.
<img alt=" " src=" " />
Here are some shortcodes for inspiration.
Embed a responsive player for a YouTube video.
The arguments are:
id
: the video id (mandatory)playlist
: the playlist id (optional)class
: a class to add to the <div>
surrounding the iframeautoplay
: when set to โtrueโ, the video autoplays on loadCode:
<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 example:
See content processing page for code and example.