+++
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
[taxonomies]
documentation=["Reference"]
categories=["Web Development", "Static Site Generation", "Zola"]
+++
[Zola](https://getzola.org) is a static site generator written in
[Rust](../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](https://tera.netlify.app).
## 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](https://toml.io/en/)
configuration language. Can contain a lot of information that will be made
available to *all* pages in the system.
- `content/`: The structured content folder. All your "living" stuff goes here.
- `sass/`: [Sass](../sass) is a CSS preprocessor language that makes CSS easier.
- `static/`: Static content such as images, fonts, and Javascript
- `templates`: 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](https://serde.rs/)). 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`:
```jinja2
{% 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`
```jinja2
{% 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.
```jinja2
{% for name in users %}
Hello: {{ name }}
{% endfor %}
```
Maps will provide a key/value pair. The names of the two fields are arbitrary:
```jinja2
{% for name, label in options %}
{% endfor %}
```
Array filters (see below) are invoked before the loop. The following will print
the list in reverse order.
```jinja2
{% 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.
```jinja2
{% 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`:
```jinja2
{% import "header.html" as header %}
```
The header macro can be invoked in that file like this:
```jinja2
{{ header::header("My Blog!") }}
```
And an example of this macro (again, in the `header.html` file) would look like this:
```jinja2
{% macro header(title) %}
{ title }
{% endmacro %}
```
#### `raw`
```jinja2
{% 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 one
- `and`: true if the left and right operands are true
- `or`: true if the left or right operands are true
- `not`: negate an expression
- `in`: true if the left operand is inside the right container. May be combined
with `not`.
**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 lowercase
- `upper`: Converts string to uppercase
- `wordcount`: Counts the words in a string
- `capitalize`: Capitalizes the first letter, lowercase the rest
- `replace`: Takes two strings as arguments, replaces the first with the second
- `addslashes`: Escapes quoted strings
- `slugify`: Provides a slug for the string
- `title`: Capitalizes each word in the string
- `trim`: Removes leading and trailing whitespace
- `trim_start`: Removes leading whitespace
- `trim_end`: Removes trailing whitespace
- `trim_start_matches`: Removes leading characters that match a pattern
- `trim_end_matches`: Removes trailing characters that match a pattern
- `truncate`: Truncates the string to the length specified
- `linebreaksbr`: Replaces line breaks (\n or \r\n) with HTML line breaks ( )
- `spaceless`: Remove space ( ) and line breaks (\n or \r\n) between HTML tags
- `striptags`: Tries to remove HTML tags from input
- `first`: Returns the first element of an array
- `last`: Returns the last element of an array
- `nth`: Returns the nth element of an array
- `join`: Joins an array with a delimeter
- `length`: Returns the length of an array, an object, or a string
- `reverse`: Returns a reversed string or array
- `sort`: Sorts an array into ascending order. You can sort objects by providing a fieldname argument
- `unique`: Removes duplicate items from an array. You can filter objects by providing a fieldname argument
- `slice`: Slices an array by the given start and end parameter
- `group_by`: Groups an array using the required attribute argument
- `filter`: Filters the array values, returning objects whose attribute is equal to the argument
- `map`: Retrieves an attribute from each object in an array
- `concat`: Appends values to an array
- `urlencode`: Performs classic (%-based) URL encoding
- `urlencode_strict`: Encodes URLs, including any slashes
- `pluralize`: Can return an alternative text if the argument is greater than one
- `round`: Returns a number rounded
- `filesizeformat`: Generates human-readable sizes for integers
- `date`: Parses a timestamp into a date(time) string
- `escape`: Escapes a string's HTML
- `escape_xml`: Escapes XML special characters
- `safe`: Marks a variable as safe: HTML will not be escaped
- `get`: 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 representation
- `as_str`: Returns a string representation of the value.
- `default`: Provides a default value if the name is not present in the context
- `markdown`: Converts the variable contents from markdown to HTML
- `base64_encode`: Encode the variable to base64
- `base64_decode`: Decode the variable from base64
- `num_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 datetime
- `get_random`: Generates a random number
- `get_env`: Returns an environment variable
- `get_page`: Returns a the content of a page in the Zola content folder
- `get_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 index
- `get_url`: Gets the generated URL for a document in the Zola content folder
- `get_image_metadata`: Gets the metadata for an image in Zola's static folder
- `load_data`: (Zola) Loads static data from a file. Understands TOML, JSON, CSV and
BibTeX. Takes either `path=` or `url=` (!) 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 arguments that con be placed into the TOML header of a the `_index.md` file are:
- `title`: a string
- `description`: a string
- `draft`: `true`/`false` if this section should be included in builds
- `sort_by`: Sorting function to use: `date`, `title`, `weight`, or `none`
- `weight`: Used to provide subsection weight to a parent section
- `template`: The template to render this section. Defaults to `./templates/section.html`
- `page_template`: The default template to render pages in this section. Pages with this field specified overide this setting
- `paginate_by`: Number of pages to paginate by. Set to `0` for no pagination
- `paginate_path`: The prefix for paginations. Default to "page"
- `paginate_reversed`: boolean
- `insert_anchor_links`: One of `left`, `right`, or `none`. Specifies whether an anchor-link should be provided for every header item. Probably overridable by the template.
- `in_search_index`: Include this section in the search index. Only matters if search is enabled
- `transparent`: `true`/`false`, specifies if this section should be inherited by the parent
- `aliases`: An array of paths to redirect to this folder
- `[extra]`: Your extra data block
The context for a section page contains the following fields, which will be
available to the template:
- `content`: The content of the `_index.md` file
- `title`: The Title found in the TOML part of `_index.md`
- `description`: (optional): The description
- `path`: As provided by Zola
- `components`: The path, split into atoms
- `permalink`: The URL for this page
- `extra`: 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 of `Header` objects: id, title, permalink, children (Which is itself
an array of `Header` 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 a subfolder with a file named `index.md` (note the lack of prefix
underscore!). The latter syntax is preferred if the file has associated assets,
such as JavaScript or images, that you want to load alongside the content within
the markdown page.
The following items can appear in the TOML header of a page:
- `title`: The title of this page.
- `description`: A description of this page
- `date`: Date this page was published
- `updated`: Date this page was updated
- `weight`: A number, used for sorting
- `draft`: Boolean. Specifies if this page should be rendered at build time
- `slug`: String. The slug Zola should use when generating the URL
- `path`: A manually specified absolute path to this content
- `aliases`: An array of former urls that lead here, to redirect people here
- `in_search_index`: If set to false and search is enabled, this page will not be included
- `template`: The template used to render this page. Defaults to `./templates/page.html`
- `[taxonomies]`: The taxonomies for this page
- `[extra]`: Your own extra data
Pages have the following information in their context:
- `content`: The markdown content from the page's file
- `title`: The title, if present in the TOML block
- `description`: The description
- `date`: The date this file was added
- `updated`: The date this file was last updated
- `slug`: The slug name of this file
- `path`: The path to this file
- `draft`: true/false, will tell Zola not to include this file during builds
- `components`: The path, split by '/'
- `permalink`: The URL Zola generates for this file
- `summary`: A provided string
- `taxonomies`: The taxonomies list, if any
- `extra`: The extras block
- `toc`: An array of `Header` objects as derived from the Markdown
- `word_count`: A naive word count
- `reading_time`: A primitive reading time, in minutes
- `earlier`: The content of the previous page, if the section header entry 'sort_by' is set to 'date.'
- `later`: The content of the next page
- `heavier`: The content of the previous page, if the section header entry 'sort_by' is set to 'weight'
- `lighter`: The content of the next page
- `year`: Year as a number.
- `month`: Month as a number.
- `day`: Day as a number.
- `assets`: An array of assets available to this page.
- `ancestors`: An array of parent paths, with the root being the last one.
### Pagination
Pagination is provided by a `Paginator` object available to the section page.
The paginator will automatically generate multiple pages for the section, and
will provide links to earlier/later pages within the collection.
### Shortcodes
Shortcodes are chunks of HTML or Markdown that you can store in the
`./templates/shortcodes` folder. Shortcodes will be processed for variables, and
Zola will create a corresponding named hook that will take those variables as
named parameters, much like a Tera function, and return the processed HTML.
### Internal links
The relationship between a Markdown file and its generated content is
deterministic, but not always readily apparent. If you want to link to content
in another markdown file, you can use the link syntax `[my
link](@/pages/about.md#example-code)`, which will generate a URL to the generated
copy of that page, and will provide a header link to the header entitled
"Example Code".
### Taxonomies
Taxonomies are a primitive organizational mechanism. You can create a list of
taxonomies in the `config.toml` file, and then provide entries for those
taxonomies in pages; those pages will then be included in the `taxonomies`
collection. The Taxonomy pages are generated with list of various taxonomies
and the collections of pages that relate to the taxonomy.