Add Series Taxonomy to Hugo Theme

In this post, I will show you how to implement a series taxonomy in a Hugo-based theme. The presented solution is based on Hugo’s built-in support for user-defined groupings of content. With this post, I am starting a new series called “Hugo Theme Recipes”, where I will share various how-tos on adding new features to a Hugo-based theme or enhancing existing ones.

As per Hugo’s documentation, a taxonomy is defined as follows:

a categorization that can be used to classify content

Hugo provides native support for taxonomies, including two default ones: tags and categories. This means that no matter what theme you choose for your website, tag and category taxonomies will be automatically generated by Hugo.

Taxonomy is structurally defined using terms and values where the term is a key within the taxonomy, and the value is a piece of content assigned to a term. Using the tags taxonomy as an example, content relationships can be displayed as follows:

Taxonomy  "Tag"
Term        "Hugo"
Value         "Start Blogging With Hugo, GitHub and Netlify"
Value         "Add Favicon to Hugo-Based Website"
Value         "Manage Environment-Specific Settings for Hugo-Based Website"

The example above presents content relationships from the taxonomy’s perspective. Here is how it looks from the perspective of the content:

Value     "Start Blogging With Hugo, GitHub and Netlify"
Taxonomy    "Tags"
Term          "Hugo"
Term          "GitHub"
Term          "Netlify"

Usually, when you publish a series of articles, it’s a good practice to add links to the next and previous articles at the end of an article that is part of the series. Instead, I opted for listing all articles in the series. Therefore, every time a new post in the series is published, I have to manually add a link to the newly published article in every previously published series’ article.

One solution to this problem might be to create a shortcode to encapsulate such a list of article links. With this approach, you add this shortcode to the end of each series’ article, and when a new article is published, you only need to update the shortcode. Then every time you start a new series, you have to create its proper shortcode.

But it is possible to parameterize such a shortcode by passing the series’ name as an argument. In this case, the content should be somehow classified so that we can retrieve the corresponding articles. To help us group such content, we can implement the series taxonomy.

Now let’s take a closer look at the implementation details. The source code is available in this commit, which I made to the Bilberry Hugo theme.


Before using the series taxonomy, it should be defined in the site config file(e.g., config.toml) by providing singular and plural labels:

  tag = "tags"
  category = "categories"
  series = "series"

Please note that if you want to continue using tags and categories default taxonomies, you should explicitly define them in the config file.

Taxonomy template

The layouts/_default/series.terms.html file is the series taxonomy template. Hugo will use it to automatically generate both a page that lists all the series and individual pages that list the content associated with each series. This template is implemented as follows:

{{ define "main" }}

<div class="content">
    <div class="article-wrapper u-cf single">
        <a class="bubble" href="{{ "/series/" | relLangURL }}">
            <i class="fa fa-fw fa-list-alt"></i>

        <article class="article">
            <div class="content">
                <h3>{{ i18n "series" | default "series" }}</h3>
                <ul id="all-series">
                    {{ range $name, $taxonomy := .Site.Taxonomies.series }}
                        {{ $series_name := $name }}
                        {{ $series_path := (printf "/series/%s" (urlize $name)) }}
                        {{ $series_page := site.GetPage $series_path }}

                        {{ if $series_page }}
                            {{ $series_name = $series_page.Title }}
                        {{ end }}

                        <li><a href="{{ $series_path }}">{{ $series_name }} ({{ $taxonomy.Count }})</a></li>
                    {{ end }}
{{ end }}

Please note that the CSS class names may differ if you use other than the Bilberry Hugo theme.


The layouts/shortcodes/series.html file is the shortcode that encapsulates the list of articles for the provided series’ name. Articles are sorted ascending by page’s date front matter variable value, i.e., the oldest first. This shortcode is implemented as follows:

{{ $series_name := .Get 0 | urlize }}

{{ range $key, $taxonomy := .Site.Taxonomies.series }}
    {{ if eq $key $series_name }}
        {{ range $taxonomy.Pages.ByDate }}
        <li hugo-nav="{{ .RelPermalink }}">
            <a href="{{ .Permalink }}">{{ .LinkTitle }}</a>
        {{ end }}
    {{ end }}
{{ end }}


The i18n function is used in the layouts/_default/series.terms.html template to display the Series label. Therefore, in the language of your choice, define a label value for the series key in the corresponding i18n configuration file, for instance, i18n/en.toml:

other = "Series"


To group articles as a series, add the series front matter variable to each article and set its value to the name of the series, for example:

series: "Building Your Blog, the Geeky Way"

Then if you want to list all articles for a particular series within the markdown, use the series shortcode with the series’ name, for example:

{{< series "Building Your Blog, the Geeky Way" >}}

This will generate a list of article links as below:

Series Shortcode in Markdown

The page that lists all the series will be available at <site-base-url>/series/, for instance,

Series Page List All

The content associated with a particular series can be accessed at <site-base-url>/series/<urlized-series-name>, for example,

And concluding this post, I want to add that the presented solution is generic enough, and it can be applied to any Hugo theme. If you’re going to use it within your theme, the only thing to change is the taxonomy template’s CSS class names.

comments powered by Disqus