Divide list of blog posts in multiple sublists based on (first) category

Current Situation: I use Hugo and the Hugo coder theme to maintain a private website including a blog. On the website, I have a “Blog” section that internally corresponds to the folder structure contentposts where in posts I gather all posts without any further subfolders. The layout of the blog and its posts is done in the theme folder themes/hugo-coder/layouts/ . In the front matter of each post, I specify tags and categories. Right now, clicking on blog on the website displays all blog posts ordered by date and with the header Posts.

Objective: I would like to split that one list in 3 - 4 lists being side by side over several rows (i.e. 2 lists side by side, then below them again two lists side-by-side), each one having another header, i.e. category, where the category is derived from one of the categories that I specify in the front matter of the blog post (e.g. the first one).

Attempt: I got inspiration to solve this issue by looking at the questions here and here though it didn’t work out properly. More specifically, in \themes\hugo-coder\layouts I have the folder /posts/ with the three files li.html, list.html and single.html where I somehow have to modify the first two to change it – how do I achieve this?

li.html:

<li>
{{ if or .Params.math .Site.Params.math }}
  <span class="date">{{ .Date.Format (.Site.Params.dateFormat | default "January 2, 2006" ) }}</span>
  <a class="title" href="{{ .Params.ExternalLink | default .RelPermalink }}">{{ .Title }}</a>
{{ partial "math.html" . }}
{{ end }}
</li>

list.html:

{{ define "title" }}
  {{ .Title }} · {{ .Site.Title }}
{{ partial "math.html" . }}
{{ end }}
{{ define "content" }}
  <section class="container list">
    <h1 class="title">{{ .Title }}</h1>
    <ul>
      {{- range .Paginator.Pages -}}
        {{- .Render "li" -}}
      {{- end -}}
    </ul>
  </section>
{{ end }}

I think that the simplest way to render these different lists would be to group the blog posts by checking for the value of the categories parameter.

For example

<section class="container list">
{{- range .Site.RegularPages -}}
{{- $category := .Params.category -}}
 {{- if eq $category "some-category" -}}
  <h3>{{ title $category }}</h3>
     <ul>
       {{- .Render "li" -}}
    </ul>
  {{- end -}}
{{- end -}}
</section>

Repeat the above check for all the categories that you need to render.

Thank you for your suggestion. Unfortunately, it doesn’t work. The list of posts disappears completely and I got a blank page without any blog posts left (though with the appropriate header, footer, …). I used the following code and I know that all blog posts have either of these category names, i.e. there is no blog posts that might go missing here.

{{ define "title" }}
  {{ .Title }} · {{ .Site.Title }}
{{ partial "math.html" . }}
{{ end }}
{{ define "content" }}
<section class="container list">
{{- range .Site.RegularPages -}}
{{- $categories := .Params.Categories -}}
 {{- if eq $categories "A" -}}
  <h3>{{ title $categories }}</h3>
     <ul>
       {{- .Render "li" -}}
    </ul>
  {{- end -}}
 {{- if eq $categories "B" -}}
  <h3>{{ title $categories }}</h3>
     <ul>
       {{- .Render "li" -}}
    </ul>
  {{- end -}}
 {{- if eq $categories "C" -}}
  <h3>{{ title $categories }}</h3>
     <ul>
       {{- .Render "li" -}}
    </ul>
  {{- end -}}
{{- end -}}
</section>

{{ end }}

I suspect that either .Site.RegularPages is not working (for which I tried .Page.Paginator which didn’t work neither) or I am missing some more code. Another idea?

I cannot make a further guess without seeing at the very least a minimal project with dummy content that replicates your actual project’s structure.

Also see the forum Requesting Help guidelines.

Of course, here you can see the actual layout files on which I based my website and parts of which I copied into the previous post.

Additionally, here is the structure of my website

Website 
     |--------- archtetypes
     |--------- content 
     |--------- data 
     |--------- Drafts 
     |--------- images 
     |--------- layouts
     |--------- resources
     |--------- static 
     |--------- themes 
     |--------- config.toml 

Note that the layouts folder above is empty as the project uses the one from the themes folder to which I provided a link.

The content folder has the structure

content 
     |--------- about
     |--------- images
     |--------- posts 
     |--------- projects 
     |--------- section-file1.md
     |--------- section-file2.md 

The blog posts, which are in the posts folder that does not have any subfolders itself, have the following pattern of front matter:

+++ 
draft = false
date = 2020-11-13T23:30:23+02:00
title = "Some Title"
description = "Some Text"
slug = "" 
tags = ["Some-Tag1", "Some-Tag2"]
categories = ["A"]
externalLink = ""
series = []
+++

Please tell me if you need additional information.

In the above categories is a map. Do you assign more than one categories to a file?

EDIT
I do not use Hugo Extended. It appears that the theme author has not commited the theme’s resources and therefore I cannot look into testing the repo on my local machine. Perhaps someone else will have a further look.

At first, I did. Then I set one category per blog post (still didn’t work) and now after your question I deleted the map leaving only the string. This creates an error though

