How to Sort Articles by Author Last Name

One of the best features of Hugo is that it automatically generates ’list’ pages, which are pages that neatly display a ’list’ of similar content. This is most often used in the blogging context, where you might want a page that displays all of the titles of your individual rants organized by date published. However, you can sort the blogs by any of the variables in your document ‘front matter’ (the top portion of your individual blogs). So this brings me to my problem, which is sorting the articles by the last name of the author of the article.

I will show three ways to do this, the first two are probably the ‘more recommended’ but less automatic ways that require planning before starting to copy hundreds of articles over from an old website. The last is what I am using for a friend’s website, because I can’t be bothered to go back and change the front matter for the articles I already made.

  1. Author Sub-Parameters
  2. Weights
  3. Automatic Last Name Grabbing

Author Sub-Parameters

First let’s look at the problem. So somewhere in your ’list.md’ file you are going to see a line that loops over some parameter to generate the list of blogs/articles on the page.

{{range .Paginator.Pages}}
	<!-- do some stuff like print title or .Render "summary"-->	

Here the .Paginator.Pages just returns an object with all of the pages you want. Then the range function is going to loop through all of the pages (blog/articles) according to their rules, which may change but roughly prioritize when the article was published and then some other stuff like the alphabetical ordering of the titles. However, you can sort by any of the page parameters for example author.

{{range .Paginator.Pages.ByParam "author"}}

or by title

{{range .Paginator.Pages.ByParam "title"}}
<!-- or-->
{{range .Paginator.Pages.ByTitle}}

or by any random parameter you leave in the front matter of your blog posts.

Therefore, if you format your blog posts like

---
author:
    first_name: sam
    last_name: warren
---

you can sort by last name by calling

{{range .Paginator.Pages.ByParam "author.last_name"}}

Weights

Let’s say you have some other function in your code that relies on calling ‘author’, and breaking author up into sub-variables is causing issues. You should probably just go fix those calls to add the strings of first and last name together, but let’s imagine you are somewhat lazy and don’t have a lot of articles.

In that case, you can just manually set the weight (order) to each article in the front-matter and not change anything in your list layout as .Paginator.Pages is already sorted by weight (lower number has higher priority).

---
weight: 1 <!-- this would be my first article-->
---

Automatic

The basic idea is that we will make a dictionary that contains the last names of the authors for each page as the key and the page as the value.

First, let’s think about how we will obtain the last name. We can get a string from each page which is the authors full name. Hugo has a function split, which will return a slice (similar to a python list) of strings split up by some delimiter (we will choose a space). We can use that to get a slice with an item for first and last name.

{{ $name := split .Params.author " " }}

to get just the last name, we can subtract 1 from the length of the slice, and index that position. This is more general than indexing position 1 (0 is the first index) because it allows for middle initials or names.

{{ $lastname := index $name (sub (len $name) 1) }}

With that string manipulation out of the way, we can focus on making the dictionaries

{{ $lastnames := dict }} <!--making empty dictionary -->
{{ range .Paginator.Pages}}
    {{ $dic := dict }}
    {{ if .Params.author }} <!-- only doing this for blog posts with an author-->
	{{ $name := split .Params.author " " }}
	{{ $lastname := index $name (sub (len $name) 1) }}
        {{ $dic = dict $lastname . }} <!-- where . is just the page (read up on the range function to better understand what . represents)-->
    {{ $lastnames = merge $lastnames $dic }} <!-- merge just adds dictionaries together-->
    {{ end }}
    {{ range $lastnames }} <!-- luckily for us, maps automatically sort the key value in alphabetical order, so we don't have to sort anything else-->
        <!-- do stuff -->
    {{ else }} <!-- in case there weren't any authors, so $lastnames wasn't created -->
        {{range .Paginator.Pages }}
            <!-- do stuff-->
        {{ end }}
    {{ end }}

Presto! Bam! Your pages are sorted by last name, and this totally didn’t take more time for me to figure out than if I had just changed the front matter like suggested in the beginning.

Sam's Site

A place for my projects


Grabbing last name from .Page.author without specifying it in the front matter