displaying series of a post in hugo

This commit is contained in:
Wouter Groeneveld 2024-01-04 09:46:29 +01:00
parent 825f5e9ed0
commit 9a184184ea
4 changed files with 95 additions and 0 deletions

View File

@ -0,0 +1,95 @@
---
title: Displaying Series of Posts in Hugo
date: 2024-01-04T09:06:00+01:00
categories:
- webdesign
tags:
- hugo
- backlinks
- blogging
---
Sometimes, the things that I write about are part of a series. For instance, the game [Wario Land II](https://jefklakscodex.com/games/gameboycolor/wario-land-2/) is part of the _Mario/Wario Land_ series, of which I've played and reviewed several. Yet, until now, I didn't _really_ link to the other games in the series, even though that has been on my mind for a while. That changed yesterday with the introduction of the frontmatter parameter `series`.
In 2022, I already explained [how I extract backlinks](/post/2022/04/true-backlink-support-in-hugo/) in Hugo, by looking for occurrences of the link in the content body using `findRE`. But that's not enough, since other related posts that are part of the series are not always mentioned. That means, backlinks, forwardlinks, and even related posts by tag intersection can't find everything. What I wanted to achieve is what [Old Game Hermit](https://www.oldgamehermit.com/2023/12/review-icewind-dale-enhanced-edition/) displays at the end of a review:
![](../oldgamehermit.jpg "'Other Reviews In This Series' on Old Game Hermit.")
The Hermit uses Wordpress, not Hugo like I do, and judging from the games that do not have links and are yet to be reviewed, I'd dare to say that it could be manually added to each article? Not something I'm keen on doing. Instead, I implemented the simplest thing I could think of: wire series of posts together with a shared `series` parameter, like this:
1. Find all pages that have the same value for parameter `series`
2. Sort them ascending by game release year
3. If there's more than one (which is the one currently being displayed), loop through them and display a link.
```
{{ $series := slice }}
{{ if isset .Params "series" }}
{{ $series = (where .Site.Pages ".Params.series" "eq" .Params.series).ByParam "game_release_year" }}
{{ $has_series := $series | len }}
{{ if gt $has_series 1 }}
<div class="series">
<strong><em>{{ .Params.series }}</em> series</strong>&nbsp;&nbsp;&#9657;
{{- range $series -}}
&nbsp;&nbsp;<a href="{{ .RelPermalink }}">{{ .Params.game_name }}</a>&nbsp;&nbsp;&#9675;
{{- end -}}
</div>
{{ end }}
{{ end }}
```
Pretty simple, right? That still didn't do it for me, as many articles are not coupled together like that. In those cases, I wanted to display the related posts (gathered via the backlink method explained above). But what if they're both part of the same series and also show up as a backlink? In that case, throw them out---Hugo has a handy `complement` function for that. My backlink logic resides in another file as it's also shown in the sidebar, but can easily be recycled using the scratchpad:
1. Find all related posts that have a valid game name that are _not_ in the above series list
2. If there's more than zero, loop through them and display a link.
```
{{ $related := (where ($.Scratch.Get "related" | complement $series) ".Params.game_name" "ne" nil) }}
{{ $has_related := $related | len }}
{{ if gt $has_related 0 }}
{{- $related = sort $related ".Params.game_release_year" "asc" }}
<div class="similar">
<strong>Related games</strong>&nbsp;&nbsp;&#9657;
{{- range $related | uniq -}}
&nbsp;&nbsp;<a href="{{ .RelPermalink }}">{{ .Params.game_name }}</a>&nbsp;&nbsp;&#9675;
{{- end -}}
</div>
{{ end }}
```
Sorting can be done by either using Hugo's separate `sort` function or by relying on the built-in `.ByDate`, or in my case, `.ByParam` shorthands. The problem is that after `Scratch.Get`, you lose your type, and `.ByParam` doesn't exist on `[]interface {}`, hence the extra line.
The result is this in HTML:
![](../jefklakscodex.jpg "'... Series' and Related links on Jefklak's Codex.")
Good enough! I didn't yet review Wario Land 3 and 4, so there's no entry in the `.Site.Pages` collection to show. I _could_ create empty files to circumvent this and display titles without links like Old Game Hermit does, but for now, like I said, good enough.
We're just missing one more thing: the RSS feed. For Old Game Hermit also displays the exact same list of links there, and I quite like that, as readers might be interested in other games from the same series---whether they're using a browser or an RSS client shouldn't matter. In Hugo, you can fully customize your RSS feed by fiddling with the `_default/rss.xml` file. Unfortunately, I can't rely on the scratchpad trick to reuse logic, and I can't reuse code via shortcodes.
I've tried several things to reduce the copy-paste logic but none of them worked. It doesn't really matter anyway since the display logic is slightly different, as instead of `<div/>` tags I settled for simple `<p/>` paragraphs. This is what it looks like in NetNewsWire:
![](../jefklakscodexrss.jpg "The series and related links via the Codex RSS feed.")
As for this blog, _Brain Baking_, I'm not yet sure whether or not displaying related links in the RSS feed itself has any effect. I don't miss it, most posts are not explicitly wired together, and people following my writing through a feed are usually more up-to-date than the ones that clicked through via a browser. That said, the "You Might Also Like..." links at the end of this post in HTML won't go anywhere.
For reference, the Wario Land II post has the following frontmatter:
```
---
title: "Wario Land II"
date: 2024-01-01T09:00:00+01:00
score: 4
howlongtobeat_id: 11065
howlongtobeat_hrs: 5.2
series: 'Mario Land'
game_name: 'Wario Land 2'
game_genre: '2D Platformer'
game_release_year: 1998
game_developer: 'Nintendo'
tags:
- 'Wario'
- '2D platformer'
---
```
The tags/genre keys are still ambiguous, but that's for another time.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB