Potentially Useful

Writing boring posts is okay

Create an expiring Now Page in Hugo

in: Meta Personal tagged: Hugo

I have added a now page to my site and a link to it in the navigation footer below. This isn’t particularly noteworthy—I’m pretty boring, so its content will probably only interest a few of my friends and family members (…maybe). However, because I have enough self-awareness to realize that I will “occasionally” let this become out of date, I devised a workaround that feels worth sharing: I learned how to make Hugo (the program I use to build this site) hide my now page whenever it gets too old.

The changes I made to my site configuration are captured in this Git commit. Since configurations and templates can vary so much between Hugo projects, I’ll explain each one a little bit in case anyone wants to do something similar for their site.

Set an expiration time parameter

First, decide how old you’ll let your page get before it expires, and convert that value to seconds. For expiration times in days or weeks this is pretty straightforward: every day has exactly 86,400 seconds, so every week has 604,800 seconds. For expiration times in months and years, this is trickier. I recommend approximating months with fractional years; e.g., three months is about 1/4 of a year. If you go this route, you’ll need to choose the duration of a year, bearing in mind:

Create a new variable in your Hugo configuration with this value; I called mine now_timeout and set it to ~1/2 a year.

now_timeout: 15778800

Create your now page

Create new content to represent your now page:

hugo new content content/now/index.md

(Note that all the shell commands should be run from the root folder of your project directory.)

Write your post, and make sure the following parameters are included in your front matter:

---
title: "Now"
date: [Place the date here]
layout: now
alternate: This page is out of date.
---

The layout is explained in the next step, and the alternate parameter defines the text that will be shown in place of your now page when it becomes a “then page”.

Create a ‘now’ layout

Your now page will probably use a layout similar to your ‘page’ layout. If you’re still using your theme’s default layout, make a copy and modify it (replacing your-theme with the name of the theme you’re using):

mkdir -p layouts/page
cp themes/your-theme/layouts/_default/single.html layouts/page/now.html

Edit this file, replacing the occurrence of {{ .Content }} with the following:

{{ if ge .Lastmod.Unix (sub time.Now.Unix .Site.Params.now_timeout) }}
{{ .Content }}
{{ else }}
<p>{{ .Param "alternate" }}</p>
{{ end }}

This is a basic if-then-else construct. If the page hasn’t expired yet, it will display it as normal, but if it has, the alternate text from the front matter will replace it. The reason that we chose an expiration time in seconds is that we’re comparing the “Unix time” representations of the page build time and the now page’s last modification time. If the template language supported duration values in months, I’d probably use that, but since it doesn’t it’s not worth the effort.

This step will be highly theme-dependent. Your site’s navigation is probably implemented with a “partial”; for example, my theme keeps this in themes/readable/layouts/partials/footer.html. Replacing your-theme with your actual theme name again, and nav-partial with the file that contains the navigation elements, make a copy of the file and edit it:

mkdir -p layouts/partials
cp themes/your-theme/layouts/partials/nav-partial.html layouts/partials/

Now the version of the navigation partial that lives in your layouts/partials directory will override your theme’s. Find the list of navigation links in your copy, and add a block like the following:

{{ $now := .GetPage "/now/" }}
{{ if ge $now.Lastmod.Unix (sub time.Now.Unix .Site.Params.now_timeout) }}
<a href="{{ $now.RelPermalink }}">{{ $now.Title }}</a>
{{ end }}

The <a> tag will probably need to be wrapped in a <p> or <li> tag, depending on your theme.

This is similar to the change we made for the now layout, only there’s no “else” clause, and we’re finding the now page content, storing it in a variable, and accessing its attributes. This was the part of Hugo theming that really required me to stop and build a better mental model of the site generation process.

That’s it

I hope this is useful to someone else!