Building Nav without defining entries in the config file

I’m writing a template and I’d like to loop over the folders/sections on my top level to generate the entries in my nav. I’m not actually sure if this is possible, because every template I look at seems to have them entered manually into the config file.

I thought the answer might be using get_section, but I can’t seem to do that for the root/top level path.

This seems like something that people would have tried to do before, is this just a known issue in Zola? Or is there a reason people want to define each section by hand rather than building it from the folder structure?

EDIT: I ran into a very similar problem when I decided to ignore this and move onto the next step, which was editing the main page to show each section. Specifically the docs here, for pagination, seem to imply I can paginate the index.html. I put the following in my index.html but I can’t get it to spit out my subsections. I also tried .subsections instead of .pages but then the variables for permalink and title did not work.

  {% for page in paginator.pages %}
  <li><a href="{{ page.permalink | safe }}">{{ page.title }}</a></li>
  {% endfor %}

I feel like I’m missing something very basic here.

Zola is pretty powerful once you’ve spent some time with it, but it’s kind of inscrutable out of the box. It does take some time to understand how to use it effectively so don’t be disheartened, you’ll get the hang of it eventually.

There’s lot of ways to answer your question, here’s some example code I use quite frequently:

<ul class="navbar-links">
	{% set tree = get_section(path="_index.md") %}
	{% for node in tree.subsections  %}
		{% set subsection = get_section(path=node) %}
		{% if not subsection.extra.menuhide %}
			<li class="{% if '/' ~ subsection.components[0] in current_url %}active{% endif %}">
				<a href="{{subsection.permalink}}">{{ subsection.title | safe }}</a>
			</li>
		{% endif %}
	{% endfor %}
</ul>

Note that the conditional {% if not subsection.extra.menuhide %} is used here to allow me to selectively hide items form the navigation. If you add a menuhide = true option to the [extra] part of the frontmatter for the section, then it won’t show up in your navigation.

The bit of code in the class attribute will add an “active” class to the <li> element when you’re viewing any pages in that section.

I’m not sure if I had used subsections before but that seems to be the ticket. Where would I have found this in the docs?

I was also expecting to use something like node.next to build spacers, “if there’s another node then put a spacer here” kind of logic. But in this case I had to use “if not loop.last”, which took me a moment when looking at the Tera docs because I was expecting it to be “node”, not “loop”.

I made some more progress but realized the asset colocation didn’t behave the way I expected it to. I want my site to be laid out in a similar structure to the example on the documentation overview page , with each post within a blog being it’s own markdown file inside the folder for the blog. But if I want to use markdown shorthand for images, ![](image.png), it expects that image to be within a subfolder, i.e. content / blog / post.md for the post itself, but content / blog / post / image.png for the asset.

My end goal was to basically use Obsidian as a frontend for writing and editing posts and Zola (and Tera) doing the heavy lifting, but creating sub directories for posts makes doing that a lot harder. I still think I’m misunderstanding something, I seem to have been struggling with the docs more than I would expect, but based on what I’m seeing I don’t think Zola is going to work for my use case at all.

You do not need to colocate the media files inside a folder in the content/ directory.
You can also put them in a mirror directory below static/
E.g.:

content / blog / post.md for the post itself, but

static / blog / post / image.png for the asset.

“Zola is pretty powerful once you’ve spent some time with it, but it’s kind of inscrutable out of the box.”

I found LLMs invaluable to quickly find how to do things in Zola (e.g: ChatGPT, Gemini, Zai, Claude…)

Of course, they can be wrong, so do not believe fully what they said. But they are super useful as a kind of brainstorm, where you discuss with somebody that can steer you on the right direction, even if his memory is not very accurate, and wrong on the details.

Just having the AI give you the proper name to search for in the docs is a huge time saver.

E.g: «I was expecting it to be “node”, not “loop”.»

For plummmm :

Just try to type your first sentence into your favorite LLM:

«In Zola, I’m writing a template and I’d like to loop over the folders/sections on my top level to generate the entries in my nav.»

Obsidian has no way out of the box to re-create the directory structure in another folder. I either have to create a subfolder, or mirror the folder structure in my static directory.

I could do either of these things by extending Obsidian I’m sure, but my goal was to get Zola to fit to Obsidian rather than the other way around. This is, admittedly, the failure of me not quite understanding how asset colocation worked when I first read the docs. But I don’t quite understand why one would have the structure of folder for a blog post list, markdown files per post, and then not allow to colocate the files in the same folder as the markdown files. A bit messy? Yeah sure, so is a ton of markdown file posts with filenames that don’t have to match the actual post title or slug. Let me drop my images in there too.

“my goal was to get Zola to fit to Obsidian”

Personally, I chose Zola rather than, say, Hugo because it was powerful (you can do a lot with it) but opinionated (you have to do it its way internally). This Opinionated / Prescriptive / Rigid / Cohesive design is for me an important feature that brings many benefits down the road.

Did you consider just coding a converter from Obsidian to a Zola hierarchy. Or using a more flexible SSG?

This said, you can co-locate:

content / blog / post / index.md for the post itself, and

content / blog / post / image.png for the asset.

The variables I used in the example (tree and node) are arbitrary. You can use anything you like. loop on the other hand is an internal variable generated invisibly by Zola and available in any for loop. See the Tera documentation about For for more info.

I’ve not used Obsidian for a while, but I’m not sure I see the problem you describe. If you point Obsidian to your root Zola content folder as your vault, doesn’t it all “just work” automatically? I tried this a couple of years back and don’t recall running into any problems with image locations.

Are you usign wikilinks by any chances? I made a PR to support it (Add support for wikilinks by Keats · Pull Request #3116 · getzola/zola · GitHub) but no one to actually check if it works as expected.