Learn and Discover Open Source with Daily Genuine Experience. From Coding, Front End, Back End, Database, and Static Site Generator.
 
 
ssg  


Preface

This feature in Hugo almost tears my eyes. Consider see how it works.

Goal: Create custom taxonomy terms layout and also taxonomy detail layout.

TThere are two artefacts required, terms.html and taxonomy.html. We need to concentrate on the loop for both artefacts.

Table of Content

  • Preface: Table of Content

  • 1: Prepare

  • 2: Taxonomy Terms

  • 3: Taxonomy Detail

  • What is Next ?

Source Code

You can download the source code of this article here.

Related Article

I also wrote about Hugo Bootstrap Taxonomy. Step by step article, that you can read here:

Again I rewrite this article. A slight modification for Bulma.


1: Prepare

Remember our last config.toml. We already have these taxonomies:

# An example of Hugo site for tutorial purpose.

baseURL      = "http://example.org/"
languageCode = "en-us"
title        = "Letters to my Beloved"
theme        = "tutor-04"

[taxonomies]
  category = "categories"
  tag = "tags"

[permalinks]
  posts    = ":section/:year/:month/:day/:slug"
  quotes   = ":section/:year/:month/:day/:slug"

In fact.

I already put both terms.html and taxonomy.html in tutor-03.


2: Taxonomy Terms

Instead of the standard terms.html, we can make it prettier, by making our own custom terms.html.

The Loop

The range is as simple as this loop below.

  {{ range $key, $value := .Data.Terms }}
    ...
  {{ end }}

Default: Terms: Simple

Create this artefact:

  • themes/tutor-03/layouts/_default/terms.html
{{ define "main" }}
<main role="main" 
      class="column is-full box-deco has-background-white">

  <section class="section">
    <h4 class="title is-4">{{ .Section }}</h4>
  
    {{ .Content }}
  </section>

  <section id="archive">
    {{ range $key, $value := .Data.Terms }}
      <div id="{{ $key }}">
        {{ $.Data.Singular | humanize }}: 
        <a href="{{ "/" | relLangURL }}{{ $.Data.Plural | urlize }}/{{ $key | urlize }}">
        {{ $key }}</a>
      </div>
    {{ end }}
  </section>
</main>
{{ end }}

Server Output: Browser: Terms: Simple

Open in your favorite browser. You should see, a page, with tags.

Hugo Bulma: Terms

Default: Terms: with Stylesheet

Or even better, consider apply Bulma stylesheet to this terms layouts.

Consider to change this artefact:

{{ define "main" }}
<main role="main" 
      class="column is-full box-deco has-background-white">

  <section class="section">
    <h4 class="title is-4">{{ .Section }}</h4>
  
    {{ .Content }}
  </section>

  <div class="field is-grouped is-grouped-multiline">
    {{ range $key, $value := .Data.Terms }}
    <div class="tags has-addons">
      {{ $posts := where $value.Pages "Type" "post" }}
      {{ $postCount := len $posts -}}
      <a href="{{ "/" | relLangURL }}{{ $.Data.Plural | urlize }}/{{ $key | urlize }}">
        <div class="tag is-light">{{ $key }}
        </div><div class="tag is-dark">{{ $postCount }}
        </div>
      </a>
    </div>
    &nbsp;
    {{- end }}
    <div class="tags dummy"></div>
  </div>
</main>
{{ end }}

Notice that all equipped with Bulma Class.

The Loop

The range is as simple as this loop below. But be aware of the count. We need to filter them only for post kind page.

  {{ range $key, $value := .Data.Terms }}
    ...
    {{ $posts := where $value.Pages "Type" "post" }}
    {{ $postCount := len $posts -}}
    ...
  {{ end }}

Server Output: Browser: Terms: with Stylesheet

Open in your favorite browser. You should see, a page, with tags.

Hugo Bulma: Terms with Stylesheet

Default: Terms: with Tree

It would be nice if your terms list, also contain a list of each article, but filter the result to contain only post type, and excluding the other page kind.

Again consider to change this artefact:

{{ define "main" }}
<main role="main" 
      class="column is-full box-deco has-background-white">

  <div class="field is-grouped is-grouped-multiline">
    {{ range $key, $value := .Data.Terms }}
    <div class="tags has-addons">
      {{ $posts := where $value.Pages "Type" "post" }}
      {{ $postCount := len $posts -}}
      <a href="{{ "/" | relLangURL }}{{ $.Data.Plural | urlize }}/{{ $key | urlize }}">
        <div class="tag is-light">{{ $key }}
        </div><div class="tag is-dark">{{ $postCount }}
        </div>
      </a>
    </div>
    &nbsp;
    {{- end }}
    <div class="tags dummy"></div>
  </div>

  <section class="section">
    <h4 class="title is-4">{{ .Section }}</h4>
  
    {{ .Content }}
  </section>

  <section class="archive-p3" id="archive">
    {{ range $key, $value := .Data.Terms }}
      <div id="{{ $key }}" class ="anchor-target">
        <span class="fa fa-folder"></span> 
        {{ $.Data.Singular | humanize }}: 
        <a href="{{ "/" | relLangURL }}{{ $.Data.Plural | urlize }}/{{ $key | urlize }}">
        {{ $key }}</a>
      </div>

      <div class="archive-list archive-p3">
      {{ range where $value.Pages "Type" "post" }}
      <div class="archive-item meta-item">
        <div class="meta_link has-text-right">
          <time class="meta_time is-pulled-right"
                datetime="{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}">
            {{ .Date.Format "Jan 02, 2006" }}
            &nbsp;<span class="fa fa-calendar"></span></time></div>
        <div class="is-pulled-left"><a href="{{ .URL | absURL }}">
          {{ .Title }}
        </a></div>
        <div class="is-clearfix"></div>
      </div>
      {{ end }}
      </div>

    {{ end }}
  </section>
