Help:Categories

Create a blog category.

Blog categories are a way to group blog posts in a way, users are able to filter for. When a category was used that does not exist, a dummy category is shown on the categories page. Because of that, make sure to create a category for your blog post, if it doesn’t already exist.

Location

DirectoryDescription
content/<Language>/categories/The base directory of the blog categories

Create a New Categories Page

To create a new page, use the command npm run create -- 'categories/<pageName>.md'. After that you can edit your newly created page, which is located in content/en/categories/<pageName>.md.

Example

Create a new page foo:

$ npm run create -- 'categories/foo.md'

>[email protected] create
> exec-bin node_modules/.bin/hugo/hugo new "categories/foo.md"

Content "/home/username/path_to_repository/repository_root_directory/content/en/categories/foo.md" created

Front Matter

Every Markdown file contains a header section, called front matter, in the YAML format to configure parts of the page or website. A categories page needs the following variables in the front matter.
VariableTypeDescription
titlestrThe title of the page or ressource
descriptionstrThe page description, normally for SEO
leadstrThe page description shown after the title or in cards
datedatetimeThe datetime the page was created
lastmoddatetimeThe datetime the page was modified. Should be the same as date when the creating a new page
contributorslist of strA list of contributors
draftboolflase shows the page, true hides the page, as it does not exist
imageslist of strImages, which will be converted and moved to the static directory. Remember to add every image you used here
mathboolThis page contains LaTeX math. This option preloads the font and includes the KaTeX script in the script footer.
You will find a complete list and how to use them inside the site in the Hugo docs →

The Datetime Type

The date and time according to ISO 8601 . The following table shows the extended format specified in ISO 8601 we use for our website to specify, when e.g. a page was created or edited. It has three parts:

  • the date
  • the time, including it's designator T
  • the timezone offset
We would prefere if you would use your local time together with the timezone offset (in this case it is mandatory), but you can also enter the time in UTC without the timezone offset.
ValueOptionalDescription
2021NoYear
07NoMonth
08NoDay of the month
TNoT is a designator, which indicates the start of the time representation
12NoHour
34NoMinute
56NoSecond
+ or -Yes+ for a positive or - a negative timezone offset
01YesTimezone offset in hours
02YesTimezone offset in minutes

Formatting Examples

The following example uses the values from the table to show the format. It does not use the actual UTC. If you are not using the timezone offset, you must calculate UTC yourself.

  • Example with timezone offset: 2021-07-08T12:34:56+01:02
  • Example without timezone offset: 2021-07-08T12:34:56

Header Example

Remember, the front matter is a YAML structure embedded into the Markdown file. The --- delimiters signal Hugo that this is a front matter in the YAML format. Here is a generated example, how the front matter might look like:

---
title: "MyTitle"
description: "A description of the page content"
lead: "A lead to the page content"
date: 2021-10-08T14:48:42+01:00
lastmod: 2021-10-08T14:48:42+01:00
contributors: ["UserA" "UserB" "UserC"]
draft: false
images: ["avatar.svg" "foo.svg" "bar.svg"]
math: true# This is an example for a comment in YAML
---

Code

Below you find the implementation of the layout.

HTML

Term Page Layout

Defined in layouts/categories/term.html.

This code is licensed under the MIT license.
{{/*<!-- 

  Categories Layout
  =================

  Contributors: Michael Sasser
  Maintainer: Michael Sasser
  License: MIT
  Version: 1
  Type: Term

  LAYOUT: /layouts/categories/term.html
  DOCS:   /content/<language>/wiki/Help:Layout_Categories.md

  Description
  -----------

  The term layout page for the blog categories.

  Changelog
  =========

  Version 1
  ---------

  Initial release

-->*/}}

