444 lines
18 KiB
Markdown
444 lines
18 KiB
Markdown
+++
|
|
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:
|
|
|
|
{{ definition_list(source="@/docs/zola/predicates.yaml") }}
|
|
|
|
- `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 %}
|
|
<option value="{name}">{label}</option>
|
|
{% 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) %}
|
|
<header class="header">
|
|
<h1>{ title }</h1>
|
|
</header>
|
|
{% 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 (<br>)
|
|
- `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.
|