Generating Archive Pages with Hugo

Archive Page
Archive Page

In the absence of a search engine — an archive page is a simple way to find older articles quickly. Here is a quick and dirty way to create multiple archive pages with Hugo.

There are a few requirements. The archive pages should be a bit modular. We should be able to just drop an archive.md file into any folder within the content directory and generate a single archive page for that topic.

hugo
└── content
   ├── posts
   │   └── archive.md
   └── projects
       └── archive.md

We should be able to generate clean slugs. Hugo makes that URLs are typically generated according to the file directory structure. The slugs for each archive page topic would be of the form /posts/archive and /projects/archive.

We could also take a more pragmatic approach by using the following file directory structure which results in slugs like /archive/posts or /archive/projects.

hugo
└── content
   └── archive
      └── posts.md
      └── projects.md

The content of each archive page will be determined by the parameters within the front matter, particularly the layout parameter. The front The front matter is the only data in this file actually. content in posts/archive.md will contain the needed parameters to generate that page.

---
title: "Posts Archive"
layout: archive
hidden: true
type: posts
summary: This page contains an archive of all posts.
---

The layout parameter will reference the template layouts/_default/archive.html to render a single archive page. That template file is shown below.

{{ define "main" }}
<section class="section is-fullheight" itemscope itemtype="https://schema.org/WebPage">
  <div class="container">
    <div class="columns is-centered">
      <div class="column is-7">

      {{ $type := .Type }}
      {{ $.Scratch.Set "count" 1 }}

        {{ range (.Site.RegularPages.GroupByDate "2006") }}
          {{ if (gt .Key 2000) }}

            {{ range (where .Pages "Type" $type) }}
              {{ if (eq ($.Scratch.Get "count") 1) }}
                {{ $.Scratch.Set "count" 0 }}
                <h1 class="title is-4 has-text-weight-normal">{{ .Date.Format "2006" }}</h1>
              {{ end }}
            {{ end }}

            {{ $.Scratch.Set "count" 1 }}

              <ul class="article__list">
              {{ range (where .Pages "Type" $type) }}
                {{ if (ne .Params.hidden true) }}
                  <li>
                    <a class="is-block" href="{{ .RelPermalink }}">
                      <span class="has-text-grey-dark">{{ .Date.Format "02 Jan" }}</span> —                      {{ .Title }}
                    </a>
                  </li>
                {{ end }}
              {{ end }}

            </ul>
            <br>

        {{ end }}
      {{ end }}

      </div>
    </div>
  </div>
</section>
{{ end }}

This template groups all posts for a particular topic by year and orders them by the month, taking into account the type parameter from the front matter of archive.md. Note the use of the .Scratch .Scratch allows us to create a sort of scratchpad for variables. Is this the best way to set up a boolean variable? Who knows … There is most likely a much cleaner The count variable ends the iteration early and grabs the year once before displaying the article titles. The first function would have been a better choice. but this is good enough.

There are some quirks when implementing an archive page as a single post. We may want to make adjustments to the RSS and pagination templates to hide any additional data produced by the archive pages.

Updated 19 October 2019