I’m overwhelmed by the templating language. Can someone help me migrate my site?
I’m looking to migrate my plain HTML site to Zola, but I’m very new to the templating language, and the default setup described in the introduction to Zola was not clear on how to support URLs with the pattern /2025/07/07/title-of-article/.
Additionally, the blog homepage is hosted at /posts/ while archives are in /2025/. Articles are not inside /posts/ as the documentation on /blog/ had assumed.
Currently, my Zola branch builds, but everything is just shoved into static/. I have no idea on how to get /posts/ to update on the site, especially as I start adding articles in Markdown in the content/ directory.
Also, /posts/ and /2025/07/ list the weekday it was posted on. Not sure how to generate that with the templating language.
Hi,
I understand that you have trouble understanding all the rules, Zola (and most other SSGs) are quite a beast!
Zola will preserve the hierarchy of your content folder.
So if you want to have a page at in example.com/2025/07/12/hello-world/, you’ll have to have a file at the path content/2025/07/12/hello-world.md.
Now, the problem is that each subdirectory is a Section in Zola, so each of your posts will be in a sub-sub-subsection of your index page. (Also, each folder must have an _index.html for Zola to recognize it as a section).
I wrote (just for you!) a minimal template/index.html page that hides to the visitor this Zola-internal concept of sections, by listing all pages in all sub-sub-subsections:
{% for sub in section.subsections %}
{% set sub = get_section(path=sub) %}
{% for ssub in sub.subsections %}
{% set ssub = get_section(path=ssub) %}
{% for sssub in ssub.subsections %}
{% set sssub = get_section(path=sssub) %}
{% for page in sssub.pages %}
<p>
<a href="{{ page.path }}">{{ page.date }}: {{ page.title }}</a>
</p>
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
An alternative is to think in Zola and put all your articles at the root of content.
They’ll live at the root of the website to, but you can preserve existing links by adding “orphan pages” (pages in content/year/month/day/, but without _index.html) that just redirect to the new page location with simple html: Redirect to an external site on page load? - #3 by zolappom
each of your posts will be in a sub-sub-subsection of your index page
OP might also investigate the transparent flag from Section’s front matter:
# If set to "true", the section will pass its pages on to the parent section. Defaults to `false`.
# Useful when the section shouldn't split up the parent section, like
# sections for each year under a posts section.
transparent = false
I’m using this, with year folders just to manage content files, and it works fine. By default it doesn’t generate page listings at the subfolder level though, since these aren’t real sections, and you might have to do some filtering of the containing real section to achieve this if you want it.
caleb@miller:~/Documents/calebh.top$ git checkout zola
Switched to branch 'zola'
Your branch is up to date with 'origin/zola'.
caleb@miller:~/Documents/calebh.top$ zola build
Building site...
Error: Failed to build the site
Error: Error parsing templates from the /templates directory
Error: Reason:
* Failed to parse "/home/caleb/Documents/calebh.top/templates/post.html"
--> 3:5
|
3 | <h1>{% page.title %}</h1>
| ^---
|
= unexpected tag; expected end of input, a macro definition tag (`{% macro my_macro() %}`, or some content
caleb@miller:~/Documents/calebh.top$
The problem with this is that every article must have a different title. There is too much of a chance for a title collision.
To your first point: you need to be using the {{ page.title }} syntax to evaluate expressions rather than the {% blah %} syntax used in both content files to e.g. invoke shortcodes and in template files to do e.g control flow. I struggled with this at the start too. Zola docs kind of have this unstated assumption that you already know the Tera templating language (or the Jinja it’s based on) but never explicitly list it as prerequisite knowledge, more as an optional extra. I think this is a bit misleading unless you’re never going even slightly off-piste.
EDIT: forgot to add, to your second point, you could prefix your content filenames and titles with a yyyyMMdd date prefix to disambiguate. (Don’t use yyyy-MM-dd, that triggers special handling to infer page date and use the rest of the filename for the output path, so you’d get collisions again. This is covered in the Page docs. You can manually override the slug in the page front matter if you really want a different format.)
I don’t think there’s a way to automatically qualify output paths with the page date.