summaryrefslogtreecommitdiffstats
path: root/content/content/shortcodes.md
blob: af90a02144282f17efe3e9c0e036775bf6faed3a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
+++
title = "Shortcodes"
weight = 40
+++

Zola borrows the concept of [shortcodes](https://codex.wordpress.org/Shortcode_API) from WordPress.
In our case, a shortcode corresponds to a template defined in the `templates/shortcodes` directory or
a built-in one that can be used in a Markdown file. If you want to use something similar to shortcodes in your templates,
try [Tera macros](https://tera.netlify.com/docs#macros).

Broadly speaking, Zola's shortcodes cover two distinct use cases:

* Inject more complex HTML: Markdown is good for writing, but it isn't great when you need add inline HTML or styling.
* Ease repetitive data based tasks: when you have [external data](@/templates/overview.md#load-data) that you
  want to display in your page's body.

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](@/content/table-of-contents.md).

## Writing a shortcode
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:

```jinja2
<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 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:

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

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

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` global functions. It might work while
running `zola serve` because it has been loaded but it will fail during `zola build`.

## Using shortcodes

There are two kinds of shortcodes:

- ones that do not take a body, such as the YouTube example above
- ones that do, such as one that styles a quote

In both cases, the arguments must be named and they will all be passed to the template.

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:

- string: surrounded by double quotes, single quotes or backticks
- bool: `true` or `false`
- float: a number with a decimal point (e.g., 1.2)
- integer: a whole number or its negative counterpart (e.g., 3)
- array: an array of any kind of value, except arrays

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.

### Shortcodes without body

Simply call the shortcode as if it was a Tera function in a variable block. All the examples below are valid
calls of the YouTube shortcode.

```md
Here is a YouTube video:

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

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

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

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 `}}`.

### Shortcodes with body
Let's imagine that we have the following shortcode `quote.html` template:

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

We could use it in our Markdown file like so:

```md
As someone said:

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

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.

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.

### Invocation Count

Every shortcode context is passed in a variable named `nth` that tracks how many times a particular shortcode has
been invoked in a Markdown file. Given a shortcode `true_statement.html` template:

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

It could be used in our Markdown as follows:

```md
{{/* true_statement(value=1) */}}
{{/* true_statement(value=2) */}}
```

This is useful when implementing custom markup for features such as sidenotes or end notes.

## Built-in shortcodes

Zola comes with a few built-in shortcodes. If you want to override a default shortcode template,
simply place a `{shortcode_name}.html` file in the `templates/shortcodes` directory and Zola will
use that instead.

### YouTube
Embed a responsive player for a YouTube video.

The arguments are:

- `id`: the video id (mandatory)
- `class`: a class to add to the `<div>` surrounding the iframe
- `autoplay`: when set to "true", the video autoplays on load

Usage example:

```md
{{/* youtube(id="dQw4w9WgXcQ") */}}

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

{{/* youtube(id="dQw4w9WgXcQ", autoplay=true, class="youtube") */}}
```

Result example:

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

### Vimeo
Embed a player for a Vimeo video.

The arguments are:

- `id`: the video id (mandatory)
- `class`: a class to add to the `<div>` surrounding the iframe

Usage example:

```md
{{/* vimeo(id="124313553") */}}

{{/* vimeo(id="124313553", class="vimeo") */}}
```

Result example:

{{ vimeo(id="124313553") }}

### Streamable
Embed a player for a Streamable video.

The arguments are:

- `id`: the video id (mandatory)
- `class`: a class to add to the `<div>` surrounding the iframe

Usage example:

```md
{{/* streamable(id="92ok4") */}}

{{/* streamable(id="92ok4", class="streamble") */}}
```

Result example:

{{ streamable(id="92ok4") }}

### Gist
Embed a [Github gist](https://gist.github.com).

The arguments are:

- `url`: the url to the gist (mandatory)
- `file`: by default, the shortcode will pull every file from the URL unless a specific filename is requested
- `class`: a class to add to the `<div>` surrounding the iframe

Usage example:

```md
{{/* gist(url="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57") */}}

{{/* gist(url="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57", class="gist") */}}
```

Result example:

{{ gist(url="https://gist.github.com/Keats/e5fb6aad409f28721c0ba14161644c57") }}