Looking for advice on updating Hugo tag layout

Hello, I have an older site on Hugo that hasn’t been fully updated yet. I’ve noticed that layouts/_default/tag.terms.html is no longer used in the recent versions of Hugo. I might be wrong, but from what I’ve noticed, there are now two files instead: layouts/_default/taxonomy.html and layouts/_default/terms.html. Is that correct?

In the Hugo documentation, the original layouts/_default/taxonomy.html template uses an H2 headline for each tag when listed, which seems a bit strange to me since it looks more like a list. I was wondering if there’s anything wrong with tweaking this template to use an unordered list when accessing https://mywebsite.com/tags/ ?

{{ define "main" }}
  <h1>{{ .Title }}</h1>
  {{ .Content }}
  {{ range .Pages }}
    <h2><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h2>
  {{ end }}
{{ end }}

modify to this, with the addition of “count” :

{{ define "main" }}
  <h1>{{ .Title }}</h1>
  {{ .Content }}
  <ul class="tags">
  {{ range .Pages }}
    <li><a href="{{ .Page.RelPermalink }}">{{ .Page.LinkTitle }}</a> ({{ .Count }})</li>
  {{ end }}
  </ul>
{{ end }}

Or even better, I would like something similar to the Hugo tags page found here, with the tags displayed in two or three responsive columns: HUGO

Being able to change the sort by name and count on the website is probably a feature implemented with JavaScript, right? I don’t think I’ll have more than 100 tags, so pagination isn’t really worth it for that. However, pagination might be important once I click on a tag and all the articles under that tag appear. What do you think?

I would be grateful for any suggestions you can offer. Thank you.

I use layout/tags/list.html.html and layout/tags/terms.html.html

My samples are here

HTH

1 Like

Thank you. I appreciate it.

I was wondering if there is a way to switch between sorting alphabetically and by count directly on the HTML page:

Switching between this:

{{ range .Data.Terms.Alphabetical }}
    <h2><a href="{{ .Page.RelPermalink }}">{{ .Page.LinkTitle }}</a> ({{ .Count }})</h2>
  {{ end }}

and this:

  {{ range .Data.Terms.ByCount }}
    <h2><a href="{{ .Page.RelPermalink }}">{{ .Page.LinkTitle }}</a> ({{ .Count }})</h2>
  {{ end }}

Although I don’t think there’s a way. That would require modifying Go’s range value on the fly in the template, and I don’t think JavaScript can do that.

I created a three-column responsive list using CSS Grid, which mimics the behavior seen on the HUGO page. Here is my implementation with horizontal sorting. The thing is that my version uses a list instead of separate DIV tags, that’s why I was asking if it’s okay using an unordered list in the template. The last piece in the puzzle which I need to figure out is how to switch between “sort by name” and “sort by count”.

you can generate both in one site and “toggle” the display

Three CSS Alternatives To JavaScript Navigation | CSS-Tricks was a help for me, but web search can help too

1 Like

Alternatively (to the suggestion of @ju52), you can sort the list with JS, provided you attach the count to the li elements in your template, eg with a data-count attribute.

function sortByName() {
  const sortedLiNodes = Array.from(document.querySelectorAll('ul.tags li')).sort((a,b) => a.innerText - b.innerText);
  document.querySelector('ul.tags').replaceChildren(...sortedLiNodes);
}

and

function sortByCount() {
  const sortedLiNodes = Array.from(document.querySelectorAll('ul.tags li')).sort((a,b) => a.dataSet.count - b.dataSet.count);
  document.querySelector('ul.tags').replaceChildren(...sortedLiNodes);
}

I used two functions here, but since the only difference between them is the sort function, it might be better to roll them into one.

1 Like

Thank you. I didn’t think about using data. I appreciate it.

Here’s the modified version:

const sortTags = (criteria) => {
  const sortedLiNodes = Array.from(document.querySelectorAll('ul.tags-list li'))
      .sort((a, b) => {
          if (criteria === 'name') {
              return a.innerText.localeCompare(b.innerText);
          } else if (criteria === 'count') {
              return b.dataset.count - a.dataset.count;
          }
      });
  document.querySelector('ul.tags-list').replaceChildren(...sortedLiNodes);
};

Then I call the function in _default/taxonomy.html:

{{ define "main" }}
  <h2>{{ .Title }}</h2>
  {{ .Content }}

  <div>
    <p>Sort by
      <a href="#" onclick="sortTags('name')">name</a> | 
      <a href="#" onclick="sortTags('count')">count</a>
    </p>
  </div>

  <ul class="tags-list">
  {{ range .Data.Terms.Alphabetical }}
    <li data-count="{{ .Count }}"><a href="{{ .Page.RelPermalink }}">{{ .Page.LinkTitle }}</a> ({{ .Count }})</li>
  {{ end }}
  </ul>
{{ end }}

Now, when I click on a tag, a list of posts associated with that tag is displayed. This behavior is managed by the _default/terms.html template. I’ve implemented pagination in terms.html, limiting the list to 50 posts per page to accommodate a growing number of posts over time.

I would like to know if there’s a way to display the post dates as DD-Month-YY, so that they appear like this in the list:

All posts tagged Tech

   - 12 Nov 2024 Post title 1
   - 11 Nov 2024 Post title 2
   - 10 Nov 2024 Post title 3

This is the _default/terms.html template:

{{ define "main" }}
  <h2>{{ .Title }}</h2>
  {{ .Content }}
  <ul>
  {{ range (.Paginate .Pages 50).Pages }}
    <li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li>
  {{ end }}
  </ul>
  {{ template "_internal/pagination.html" . }}
{{ end }}

which just displays:

All posts tagged Tech

   - Post title 1
   - Post title 2
   - Post title 3

For each post in the content folder, I have the date specified like so in the front matter:

---
title: "Post front matter"
date: 2024-08-03T15:53:51+02:00
author: Zoltan

I would be grateful for any suggestion. Thank you.