Goal: To replicate the old tags page I had in Jekyll. Here is a screenshot of that page.

Set up tags

Enable taxonomies and add “tags” as a taxonomy in the config.toml. Additionally, I’m choosing not to render taxonomy pages, because I don’t want individual tag pages.

taxonomies = [
    {name = "tags", render = false}
]

Add Zola-style tags to blog posts

Use the correct syntax in your frontmatter. Make sure to put it after any other frontmatter fields.

+++
date = 2023-08-17
title = "Setting up blog tags in Zola"
[taxonomies]
tags = ['zola', 'webdev']
+++

I wrote a Python script to convert my YAML frontmatter the above format.

My hacked-together Python script
from sys import argv
import os

for root, dirs, files in os.walk(argv[-1]):
    for name in files:
        if ".md" in name[-3:] and "20" in name[:2]: # this particular line is specific to my blog posts
            with open(os.path.join(root, name)) as yamlfile, open(os.path.join(root, name + ".toml.md"), "w") as outfile:
                count = -1
                fmlist = dict({})
                for line in yamlfile.readlines():
                    if "+++" in line: # already using TOML
                        break
                    if count > 1: # after processing frontmatter
                        print(line, end='', file=outfile)
                    elif count == 1: 
                    # after building frontmatter dict, 
                    # print out TOML-formatted frontmatter
                        print("+++", file=outfile)
                        print(fmlist["date"], file=outfile)
                        print(fmlist["title"], file=outfile)
                        print(fmlist["tags"], file=outfile)
                        print("+++", file=outfile)
                        print("", file=outfile)
                        count = count + 1
                    elif count < 1:
                    # within YAML frontmatter
                        if "---" in line: 
                            count = count + 1
                        elif "date:" in line:
                            l = line.replace(":", " =").strip()
                            fmlist["date"] = l
                        elif "title:" in line:
                            l = line.split("title: ")[1].strip()
                            if "\"" in l:
                                l = "title = " + l
                            else:
                                l = "title = \"" + l + "\""
                            fmlist["title"] = l
                        elif "tags:" in line:
                            l = "[taxonomies]\ntags = " + str([x.strip() for x in line.split(" ")[1:]])
                            fmlist["tags"] = l
                        else:
                            continue

Display tags on the blog post pages. Modify the template to include printing tags.

{% if page.taxonomies.tags %}
    {% set post_tags = page.taxonomies.tags | sort | unique(case_sensitive=false) %}
    Tags:
    {% for tag in post_tags %}
        <a href="/tag-listing#{{ tag | slugify }}">{{ tag }}</a>
        {%- if not loop.last %}{{ ", " | safe }}{% endif -%}
    {% endfor -%}
{% endif %}

Create a page for the tag listing

Create templates/tags.html.

{% extends "base.html" %}

{% block content %}
<header>
    <h2>
        Tags
    </h2>
</header>


{% set blogtags = get_taxonomy(kind="tags") %}

{% endblock content %}

Create content/tag-listing.md.

+++
title = "Tags"
template = "tags.html"
+++

List posts under each tag

{% for tag in blogtags.items %}
<h3 id="{{ tag.name | slugify }}">
    {{ tag.name }}
</h3>

<ul>
    {% for post in tag.pages %}
    <li>
        <time datetime="{{ post.date }}">{{ post.date }}</time></dt>
        &ndash;
        <a href="{{ post.permalink | safe }}">{{ post.title }}</a>
    </li>
    {% endfor %}
</ul>
{% endfor %}

Create a tag cloud

There might be a more efficient way to do this; I just hacked this together with what I know of Tera.

{# determine most and least popular tags #}
{% set tags_by_count = blogtags.items | sort(attribute="page_count") %}
{% set least_pop_tag = tags_by_count | first %}
{% set lowest_weight = least_pop_tag.page_count %}
{% set most_pop_tag = tags_by_count | last %}
{% set highest_weight = most_pop_tag.page_count %}

{# tag cloud #}
{% for tag in blogtags.items %}
<span>
    <a 
        href="#{{ tag.name | slugify }}"
        style="font-size: calc(1rem + ({{ tag.page_count }} - {{ lowest_weight }}) / ({{ highest_weight }} - {{ lowest_weight }}) * 1rem);"
        >{{ tag.name }}</a> 
        {%- if not loop.last %}{{ ", " | safe }}{% endif -%}
</span>
{% endfor %}

Et voilà! View the final result.


References: