elf-notes/content/zola/_index.md

388 lines
14 KiB
Markdown
Raw Normal View History

+++
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 = "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 is a single binary that builds an entire web site out of a
collection of markdown documents in a folder-structured hierarchy, using a
corresponding collection of HTML templates, which in turn use a corresponding
collection of SASS collection and a collection of HTML templates. The templating
2022-06-14 01:25:11 +00:00
language is called [Tera](https://tera.netlify.app). For convenience, all the
functions defined for both Tera and Zola have been compiled into lists in this
document.
If you need anything else (Typescript built into Javascript, templates other
2022-06-14 01:25:11 +00:00
than Zola's internal, static file conversion, etc.), you'll need separate build
toolchains for those.
## Mental Model for Zola
2022-06-14 01:25:11 +00:00
Elf, a website built with Zola originates with the `content/` folder. Inside
that folder, every markdown document and every folder creates a corresponding
page in the constructed website. There are only *two* models you have to
understand Zola: *sections* and *pages*.
A *section* is a folder with a file named `_index.md` in it; note the
underscore, which signifies the section definition file. For these documents, a
[`Section` model](#section) is the default context object received by the
template. Each markdown document in the same folder, and each folder immediately
underneath this folder that has an `index.md` folder (note the lack of
underscore) is a *page* and receives the [`Page` model](#page) as the default
context.
Every markdown document has two parts: a frontmatter block, written in TOML, and
the content, written in Markdown. Whether a `section` or `page` context is
passed by default, if there is content the `.content` field will be the HTML
output of the markdown in the document.
Every folder, whether containing an `_index.md` or `index.md` file, can contain
co-located assets such a images, videos, and even Javascript. These will be
found in the `.assets` field of the context object (the use of co-located assets
in why a folder can be a page).
Whether a `Page` or a `Section`, the corresponding context object provides means
by which every template has access to the metadata (and even the content!) of
every other markdown document, arranged in the hierarchy described in the
`content` folder.
2022-06-14 01:25:11 +00:00
### Proces Recommendation
1. Design your document hierarchy first.
2. Construct your content folder to support that hierarchy.
3. Build the `Section` template for the home page.
4. Build the `Section` template for your level two sections
5. Build the corresponding `Page` templates.
6. Worry about Sass afterward
2022-06-14 01:25:11 +00:00
### Construction Recommendation
Use the `include` block more than the `extends` block. Build your websites by
composition, not inheritance with override. Ignore the way Django and everyone
else does it. Composition may result in some small amount of repetition, but
the legibility and coherency of your project will more than compensate.
## Running Zola
Zola has only a few commands:
- `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.
- `zola check` - Check that the current site is coherent
- `zola help` - This list!
## Project Layout
Zola uses a simple layout of content and support, with a single configuration
file. The configuration file has two parts: a root which controls compilation,
and an `[extra]` section that provides data and details that will be available
to all templates during compilation.
The following files and folders define a basic Zola project. Any other folders
in a zola project are ignored.
- `config.toml`: The configuration file. Uses the [TOML](https://toml.io/en/)
configuration language.
- `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
Every folder under the `content/` folder that has an `_index.md` file is
considered a *section*, presenting a table of contents or other introductory
matter. Every other markdown document in a section is considered a *page*.
Zola uses different templates for sections versus pages, and individual pages
and sections can choose alternative templates.
A folder under a section that has an `index.md` file (note the lack of
underscore prefix) is considered a *page*. This allows content writers to
supply additional assets, such as images or data files, along with the contents
of the page.
## The Templating Language
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 delimiter 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.
You can inherit and extend a block with a `super()` command:
``` jinja2
{% block stylesheet %}
{{ super() }}
{# Insert your own stylesheet HTML here #}
{% endblock %}
```
<aside>Note that using some of these templates in this document to *show* them
required the use of the Unicode "zero-width" space (Ux200B;) to prevent Tera
from interpreting them.</aside>
#### `extends`
The `extends` keyword imports one template into another. A file that `extends`
that import then provides its own overrides or extensions for blocks found in
the imported templates, 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="zola/predicates.json") }}
2022-05-13 19:18:44 +00:00
#### `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**:
{{ definition_list(source="zola/expressions.json") }}
**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:
``` jinja2
{% filter filter_name %}
...
{% endfilter %}
```
The filters provided are:
{{ definition_list(source="zola/filters.json") }}
### Functions
Only a few functions provide ad-hoc expressions in-line with template
interpretation.
- `range(end=n, start=0, [step_by=n])`: Generates an array of numbers.
- `now(datetime, utc)`: Generates the current datetime.
- `get_random(end=n, [start=0])`: Generates a random number
- `get_env(name="s", default="d")`: Returns an environment variable
- `get_page(path="p")`: Returns a the content of a page in the Zola content folder
- `get_section(path="p")`: Returns the content of a Zola section (an `_index.md`) file as an
object.
- `get_taxonomy_url(kind="taxonomy", name=page.taxonomies.category)`: Returns the URL of a Zola taxonomy index
- `get_url(path="p")`: Gets the generated URL for a document in the Zola content folder
- `get_image_metadata(path="p")`: Gets the metadata for an image in Zola's static folder
- `load_data(path="p")`: (Zola) Loads static data from a file. Understands TOML, JSON, CSV and
BibTeX. Takes either `path=` or `url=` (!) as an argument.
- `resize_image(path, width, height, op, format, quality)`: (Zola) Takes an
image, resizes the image, and provides a link to the resized image.
## Zola Content
### Sections {#section}
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`.
2022-06-14 01:25:11 +00:00
#### Section Header in every `_index.md` file
The arguments that con be placed into the TOML header of a the `_index.md` file are:
2022-06-14 01:25:11 +00:00
{{ definition_list(source="zola/section_arguments.json") }}
#### Section Object delivered to the template:
The context for a section page contains the following fields, which will be
available to the template:
2022-06-14 01:25:11 +00:00
{{ definition_list(source="zola/section_fields.json") }}
### Pages {#page}
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.
2022-06-14 01:25:11 +00:00
#### Page Header in every page file
The following items can appear in the TOML header of a page:
2022-06-14 01:25:11 +00:00
{{ definition_list(source="zola/page_arguments.json") }}
#### Page Object delivered to templates
Pages derive the following information in their context:
2022-06-14 01:25:11 +00:00
{{ definition_list(source="zola/page_fields.json") }}
### 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.