13 KiB
+++ title = "Zola" description = "Zola is a static site generator" date = 2025-05-01T18:00:00+00:00 updated = 2021-05-01T18:00:00+00:00 template = "docs/section.html" sort_by = "weight" weight = 4 draft = false +++
Zola
Zola is a static site generator written in Rust. It builds an entire web page out of a structured markdown collection and a collection of HTML templates. The templating language is called Tera.
Running Zola
Zola is a single binary.
zola init
- Starts a new Zola project. Creates the structure described in the next section, especially if you enable sass.zola serve
- Starts a localhost webserver to serve your content for demo.zola build
- Builds a Zola project into a collection of static HTML.
Project layout
The following files and folders define a basic Zola project
config.toml
: A configuration file in the TOML configuration language. Can contain a lot of information that will be made available to all pages in the system.content/
: The structured content folder.sass/
: Sass is a CSS preprocessor language that makes CSS easier.static/
: Static content such as images, fonts, and Javascripttemplates
: The HTML templates (and includes, etc) that define the website's layouts
Note that if you want to use modern Javascript features such as a precompiler like Typescript or a bundler like Webpack, that is outside the functionality of Zola. You'll have to have a separate project for that, or a subfolder or git submodule, and you'll have to have a separate build step for that.
It's also a bit of a shame that Tera is 100% an HTML play, and there's no HAML or similar HTML templating involved. That would be a nifty project.
Tera
The Tera templating language looks a lot like Django's, or for that matter any number of templating languages. Every page generated with Tera receives a context, which can be thought of as a JSON object with which to populate the page (it is, technically, a Serde::Serializable). Zola provides a large and complex context, which is explained further down.
Tera has the following syntax. Everything within these markers is processed by Tera; everything outside is left untouched.
{{
and}}
for expressions{%
and%}
for statements{#
and#}
for comments
Statements that have a dash as part of their delimeter remove all whitespace
from around the delimiter. {%-
says to eliminate all whitespace between this
statement and anything that came before it; -%}
says to eliminate everything
that comes after it.
Statements
block
The block
is probably the most important statement; it defines a chunk of
content. When a template is created, it can define its whole content as a
block, and it can define subsections (note: section is a heavily overloaded
word) of itself. These blocks can be used as-is, or replaced when another
template inherits them and overwrites them.
extends
The extends
keyword imports one template into another. A file that extends
that import then provides its own overrides for blocks found in the imported
templated, substituting its own content and processing for that of the extended
template.
set
Variables are set in a given scope with set
:
{% set my_var = "hello" %}
Sets a variable my_var
. Variables can contain booleans, floats, strings,
integers, and arrays. There is a special syntax, set_global
, that can be used
to set variables one level up in scope when working inside for
loops (i.e. in
the outer scope containing the loop, preserving its content between iterations).
if
Conditional statements are managed with if/is ... else ... endif
{% if my_var is ... %} ... {% endif %}
The list of is
tests that are shipped with Zola are:
defined
: the given variable is defined.undefined
: the given variable is undefined.odd
: the given variable is an odd number.even
: the given variable is an even number.string
: the given variable is a string.number
: the given variable is a number.divisibleby
: the given expression is divisible by the arg given.iterable
: Returns true if the given variable can be iterated over in Tera (i.e. is an array/tuple or an object).object
: Returns true if the given variable is an object (i.e. can be iterated over key, value).starting_with(string)
: Returns true if the given variable is a string and starts with the arg given.ending_with(string)
: Returns true if the given variable is a string and ends with the arg given.containing(val)
: Returns true if the given variable contains the arg given.- strings: is the arg a substring?
- arrays: is the arg one of the members of the array?
- maps: is the arg a key of the map?
matching(regexp)
: Returns true if the given variable is a string and matches the regex in the argument.
for
Arrays are iterated with the for x in array/map ... endfor
syntax.
{% for name in users %}
Hello: {{ name }}
{% endfor %}
Maps will provide a key/value pair. The names of the two fields are arbitrary:
{% for name, label in options %}
<option value="{name}">{label}</option>
{% endfor %}
Array filters (see below) are invoked before the loop. The following will print the list in reverse order.
{% for name in users | reverse %}{{ name }}{% endfor %}
Loops have continue
and break
statements that can be invoked inside if
blocks.
include
Include other content into the current template being rendered. Include strings cannot be built out of variables, but they may be a list, in which case the first filename found is rendered. If the include block has the phrase 'ignore missing' at the end a missing file will not cause an error at build time.
{% include "header.html" %}
Macros
Macros are blocks of template that can be passed variables; they're basically
just big chunks of content that can be parameterized. Macros must be defined in
a file separate from the main content and imported with a distinct syntax from
import
:
{% import "header.html" as header %}
The header macro can be invoked in that file like this:
{{ header::header("My Blog!") }}
And an example of this macro (again, in the header.html
file) would look like this:
{% macro header(title) %}
<header class="header">
<h1>{ title }</h1>
</header>
{% endmacro %}
raw
{% raw %}Content {{ goes here }}{% endraw %}
Content within the raw
block will not be processed.
Expressions
Tera's {{
... }}
syntax supports expressions, usually just evaluating the
variable. There are a few basic operations and filters available, however:
Math And Logic Expressions:
+
: adds 2 values together, {{ 1 + 1 }} will print 2-
: performs a subtraction, {{ 2 - 1 }} will print 1/
: performs a division, {{ 10 / 2 }} will print 5*
: performs a multiplication, {{ 5 * 2 }} will print 10%
: performs a modulo, {{ 2 % 2 }} will print 0==
: checks whether the values are equal!=
: checks whether the values are different>=
: true if the left value is equal or greater to the right one<=
: true if the right value is equal or greater to the left one>
: true if the left value is greater than the right one<
: true if the right value is greater than the left oneand
: true if the left and right operands are trueor
: true if the left or right operands are truenot
: negate an expressionin
: true if the left operand is inside the right container. May be combined withnot
.
Concatenation:
Strings can be concatenated with the ~
operator.
Filters:
Filters can be used to, well, filter and edit expressions. A filter is placed
at the end of an expression with a pipe between them, i.e. {{ name | upper }}
would upper-case the contents of the variable name
.
An entire chunk of HTML can be filtered by {% filter filter_name %} ... {% endfilter %}
.
The filters provided are:
lower
: Converts string to lowercaseupper
: Converts string to uppercasewordcount
: Counts the words in a stringcapitalize
: Capitalizes the first letter, lowercase the restreplace
: Takes two strings as arguments, replaces the first with the secondaddslashes
: Escapes quoted stringsslugify
: Provides a slug for the stringtitle
: Capitalizes each word in the stringtrim
: Removes leading and trailing whitespacetrim_start
: Removes leading whitespacetrim_end
: Removes trailing whitespacetrim_start_matches
: Removes leading characters that match a patterntrim_end_matches
: Removes trailing characters that match a patterntruncate
: Truncates the string to the length specifiedlinebreaksbr
: Replaces line breaks (\n or \r\n) with HTML line breaks (
)spaceless
: Remove space ( ) and line breaks (\n or \r\n) between HTML tagsstriptags
: Tries to remove HTML tags from inputfirst
: Returns the first element of an arraylast
: Returns the last element of an arraynth
: Returns the nth element of an arrayjoin
: Joins an array with a delimeterlength
: Returns the length of an array, an object, or a stringreverse
: Returns a reversed string or arraysort
: Sorts an array into ascending order. You can sort objects by providing a fieldname argumentunique
: Removes duplicate items from an array. You can filter objects by providing a fieldname argumentslice
: Slices an array by the given start and end parametergroup_by
: Groups an array using the required attribute argumentfilter
: Filters the array values, returning objects whose attribute is equal to the argumentmap
: Retrieves an attribute from each object in an arrayconcat
: Appends values to an arrayurlencode
: Performs classic (%-based) URL encodingurlencode_strict
: Encodes URLs, including any slashespluralize
: Can return an alternative text if the argument is greater than oneround
: Returns a number roundedfilesizeformat
: Generates human-readable sizes for integersdate
: Parses a timestamp into a date(time) stringescape
: Escapes a string's HTMLescape_xml
: Escapes XML special characterssafe
: Marks a variable as safe: HTML will not be escapedget
: Accesses a value from an object when the key is not a valid identifier.split
: Splits a string into an array of strings, separated by a pattern.int
: Converts a value into an integer.float
: Converts a value into a float.json_encode
: Transforms a value into its JSON representationas_str
: Returns a string representation of the value.default
: Provides a default value if the name is not present in the contextmarkdown
: Converts the variable contents from markdown to HTMLbase64_encode
: Encode the variable to base64base64_decode
: Decode the variable from base64num_format
: Format a number in a variety of ways
Functions
Only a few functions provide ad-hoc expressions in-line with template interpretation.
range
: Generates an array of numbers.now
: Generates the current datetimeget_random
: Generates a random numberget_env
: Returns an environment variableget_page
: Returns a the content of a page in the Zola content folderget_section
: Returns the content of a Zola section (an_index.md
) file as an object.get_taxonomy_url
: Returns the URL of a Zola taxonomy indexget_url
: Gets the generated URL for a document in the Zola content folderget_image_metadata
: Gets the metadata for an image in Zola's static folderload_data
: (Zola) Loads static data from a file. Understands TOML, JSON, CSV and BibTeX. Takes eitherpath=
orurl=
(!) as an argument.resize_image
: (Zola) Takes an image, resizes the image, and provides a link to the resized image.
Zola Content
Sections
In Zola, every folder under ./content/
(including that folder itself) is
potentially a section. Sections are basically Zola's version of the WWW
index
protocol. A section is defined by the presence of an _index.md
file
which contains both a TOML header (separated by +++
above and below), and by
some optional content. The TOML header may specify which template to use to
render the section info, otherwise Zola falls back to the default at
./templates/section.html
.
The context for a section page contains the following fields, which will be available to the template:
content
: The content of the_index.md
filetitle
: The Title found in the TOML part of_index.md
description
: (optional): The descriptionpath
: As provided by Zolacomponents
: The path, split into atomspermalink
: The URL for this pageextra
: The contents of the TOML's[extra.*]
blocks.pages
: An array of all child pages in this same folder.subsections
: An array of all child sections in this same folder.toc
: An array ofHeader
objects: id, title, permalink, children (Which is itself an array ofHeader
objects)word_count
: Unicode-smart.reading_time
: Number;assets
: An array of assets available in this section.ancestors
: An array of parent paths, with the root being the last one.
Pages
A page is either a markdown file within the same folder as its section, or it
is in index.md
(note the lack of prefix underscore!) file in a separate
folder. The latter syntax is preferred if the file has associated assets, such
as javascript or images.