Zola Tutorial 3: Navigation
· 14 min read · Views --
Last updated on

Zola Tutorial 3: Navigation

Author: Alex Xiang


Zola Tutorial 3: Navigation

Zola automatically generates a unique ID for each Markdown heading. If slugify.anchors is set to on, which is the default, Zola creates the ID by converting the heading text into a slug.

If slugify.paths = "safe", spaces in generated IDs are replaced with underscores, and characters such as #, %, <, >, [, ], (, ), `, ^, {, |, and } are removed. If slugify.paths = "off", Zola does not apply this processing, but the generated ID may become invalid. Duplicate headings get a numeric suffix.

Examples:

# Something exciting! <- something-exciting
## Example code <- example-code

# Something else <- something-else
## Example code <- example-code-1

You can also assign a custom ID and CSS classes to a heading:

# Something manual! {#manual .header .bold}

This is useful for stable deep links. Changing a heading title does not have to break an existing link if you keep the manual ID.

Zola can insert anchor links next to headings. This is controlled by insert_anchor_links in a section front matter. Valid values include "left", "right", "heading", and "none".

The default template is simple:

<a class="zola-anchor" href="#{{ id }}" aria-label="Anchor link for: {{ id }}"> </a>

Variables available in the template include:

  • id: the generated heading ID
  • lang: current language
  • level: heading level, from 1 to 6

If insert_anchor = "heading" is used, the template file is still read, but only the <a> tag is extracted.

Because linking to other pages and headings is common, Zola adds a special Markdown link format. Prefix the target with @/, and point to a Markdown file relative to the content directory:

[my link](@/pages/about.md)
[my link](@/pages/about.md#example)

Invalid internal links are errors by default. If you want them to become warnings, set internal_level = "warn" under [link_checker] in config.toml. Still, broken internal links cannot be correctly resolved and may be rendered as raw HTML links.

Table Of Contents

Each page and section automatically gets a table of contents based on Markdown headings. Templates can access it through page.toc or section.toc.

toc is an array of headers. Each header contains:

level: 1 | 2 | 3 | 4 | 5 | 6
id: String
title: String
permalink: String
children: Array<Header>

A two-level table of contents can be rendered like this:

{% if page.toc %}
 <ul>
 {% for h1 in page.toc %}
 <li>
 <a href="{{ h1.permalink | safe }}">{{ h1.title }}</a>
 {% if h1.children %}
 <ul>
 {% for h2 in h1.children %}
 <li>
 <a href="{{ h2.permalink | safe }}">{{ h2.title }}</a>
 </li>
 {% endfor %}
 </ul>
 {% endif %}
 </li>
 {% endfor %}
 </ul>
{% endif %}

Taxonomies

Zola has built-in support for taxonomies, which are used to group content.

  • Taxonomy: a grouping category, such as Director or Genre
  • Term: a group inside a taxonomy
  • Value: the content item assigned to a term

For a movie site, useful taxonomies might include:

  • Director
  • Genres
  • Awards
  • Release year

Zola can generate a taxonomy list at build time. Each taxonomy contains terms, and each term contains pages. For example, the Release year taxonomy might contain both 2003 and 2017, and the 2017 term might include movies such as The Shape of Water and Bright.

Taxonomy Configuration

A taxonomy has several common properties:

  • name: usually appears in the URL
  • paginate_by: enables pagination for taxonomy terms
  • paginate_path: path prefix for pagination, such as page/1
  • feed: generates a feed for each term
  • lang: used for multilingual sites
  • render: if false, pages for the taxonomy or term are not rendered

Single-language configuration:

taxonomies = [
 { name = "director", feed = true },
 { name = "genres", feed = true },
 { name = "awards", feed = true },
 { name = "release-year", feed = true },
]

Multilingual configuration:

taxonomies = [
 { name = "director", feed = true },
 { name = "genres", feed = true },
 { name = "awards", feed = true },
 { name = "release-year", feed = true },
]

[languages.fr]
taxonomies = [
 { name = "director", feed = true },
 { name = "genres", feed = true },
 { name = "awards", feed = true },
 { name = "release-year", feed = true },
]

After configuration, add taxonomy data in content:

+++
title = "Shape of water"
date = 2019-08-15

[taxonomies]
director = ["Guillermo Del Toro"]
genres = ["Thriller", "Drama"]
awards = ["Golden Globe", "Academy award", "BAFTA"]
release-year = ["2017"]
+++

Taxonomy names are not slugified in paths. Terms are slugified according to slugify.taxonomies. Taxonomy names are case-insensitive, and terms with the same slug are merged. Pages and sections that share the same tag appear under the same taxonomy.