Failed to render pages: render of "page" failed: execute of template failed: template: posts/single.html:24:47: executing "content" at <partial "taxonomy/categories.html" .>: error calling partial: "C:\Website\themes\hugo-coder\layouts\partials\taxonomy\categories.html:3:27": execute of template failed: template: partials/taxonomy/categories.html:3:27: executing "partials/taxonomy/categories.html" at <.>: range can't iterate over Math

which is because of the following partial categories.html

<div class="categories">
  <i class="fas fa-folder"></i>
  {{- range $index, $el := . -}}
    {{- if gt $index 0 }}
      <span class="separator">•</span>
    {{- end }}
    <a href="{{ ( printf "categories/%s/" ( . | urlize ) ) | relLangURL }}">{{ . }}</a>
  {{- end -}}
</div>

I’m sorry that you don’t have access to further resources. I’d be happy to supply any other information/code snippet you need from the project I have.

Give this a try:

git clone --single-branch -b hugo-forum-topic-31882 https://github.com/jmooring/hugo-testing hugo-forum-topic-31882
cd hugo-forum-topic-31882
hugo server

Then visit http://localhost:1313/blog/.

The important template code is in layouts/posts/list.html.

2 Likes

Based on your code @jmooring, I gave the following a try without success

{{ define "title" }}
  {{ .Title }} · {{ .Site.Title }}
{{ partial "math.html" . }}
{{ end }}
{{ define "content" }}
<section class="container list">
  {{ $pages := slice }}
  {{ $categories := slice }}

  {{ range where .Site.RegularPages.ByTitle "Type" "posts" }}
    {{ $category := (index .Params.categories 0) }}
    {{ $categories = $categories | append $category }}
    {{ $pages = $pages | append (dict "category" $category "page" .Page) }}
  {{ end }}

  {{ range $categories | uniq | sort }}
    <h2>{{ . }}</h2>
    {{ range where $pages "category" . }}
      <a href="{{ .page.RelPermalink }}">{{ .page.Title }}</a><br>
     <ul>
       {{- .Render "li" -}}
    </ul>
    {{ end }}
  {{ end }}
</section>

{{ end }}

It gives the error

Error: Error building site: failed to render pages: render of "section" failed: "C:\Website\themes\hugo-coder\layouts\posts\list.html:21:11": execute of template failed: template: posts/list.html:21:11: executing "content" at <.Render>: Render is not a method but has arguments

You are using the .Render function from within a two levels deep list context and Hugo cannot find li.html.

Instead use $.Render "li" so that li.html is called directly from the global context.

Also see:

1 Like

Thanks @alexandros for the remark. That actually solved the error and now I do get a list of blog posts by the categories.

The following is the one I get with the help of @jmooring’s code and the remark of @alexandros .

Based on this (and thanks again @jmooring), there are some minor errors and design tweaks left:

  1. All dates are wrong. The blog posts are all different with different dates but it gets displayed always the same date. Particularly irritating is that the 29 Nov 2020 isn’t the date of any of the blog posts displayed? I have no idea where that date comes from.
  2. I want to position the categories A and B next to each other and the category C below A, i.e. there are always 2 categories per row, evenly spaced.
  3. Right now, the date is below the (light-blue) blog post title. I would like to have the data on the left (i.e. in front) of the blog post title for each blog post. This would also reduce the excess space between the date and post title.
  4. As of now, there is a superfluous Posts line next to each date. I would like to suppress or delete that.

Attempts/Ideas:

  1. I have to somehow get the blog post date into the list.html file. Maybe .Site.Params.dateFormat? But where to put exactly?

  2. To be honest, I have no idea how to do the spacing/grouping of categories.

  3. I think the solution to this question is linked to the answer to question 1. As soon as I know how to include the blog post date, I can put it next to <a href="{{ .page.RelPermalink }}">{{ .page.Title }}</a><br> I suppose.

  4. Finally, for the last question, I tried modifying {{ range where .Site.RegularPages.ByTitle "Type" "posts" }} but that crashed the site completely.

My mistake. The date displayed is the creation date of the project.
Instead of the dollar sign use .page.Render "li"

I hadn’t quite paid attention to the rest of the template code as written by @jmooring

As for your other design/layout questions these are off topic. Try searching another channel for CSS/HTML like CSSTricks, StackOverflow and similar.

1 Like

Thanks @alexandros, that solved the date problem. Considering your remark, do these other questions don’t have anything to do with Hugo and Hugo coding, i.e. don’t I have to change the list.html file similar as before? Is it completely independent from the list.html file?

I will give you a detailed reply, but yes your questions are not quite related to Hugo.

Positioning items next to each other is a CSS question.

You need to adapt your HTML markup to achieve what you want, basically you need to move the blog post title with its link within the li.html template.

This is within the li.html you either need to delete it or wrap it within the link to the blog post and remove said link from above.

In any case these are issues about general HTML markup and CSS, we cannot help more with such issues in this forum.

1 Like

Thank you very much for the detailed reply @alexandros! I will look elsewhere then.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.