Taxonomy

Taxonomy is the system for classifying articles by tags and categories. gohan automatically generates a dedicated page for each tag and category.

日本語版: taxonomy.ja.md


Setting up taxonomy in articles

Specify tags and categories in the Front Matter:

---
title: Understanding Go Concurrency
date: 2024-03-01
slug: go-concurrency
tags:
  - go
  - concurrency
  - goroutine
categories:
  - tech
  - programming
---
  • tags — Article keywords. Multiple values allowed. One page is generated per tag.
  • categories — Article classification. Multiple values allowed. One page is generated per category.

Generated pages

Given the article above, the following pages are generated:

public/
├── tags/
│   ├── go/index.html
│   ├── concurrency/index.html
│   └── goroutine/index.html
└── categories/
    ├── tech/index.html
    └── programming/index.html

Accessing taxonomy in templates

Tag page (tag.html)

.Articles contains only the articles that have this tag:

<!-- themes/default/templates/tag.html -->
<!DOCTYPE html>
<html lang="{{.Config.Site.Language}}">
<head>
  <meta charset="UTF-8">
  <title>Tag Articles — {{.Config.Site.Title}}</title>
</head>
<body>
  <header><nav><a href="/">← {{.Config.Site.Title}}</a></nav></header>
  <main>
    <h2>Articles ({{len .Articles}})</h2>
    <ul>
      {{range .Articles}}
      <li>
        <time>{{formatDate "2006-01-02" .FrontMatter.Date}}</time>
        <a href="/posts/{{.FrontMatter.Slug}}/">{{.FrontMatter.Title}}</a>
      </li>
      {{end}}
    </ul>
  </main>
</body>
</html>

Category page (category.html)

.Articles contains only the articles that belong to this category:

<!-- themes/default/templates/category.html -->
<!DOCTYPE html>
<html lang="{{.Config.Site.Language}}">
<head>
  <meta charset="UTF-8">
  <title>Category Articles — {{.Config.Site.Title}}</title>
</head>
<body>
  <main>
    <h2>Articles ({{len .Articles}})</h2>
    <ul>
      {{range .Articles}}
      <li>
        <a href="/posts/{{.FrontMatter.Slug}}/">{{.FrontMatter.Title}}</a>
      </li>
      {{end}}
    </ul>
  </main>
</body>
</html>

Listing all tags and categories

Use .Tags and .Categories to generate dynamic links to all tags/categories:

<!-- e.g. in index.html -->
<section>
  <h3>Tags</h3>
  <ul>
    {{range .Tags}}
    <li><a href="{{tagURL .Name}}">{{.Name}}</a></li>
    {{end}}
  </ul>

  <h3>Categories</h3>
  <ul>
    {{range .Categories}}
    <li><a href="{{categoryURL .Name}}">{{.Name}}</a></li>
    {{end}}
  </ul>
</section>

URL generation

Tag and category names are normalized to URL slugs:

  • Spaces → hyphens
  • Uppercase → lowercase
  • Example: "Go Language"/tags/go-language/

Template functions:

<a href="{{tagURL "Go Language"}}">Go Language</a>
<!-- → <a href="/tags/go-language/">Go Language</a> -->

<a href="{{categoryURL "Web Development"}}">Web Development</a>
<!-- → <a href="/categories/web-development/">Web Development</a> -->

Archive pages

Year-based and month-based archive pages are generated automatically from the article date field.

When i18n is not configured, archives are generated at the root:

public/
└── archives/
    ├── 2024/
    │   ├── index.html
    │   └── 03/index.html
    └── 2023/
        └── index.html

When i18n is configured, archives are generated per locale. The default locale uses the root path; other locales are prefixed with their locale code:

public/
├── archives/          # default locale (e.g. en)
│   └── 2024/
│       ├── index.html
│       └── 03/index.html
└── ja/
    └── archives/      # non-default locale
        └── 2024/
            ├── index.html
            └── 03/index.html

In archive.html, .Articles contains only the articles for that locale and period, and .CurrentLocale is set to the locale string.

<!-- themes/default/templates/archive.html -->
<!DOCTYPE html>
<html lang="{{.Config.Site.Language}}">
<head>
  <meta charset="UTF-8">
  <title>Archive — {{.Config.Site.Title}}</title>
</head>
<body>
  <main>
    <h2>Archive ({{len .Articles}} articles)</h2>
    <ul>
      {{range .Articles}}
      <li>
        <time>{{formatDate "2006-01-02" .FrontMatter.Date}}</time>
        <a href="/posts/{{.FrontMatter.Slug}}/">{{.FrontMatter.Title}}</a>
      </li>
      {{end}}
    </ul>
  </main>
</body>
</html>

Locale-aware taxonomy (i18n)

When i18n is enabled, you can maintain separate tag and category lists per locale. Place locale-specific files under the locale directory; if absent, gohan falls back to the global file:

content/
  tags.yaml              # global / fallback for all locales
  categories.yaml
  en/
    tags.yaml            # EN-specific (optional)
    categories.yaml      # EN-specific (optional)
    posts/
  ja/
    tags.yaml            # JA-specific (optional)
    categories.yaml      # JA-specific (optional)
    posts/

During gohan build, each article is validated against its own locale's registry. Articles whose locale has no dedicated file are validated against the global file.

See i18n feature docs for the full configuration reference.


Taxonomy design guidelines

  • Tags — Specific keywords for the article (go, docker, postgresql, etc.). Having many tags is fine.
  • Categories — Broad classifications (tech, life, book, etc.). Keep them few (5–10 recommended).

Related