Add dynamic post tag pages

Apr 3, 2024

I want a way for users to be able to find posts based on topic. To do this, I used a dynamic tag page.

I can add tags to the front matter at the top of each post, something like:

layout: main.njk
title: Add dynamic post tag pages
tags: 
    - post
    - 11ty

I then took the examples from the official 11ty site and modified them slightly to use my pre-existnig templates, and to pare down the features a bit. I now have two new pages: tags.md and tags-list.md.

Tags.md looks like this:


---
pagination:
  data: collections
  size: 1
  alias: tag
  filter:
    - all
    - post
    - posts
    - tagList
  addAllPagesToCollections: true
layout: collection.njk
eleventyComputed:
  title: Tagged “{{ tag }}permalink: /tags/{{ tag | slugify }}/
---

{% set postslist = collections[ tag ] %}

{% for post in postslist | reverse %}
	<li>
		<a href="{{ post.url }}">{{ post.data.title }}</a>
		 - {{ post.date | postDate }}
	</li>
{% endfor %}

<p>See <a href="/tags/">all tags</a>.</p>

Related, I found how to display code in blocks without having to remove curly braces by using %raw% and %endraw% tags. Neat! Thanks to this blog post.

Anyways, the code for the tags listing is very similar to the code for my post list page. In fact, I could easily make the overall post list into a special case of tag listing, but that's not important to me right now.

This generates pages like /tags/11ty/index.html, but it doesn'ts do just /tags/. Instead, that's handled by tags-list.md, here:


---
layout: collection.njk
permalink: /tags/
title: Tags
---

<ul>
{% for tag in collections.all | getAllTags | filterTagList %}
	{% set tagUrl %}/tags/{{ tag | slugify }}/{% endset %}
	<li><a href="{{ tagUrl }}" class="post-tag">{{ tag }}</a></li>
{% endfor %}
</ul>

I then went back and added tags to each of my old posts, and added a navigation tag to the tags index page, as described in my navbar post.

This also involved a few new filters, shamelessly stolen from the 11ty starter blog project:


  eleventyConfig.addFilter("getAllTags", collection => {
		let tagSet = new Set();
		for(let item of collection) {
			(item.data.tags || []).forEach(tag => tagSet.add(tag));
		}
		return Array.from(tagSet);
	});
    
  eleventyConfig.addFilter("filterTagList", function filterTagList(tags) {
		return (tags || []).filter(tag => ["all", "nav", "post", "posts"].indexOf(tag) === -1);
	});