</main>
{{ end }}

Notice that, I have added FontAwesome for comfort.

The Loop

We also need to filter them only for post kind page. This require nested loops as below:

  {{ range $key, $value := .Data.Terms }}
    ...
    {{ range where $value.Pages "Type" "post" }}
      ...
      {{ .Title }}
      ...
    {{ end }}
    ...
  {{ end }}

Server Output: Browser: Terms: with Tree

Open in your favorite browser. You should see, a page, with tags.

Hugo Bulma: Terms with Tree

Test

I remove the post type from this frontmatter.

+++
title      = "M2M - The Day You Went Away"
date       = 2014-03-15T07:35:05+07:00
categories = ["lyric"]
tags       = ["pop", "90s"]
slug       = "m2m-the-day-you-went-away"
author     = "epsi"
+++

This article won’t show up nomore as post in either terms.html, and taxonomy.html.


3: Taxonomy Detail

You can click for each terms and have the detail, such as love badge or lyric badge:

Which will be using the layouts/_default/list.html Of course we can make our own taxonomy.html to show taxonomy detail. Now we need to make the taxonomy.html artefact.

The Loop

The range needs tob filtered, to include only post kind page as this loop below.

  {{ range where .Data.Pages "Type" "post" }}
    ...
  {{ end }}

Default: Taxonomy: Simple

Consider to create this artefact:

{{ define "main" }}
<main role="main" 
      class="column is-full box-deco has-background-white">
  <section class="section">
    <h4 class="title is-4">{{ .Section }}</h4>
  
    {{ .Content }}
  </section>

  <section class="section" id="archive">
  {{ range where .Data.Pages "Type" "post" }}
    <div class="archive-item">
      <div class="is-pulled-left"><a href="{{ .URL | absURL }}">
        {{ .Title }}
      </a></div>
      <div class="is-pulled-right has-text-right"><time>
          {{ .Date.Format "02 Jan" }}&nbsp;
          <span class="fa fa-calendar"></span>
      </time></div>
      <div class="is-clearfix"></div>
    </div>
  {{ end }}
  </section>

</main>
{{ end }}

Server Output: Browser: Taxonomy: Simple

Open in your favorite browser. You should see, a page, contain link.

Hugo Bulma: Simple Taxonomy

Default: Taxonomy: Summary by Year

Just like list, we can have the summary by year as below:

{{ define "main" }}
<main role="main" 
      class="column is-full box-deco has-background-white">
  <section class="section">
    <h4 class="title is-4">{{ .Section }}</h4>
  
    {{ .Content }}
  </section>
  
  {{ $posts := where .Data.Pages "Type" "post" }}

  {{ range ($posts.GroupByDate "2006") }}
    <section class="section" id="archive">
      {{ partial "summary/by-year.html" . }}
    </section>
  {{ end }}
</main>
{{ end }}

The detail of the partial layout can be seen here.

As already discussed in previous article.

The Outer Loop

Again, the range is as a little bit complex. As already discussed in previous article.

  {{ $posts := where .Data.Pages "Type" "post" }}

  {{ range ($posts.GroupByDate "2006") }}
    ...
      {{ partial "summary/by-year.html" . }}
    ...
  {{ end }}

Server Output: Browser: Taxonomy: Year

And summary by month as below:

Hugo Bulma: Taxonomy by Year

Default: Taxonomy: Summary by Month

{{ define "main" }}
<main role="main" 
      class="column is-full box-deco has-background-white">
  <section class="section">
    <h4 class="title is-4">{{ .Section }}</h4>
  
    {{ .Content }}
  </section>
  
  {{ $posts := where .Data.Pages "Type" "post" }}

  {{ range ($posts.GroupByDate "2006") }}
    <section class="section" id="archive">
      {{ partial "summary/by-month.html" . }}
    </section>
  {{ end }}
</main>
{{ end }}

The detail of the partial layout can be seen here.

As already discussed in previous article.

Server Output: Browser: Taxonomy: Month

Hugo Bulma: Taxonomy by Month


What is Next ?

Feel sleepy ? Although it is a good idea to finish your tutorial. Just like this kitten, you may sleep anytime you want. Have a break for a while, feed your pet, and resume our tutorial.

adorable kitten

There are, some interesting topic about Blog Archive in Hugo. Consider continue reading [ Hugo - Archive ].

Thank you for reading.