{{ define "main" }}

  {{ $blog := where .Site.RegularPages "Section" "blog" }}

  {{ $pages := slice }}


  <!-- Find the category page -->
  {{ $category_page := "" }}
  {{ range (where $.Site.RegularPages "Section" "categories") }}
    {{ if eq (lower .Title) (lower $.Title) }}
      {{ $category_page = . }}
    {{ end }}
  {{ end }}


  <!-- Find the blog posts (pages) -->
  {{ range $temp_page :=  (where $blog "Params.categories" "!=" nil) }}
    {{ range $c := .Page.Params.categories }}
      {{ if eq (lower $c) (lower $.Title) }}
        {{ $pages = $pages | append $temp_page }}
      {{ end }}
    {{ end }}
  {{ end }}


  <div class="container">
    <div class="section pt-5">
      <a href="/categories/">&#8592; Back to categories</a>
      <div class="row g-5 justify-content-center">
        <div class="col-md-12 col-lg-9 col-xl-9">
          <h1 class="pb-2 mb-2 fst-italic">
            <i class="fa fa-folder-open"></i>
            Category:
            {{ .Title | title }}
          </h1>
          <p class="lead">
            {{ with $category_page }}
              {{ .Params.lead | safeHTML }}
            {{ end }}
          </p>
          <div class="pb-4 mb-4">
            {{ with $category_page }}
              {{ .Content }}
            {{ end }}
          </div>
          {{ $paginator := .Paginate $pages -}}
          {{ range $paginator.Pages -}}
            {{ partial "main/blog-post-list-layout.html" . -}}
          {{ end }}
          <div class="pagination justify-content-center">
            {{ $.Scratch.Set "paginator" true }}
            {{ template "_internal/pagination.html" . }}
          </div>
        </div>
        {{ partial "main/blog-sidebar.html" . }}
      </div>
    </div>
  </div>
{{ end }}

Terms Page Layout

Defined in layouts/categories/terms.html.

This code is licensed under the MIT license.
{{/*<!-- 

  Categories Layout
  =================

  Contributors: Michael Sasser
  Maintainer: Michael Sasser
  License: MIT
  Version: 1
  Type: Terms

  LAYOUT: /layouts/categories/terms.html
  DOCS:   /content/<language>/wiki/Help:Layout_Categories.md

  Description
  -----------

  The terms layout page for the blog categories.

  Changelog
  =========

  Version 1
  ---------

  Initial release

-->*/}}

