Related updates

I had the idea of displaying updates related to the Hugo course I’m writing at the bottom of the course landing page. Until I have some course material to share I figured I might as well get these updates on the page so you can see how I’m getting on.

These updates live in their own directory and are marked with a specific tag. And I want to display them on a single page on my website. How do you do it?

First I need to get hold of all the updates I’ve written. As mentioned, updates are a dedicated content type. In other words, they live in their own directory at content/updates. Each update has it’s own markdown file.

Hugo refers to this type of content as regular pages. Think post or content page, as opposed to a taxonomy or section page. You can get hold of all regular pages from anywhere on your site using the .Site.RegularPages variable.

 {{ $updates := .Site.RegularPages }} 

But here’s the thing, using .Site.RegularPages on it’s own will return all regular pages. I have a few different content types on this site, so that includes any file in content/writing and content/newsletter. Not exactly what I want. I’m only interested in content/updates.

The solution is to filter by the Type associated with the content. Hugo automatically assigns a Type to all content types. The type is based on the name you give your content directory. For example, content/writing has the Type writing and content/updates has the Type updates.

Then you can use the where function to filter the array.

Putting this in practice my updates variable now looks like this.

 {{ $updates := where .Site.RegularPages "Type" "updates" }} 

Next I’m need to loop through my updates. You can do this using the range function, which is the equivalent of using foreach in other programming languages.

<!-- grab updates -->
{{ $updates := where site.RegularPages "Type" "updates" }}  
<!-- loop through updates -->
{{ range $updates }}
  // return something!  
{{ end }}

Now, what data should I return? Well, all I want to do is create a list of updates, so for each update I need the title, the date it was written and a link to it. That way you’ll be able to click the title and read the update.

<!-- grab updates -->
{{ $updates := where site.RegularPages "Type" "updates" }}  
<ul>
<!-- loop through updates -->
{{ range $updates }}
  <li>
    <a href="{{ .Permalink }}">{{ .Date.Format "Jan 2, 2006" }}  {{ .Title }}</a>
  </li>   
{{ end }}
</ul>

Now I have updates showing on the page, but there’s a problem. I only want to show updates that have been assigned the topic “Hugo” in the frontmatter of the updates markdown file.

---
title: "Learning exhaust"
date: 2021-12-07T10:29:30Z
slug: "learning-exhaust"
topics: ["Hugo"]
---

To check if an element is in a particular array you can use the in function.


  <!-- grab updates -->
  {{ $updates := where site.RegularPages "Type" "updates" }}  
  <ul>
  <!-- loop through updates -->
  {{ range $updates }}
    <!-- render if topic Hugo returns true -->
    {{ if in .Params.topics "Hugo" }}
      <li>
        <a href="{{ .Permalink }}">{{ .Date.Format "Jan 2, 2006" }}  {{ .Title }}</a>
      </li>   
    {{ end }}
  {{ end }}
  </ul>
{{ end }}

What we’re saying here is; only display updates if they have the topic “Hugo” assigned in their frontmatter and ignore all other pages.

There’s one last thing to do before I’m done here.

Currently I’m writing this logic in a template called page.html in my _default directory. The template is used by quite a few different pages, so these updates will show on all those different pages. Not exactly what I want. If you remember, I only want these updates to display on my Hugo course page.

The simple solution is to check if the current page URL is the same as the URL of the page in question – in my case that’s /learn-hugo/. To do this you can use the eq function and the .URL variable to check if the statement evaluates true. Simply put, if the current page URL equals /learn-hugo/, then run this code.

<!-- render if permalink returns true -->
{{- if eq .Permalink "/learn-hugo/" }}
  <h2>Course updates</h2>
  <!-- grab updates -->
  {{ $updates := where site.RegularPages "Type" "updates" }}  
  <ul>
  <!-- loop through updates -->
  {{ range $updates }}
    <!-- render if topic returns true -->
    {{ if in .Params.topics "Hugo" }}
      <li>
        <a href="{{ .Permalink }}">{{ .Date.Format "Jan 2, 2006" }}  {{ .Title }}</a>
      </li>   
    {{ end }}
  {{ end }}
  </ul>
{{ end }}

Notice the final statement contains all the previous code. This is because I only want Hugo to execute all this logic if the page is /learn-hugo/. In other words, if the condition is met.

That’s it. I now have course related updates displaying at the bottom of my Hugo course page. Hopefully you’ve learnt something here.

I think that’s it for the technical stuff for now. I need to get my head down and focus on creating course content, otherwise I’ll never get this thing launched by Spring ‘22.

Monthly Newsletter

Once a month I curate a newletter for designers and developers interested in CSS, Jamstack and keeping it simple. Check out past issues to get an idea.