--- title: "Adding categories to Eleventy" date: 2022-05-28T00:00:00 slug: adding-categories-to-eleventy --- I've decided to put a bit more love into this blog, I've neglected it since the new year. As part of that, I wanted to make a few more changes - namely, I wanted some better navigation to allow me to write different types of content. So, I've added a little category list to the site to allow people to search by different tags. ## Organising posts First of all, to identify blog posts, I use a single tag: `posts`. I use an `11tydata.json` file in my posts directory that looks like this to ensure every post is automatically tagged correctly: ```javascript { "tags": [ "posts" ], "permalink": "post/{{ title | slug }}/", "layout": "post.njk" } ``` I also have a `draft` tag, that I use to un-publish posts that I'm working on without needing to keep WIP on one machine. I'll assume that any other tag that an item in the `posts` collection has is it's category, and that a post can have multiple categories. ## Getting the category list So, to generate a list of categories and the number of posts in each category, I've added a [simple custom collection](https://www.11ty.dev/docs/collections/#collection-api-methods) to my site, called `categories`. Here's the code: ```javascript eleventyConfig.addCollection('categories', (collectionApi) => { const posts = collectionApi .getFilteredByTag("posts") .filter(p => !p.data.tags.includes("draft")); return posts.reduce((tags, post) => { post.data.tags.filter(tag => tag !== 'posts').forEach(tag => { if (!tags[tag]) { tags[tag] = 0; } tags[tag]++; }); return tags; }, {"All posts": posts.length}) }); ``` It's fairly simple, even if Javascript's `reduce` is a callback-headache. All we're doing is getting all of the items in the `posts` collection, removing anything tagged as a draft post, and then for each tag we're first checking if the tag already exists. If it doesn't exist, we initialise it in our tags object with a count of 0. Then, we increment the tag count by 1. We then also add an extra tag called `All posts`, which is the total count of the `posts` object. The output of this function is an object that looks like this: ```javascript { "All posts": 10, "frontend": 3, "backend": 2, "recipes": 4, "books": 1 } ``` ## Displaying categories Listing the categories is easy, we just need to use our new collection: {% raw %} ```html ``` {% endraw %} To actually display a category, [Eleventy has an easy guide for this](https://www.11ty.dev/docs/quicktips/tag-pages/). We just need a bit of customisation to use our blog layout, filter out tags such as drafts, and the categories themselves, and then set our permalink: {% raw %} ```yaml --- pagination: data: collections size: 1 alias: tag filter: - draft - categories - all permalink: /blog/category/{{ tag }}/ layout: blog.njk eleventyComputed: pageTitle: Posts Tagged "{{ tag }}" title: Lewis Dale's Blog --- {% set taglist = collections[ tag ] %} {% for post in (taglist | filterDrafts | sortedByDate) %} {% include "components/blogpost.njk" %} {% endfor %} ``` {% endraw %} And that's pretty much it! There's probably still some work to be done with paginating the tags once I have enough posts to need it.