{{ define "main" }}

  <!-- Check if path for pagination should be /blog/ or /blog/<year>/ -->
  {{ $blog := (where .Site.RegularPages "Section" "blog") }}


  <!-- Store for all elements (not uniq) -->
  {{ $categories := newScratch }}
  {{ $temp_categories := slice }}

  <!-- find all categories and number of occurences -->
  <!-- The structure is so, because sort removes the key -->
  <!-- structure: [{<category name>: {"category" : <category name>, "count": 1, "pages":[page_1, page_n]}}, ...] -->
  {{ range $temp_page :=  (where $blog "Params.categories" "!=" nil) }}
    {{ range $c := .Page.Params.categories }}
      <!-- was there already an occurence of that category -->
      {{ if in $temp_categories (lower $c) }}
        <!-- get current value of count -->
        {{ $count := ($categories.Get (lower $c)).count }}
        {{ $pages := ($categories.Get (lower $c)).pages }}
        {{ $category_page := ($categories.Get (lower $c)).category_page }}
        <!-- Write a new map back, with the current count + 1 and the additional page -->
        {{ $categories.Set (lower $c) (dict "category" (lower $c) "count" (add $count 1) "pages" ($pages | append $temp_page) "category_page" $category_page) }}
      {{ else }}
        <!-- get category page, by compareing the category page with the category name used in the blog post (the one from above) -->
        {{ $category_page := "" }}
        {{ range (where $.Site.RegularPages "Section" "categories") }}
          {{ if eq (lower .Title) (lower $c) }}
            {{ $category_page = . }}
          {{ end }}
        {{ end }}
        <!-- create the category with the initial count of 1 -->
        {{ $categories.Set (lower $c) (dict "category" (lower $c) "count" 1 "pages" (slice $temp_page) "category_page" $category_page)}}
        {{ $temp_categories = $temp_categories | append (lower $c) }}
      {{ end }}
    {{ end }}
  {{ end }}
  <!-- {{/* values: {{sort $categories.Values "count" "desc"}}<br /> */}} -->

  <div class="container">
    <div class="section pt-5">
    <a href="/blog/">&#8592; Back to blog</a>
    <div class="row g-5 justify-content-center">
        <div class="col-md-12 col-lg-9 col-xl-9">
        <h1 class="pb-2 mb-2 fst-italic">
          <i class="fa fa-folder-open"></i>
          {{ .Title }}
        </h1>
        <p class="lead">{{ .Params.lead | safeHTML }}</p>
        <div class="text-center pb-4 mb-4">{{ .Content }}</div>
        <div class="row row-cols-1 row-cols-md-3 g-4">
          {{ range (sort $categories.Values "count" "desc")}}
            {{/*  {{.}}<br /> */}}
            <div class="col">
              <div class="card text-center h-100">
                <div class="card-image">
                  <a href="{{ .Page.Permalink }}">
                  <!-- The first page hugo finds (any page) -->
                  {{ $firstChild := index .pages 0 }}
                  <!-- If the category_page exists -->
                  {{ if ne .category_page "" }}

                    <!-- This overwrites any existing image to the first one -->
                    <!-- in the category -->
                    {{ $firstChild = index .category_page }}
                  {{ end }}
                    <!-- does images exist? -->
                    {{ if isset $firstChild.Params "images" }}
                      <!-- if it has more then one elements -->
                      {{ if gt (len $firstChild.Params.images) 0 }}

                        {{ $images := $firstChild.Params.images }}
                        <!-- image_name e.g. "my.svg" -->
                        {{ $image_name := (index $images 0) }}


                        <!-- image_path e.g. "/path/to/" -->
                        {{ $image_path := $firstChild.RelPermalink | relURL }}
                        <!-- avatar e.g. "/path/to/foo.svg" -->
                        {{ $image := $image_name | printf "%s%s" $image_path | printf "%s" }}
                        <img
                          src="{{ $image }}"
                          class="card-img-top lazyload blur-up"
                          alt=""
                          width="100%"
                          height="256px"
                        />
                        <!-- Not able to find an image -->
                      {{ else }}

                        <svg
                          class="card-img-top bd-placeholder-img lazyload blur-up"
                          width="100%"
                          height="256px"
                          xmlns="http://www.w3.org/2000/svg"
                          role="img"
                          aria-label="Placeholder: Thumbnail"
                          preserveAspectRatio="xMidYMid slice"
                          focusable="false"
                        >
                          <title>Missing Thumbnail</title>
                          <rect
                            width="100%"
                            height="100%"
                            fill="#2f3237"
                          ></rect>
                          <text x="50%" y="43%" fill="#dee2e6" dominant-baseline="middle" text-anchor="middle" dy=".3em" style="font: italic 20px sans-serif;">
                            Missing
                          </text>
                          <text x="50%" y="57%" fill="#dee2e6" dominant-baseline="middle" text-anchor="middle" dy=".3em" style="font: italic 20px sans-serif;">
                            Thumbnail
                          </text>
                        </svg>
                      {{ end }}
                    {{ end }}
                  </a>
                </div>
                <div class="card-body pb-1">
                  <a class="stretched-link" href="/categories/{{.category}}"></a>
                  <h4 class="card-title">{{ .category | title }}</h4>
                  <p class="card-text">
              {{ if ne .category_page "" }}
                {{ .category_page.Params.lead }}
              {{ else }}
              <span class="text-muted">This category is new and has no description, yet.</span>
              {{end}}
                  </p>
                  <div class="card-footer">
                    <small class="text-muted">
                      {{ .count }}
                      Post{{ if ne .count 1 }}s{{ end }}
                    </small>
                  </div>
                </div>
              </div>
            </div>
          {{ end }}
        </div>
      </div>

      {{ partial "main/blog-sidebar.html" . }}
    </div>
  </div>
    </div>
  </div>

{{ end }}

Archetype

Defined in layouts/categories.md.

This code is licensed under the MIT license.
---
title: "{{ replace .Name "-" " " | title }}"
description: ""
lead: ""
date: {{ .Date }}
lastmod: {{ .Date }}
contributors: []
draft: true
images: ["{{ .Name | urlize }}.jpg"]
---
Top