Make an seperate article list with Hugo

I have been thinking about a separate article list on my homepage for a long time. Yesterday was finally the time to do it. I struggled a bit getting this setup. I was unsure – and still am – of the right way for this.

I usually used a short code to collect the post and then included this in a content page with the correct name. But I feel this is not the best solution. So this time, I created a new output format to create another index page for the blog.

Setup a secondary index page

I’ve added the following to my config.toml file:

[outputFormats]
	[outputFormats.articles]
		mediaType = "text/html"
		baseName = "articles"
		isPlainText = false

[outputs]
	home = ["HTML", "articles"]

This configuration defines a new output format that still generates HTML (because of the media type key). And the second important step was to enable this output format for the home page (home =). Home is the page kind of the homepage, the one I want to duplicate (see Output Formats for Pages).

The last step is to duplicate the index.html layouts file inside your page’s layouts folder (or copy it from the theme folder into your layouts folder if it is missing.) And rename it to index.articles.html. This file renders your new index page with the posts you want to display.

Filtering the posts

My subsequent struggle was filtering the posts I wanted to display on my new page. All my long-form entries use the layout type post. So I can filter my post list by these criteria. But I also wanted to exclude entries with a specific tag. And this is where I’ve struggled. Nothing I’ve tried wished to work. Based on the documentation I found, I would have expected that it should work like this (the variable all_articles contains all the articles in my blog):

{{ $articles_without_reviews := (where $all_articles "Params.tags" "not in" "review") }}

Set variable articles_without_reviews to all the post which doe not have the review tag. But this just returned nothing. I was able to filter the other way around with:

{{ $articles_with_reviews := (where $all_articles "Params.tags" "intersect" "review") }}

But there is not “not intersect” option 1 in hugo :-( so in the end I went with the following solution:

{{ $res := slice }}
{{ range $all_articles}}
	{{ if in .Params.tags "review" }}
	{{ else }}
		{{ $res = $res | append . }}
	{{ end }}
{{ end }}

What I don’t like

With this solution, I’ve started mixing where my content is defined and where the page’s layout is placed. It creates a completely missing page in my content folder. And to give it a custom title (and not copy the tile from my _index.md file), I also set this all directly in the layout file. I also needed to add the page manually to my main menu (another entry in the config.toml file):

[menu]
  [[menu.main]]
    identifier = "posts"
    name = "Timeline"
    title = "Timeline"
    url = "/"
    weight = -110
    [[menu.main]]
      identifier = "articles"
      name = "Articles"
      title = "Articles"
      url = "/articles.html"
      weight = -100

  1. I found a feature request for this, but it has no reaction to it: Negative intersect (“not intersect”) is needed↩︎

Comments

How to respond

Write your comment on your on page and link it to this page with the following link:
https://vmac.ch/posts/2022-07-10-make-an-article-list-with-hugo/
Then insert the permalink to your post into the form below and submit it.

Alternatively you can reach me by email to: comment@vmac.ch