Create a filter by taxonomy terms in the section page

I’ve done several researches on this forum, on the documentation site (both really useful for me) and on the web, but being a beginner with the hugo templating language I’m having difficulties to implement what I want.

I will try to be detailed in explaining my problem and I apologize in advance if I use the wrong terminology. I hope someone can give me an answer (if it’s possible) in a “for dummy” style because, really, I’m struggling now to understand how hugo works.

Let’s say I have a website and use a hugo theme structured like this (more or less):

├── assets
├── config
├── content/
│   ├── home/
│   └── post/
│       ├── _index.md
│       ├── post1/
│       │   └── index.md
│       ├── post2/
│       │   └── index.md
│       └── other-posts
├── data
├── layouts/ 
├── other-folders-and-files
└── themes

What I’d like to do is customize the layout of the “post” section page (i.e. the html file related to content/post/_index.md) which lists all the posts on my site. Each of these posts is organized with two “taxonomies”: categories and tags. Therefore each taxonomy contains different “terms”.

Since I have so many posts, I would like the user visiting my site to be able to filter them on the section page, choosing a particular “term” from one of the two taxonomies.

As an idea I wanted to create two dropdown menus, one for categories and one for tags, similar to this one proposed by w3school. Regarding the HTML, CSS and JS code to create the two menus I’m fine, however I don’t know how to tell hugo that when a button of a “term” is clicked only the posts related to that “term” should be shown in the section page. I think maybe this can be solved by creating attributes within the HTML tags (like data-* attributes) and create references/matches via hugo code, however this is too advanced for me. I also don’t know if it’s necessary to add javascript code to make the two filters work (the theme I use works with bootstrap v4.6) or it can be done only via hugo.

Is there a simple way (understandable for a beginner) to do this? Thanks.

Thank you for the well-written description of your objective.

My first thought is, “Do you really want to do this?” Here’s why I ask…

Let’s assume you have 10,000 posts. Displaying all of these on one page would be unusual, which is where pagination comes into play. With a JS filter, you would be filtering posts after pagination has occurred.

To me, it might make more sense to display a <select> list of terms (or 2 <select> lists, one for each taxonomy), and then change the browser location to the pre-rendered, paginated list.

Thoughts?

1 Like

Thank you for your answer and suggestions.

I agree with you about pagination, although I may have been exaggerating when I said I had a lot of posts.

What do you mean by

With a JS filter, you would be filtering posts after pagination has occurred.

Regarding the <select> list you suggest, do you perhaps mean to create something similar to this code?

<select class="some-class" data-filter-group="category">
  <option value="*">Category</option>
  {{ $categories := $.Site.Taxonomies.categories.Alphabetical  }}
  {{ range $categories }}
  {{ if .Term }}
    <option value=".category-{{ .Term }}">{{ .Term }}</option>
  {{ end }}
  {{ end }}
</select>

<select class="some-class" data-filter-group="tag">
  <option value="*">Tag</option>
  {{ $tags := $.Site.Taxonomies.tags.Alphabetical  }}
  {{ range $tags }}
  {{ if .Term }}
    <option value=".tag-{{ .Term }}">{{ .Term }}</option>
  {{ end }}
  {{ end }}
</select>

To reproduce this example I was inspired by the html code of the theme I’m using (Academic if it’s helpful to know), although I don’t know how the data-filter-group attribute works (and I think I should focus on that).

But I’ve observed, experimenting on the template I’m using (if you’re interested you can see the demo of the theme here, to have a visual example of what I’m referring to, and the publications section here where you can notice that the <select> feature is already present but not for taxonomies), that adding pagination to this section to move posts (in my case) in different pages the filter works only on the posts contained in that page, so it seems that the pages become independent from each other and it’s not what I would like.

You also suggest this, but I honestly didn’t understand what you meant:

To me, it might make more sense to display a <select> list of terms (or 2 <select> lists, one for each taxonomy), and then change the browser location to the pre-rendered, paginated list.

Could you give an example?

P.S.: Regardless of what theme I use, I’m looking for a solution (if possible) that can improve the navigation on my site. I gave an example on the Academic theme just so I could get a compatible answer to my case.

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

Thanks again for this really comprehensive (and powerful) example. Actually I had already thought of a similar thing, maybe I had to read your post more carefully, that is redirect to the list page of each term, and this can work if my site is organized only with posts.

However, if, for example, in addition to posts I had other content (e.g. projects and/or publications) which are then in their respective section folders

.
├── content/
│   ├── post/
│   │   ├── _index.md
│   │   ├── post1/
│   │   ├── post2/
│   │   └── ...
│   ├── project/
│   │   ├── _index.md
│   │   ├── project1/
│   │   ├── project2/
│   │   └── ...
│   └── publication/
│       ├── _index.md
│       ├── publication1/
│       ├── publication2/
│       └── ...
└── other-folders-and-files

and for the single projects/publications I use the same tags and categories used for the posts (e.g. a project and a post related to python with “python” tag), this redirection strategy would create confusion in my opinion.

This is why I would prefer to adopt a different strategy (of course if it is possible and easy to implement).

Otherwise, to do what you did I would have to create two taxonomies for each type of content (post-tag, post-categ, project-tag, project-categ and so on).

In that case don’t direct to the default taxonomy or term pages; create your own templates that are limited to a particular “Type” or “Section” or whatever.

Nix that. For taxonomy pages (just a few) that’s easy enough, but it would be a hassle for term pages.

Thanks again.

Back to my previous question, if I wanted to avoid pagination and directing, then directly filtering the content in the single section page using the <select> feature, how can I do that? That is, how can I tell hugo that clicking on a term in the drop-down menu should only show posts with that specific tag or category?

Assume that I don’t have that many posts and/or projects (e.g. a dozen/twenty or so) and that keeping them on a single page wouldn’t be a big problem (at least in my opinion).

I’ve updated the repository. Either pull changes, or:

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

Fantastic! I really can’t thank you enough. I had been trying to do this on my own for over a month with no results and now you…you’ve done the miracle! Your insights on pagination, directing and filtering in one page was very educational for me.

I also read the issue on “Summary” and “Read more” that you linked, it might be useful for me in the future.

Just one last thing, and then I think we can close the thread (and obviously I vote your post as “solution”): I observed something strange in the “Articles” section where there are 3 taxonomies to filter, maybe it’s the natural behavior of the <select> features or it’s about the Javascript setting to fix, I don’t know.

There is a strange behavior in the matching when multiple taxonomies are filtered simultaneously. I make a practical example:

  1. If you go on the section “Articles” (10 in total)
  2. Select “Category Y” and you get only the articles with that category (5 articles).
  3. Select also a “Color” that is not included in those articles: “Green” or “Purple”, you get again all the 10 articles, so also those with “Category Z”, instead of 0 articles.
  4. Continue to select also a “Tag”, “A” or “Z” is the same, the filter works and you get 2 articles.
  5. Reset and select again “Category Y”.
  6. Select also a “Tag” instead of a “Color”, “A” or “Z” is equal, and you get 2 articles, that both have the “Colors” “Red” and “Blue”.
  7. You select a different color from these two:
    7a) “Green” or “Purple”: the 2 articles remain (strange);
    7b) “Orange” or “Yellow”: 0 articles (good);

Is there a logic behind it or is it a bug? Anyway, it’s not a big problem for me since I will use only 2 taxonomies and I can confirm that in this case, trying on the “Post” section, it works like a charm.

Yeah, that’s a bug. Two issues, actually:

  1. Fix the intersection logic
  2. Dynamically filter select options to display only what’s relevant to the current subset

Both of these are JS issues. Of these two issues, #1 is probably something stupid that I did, and #2 is more difficult. #1 wouldn’t have been exposed if #2 were in place.

What I like about this so far:

  1. Zero configuration: create a taxonomy, create some some content, add a term.
  2. Filter is hidden unless relevant.
  3. All data is “on page” with data attributes instead of in a separately rendered JSON file.

What I don’t like about like this so far:

  1. The issues you identified.
  2. Inability to select multiple terms from the same taxonomy.
  3. Lack of pagination.
  4. It doesn’t leverage existing JS libraries for faceted filtering, re-inventing the wheel.
  5. All data is “on page” with data attributes instead of in a separately rendered JSON file. Even though I kind of like this, in the end I think it makes things more difficult.

What we have so far is a prototype at best, and I’m not terribly thrilled about it.

See https://github.com/javve/list.js

Well, if it’s just a JS bug then I’ll try to handle it on my own (as this is not the right place to discuss about it), even if currently your prototype is already very good for me, since it works very well with two taxonomies.

The only downside, which you have also pointed out several times, is to figure out how to make the filter work in case of pagination, because now that I’ve thought about it I may need in the future to distribute the content on more pages.

In this regard maybe List.js that you suggested might be a solution. I found these 3 examples interesting and close to my case (link1, link2, link3). I might try to “combine” them and create two <select> filters that work on pagination. I think it might be feasible although I am not very familiar with JS…

What do you think about this?

Last question: beyond what was my request in this thread, if you were in my situation, given your experience, how would you organize this site?

I resolved the intersection problem. Please pull changes to test. Still thinking about the rest…

I cloned the repo but when I run hugo server I get this error:

Start building sites .
hugo v0.90.0-DD0D3FDB+extended windows/amd64 BuildDate=2021-12-08T09:33:47Z Vend
orInfo=gohugoio
ERROR 2022/02/07 21:49:19 JSBUILD: failed to transform "js/main.js" (application
/javascript): Could not resolve "list.js"
ERROR 2022/02/07 21:49:19 JSBUILD: failed to transform "js/main.js" (application
/javascript): Could not resolve "list.js"
ERROR 2022/02/07 21:49:19 failed to render pages: render of "page" failed: execu
te of template failed: template: _default/single.html:8:5: executing "_default/s
ingle.html" at <partialCached "head/js.html" .>: error calling partialCached: "C
:\Users\Windows 8\Documents\datascience-projects\website\hugo-forum\new-update\h
ugo-foum-topic-36998\layouts\partials\head\js.html:6:25": execute of template fa
iled: template: partials/head/js.html:6:25: executing "partials/head/js.html" at
 <$js.Content>: error calling Content: JSBUILD: failed to transform "js/main.js"
 (application/javascript): Could not resolve "list.js"
Error: Error building site: JSBUILD: failed to transform "js/main.js" (applicati
on/javascript): Could not resolve "list.js"
Built in 233 ms

I added a component (not implemented yet) since posting here earlier. You have to npm install…

git clone --single-branch -b hugo-forum-topic-36998 https://github.com/jmooring/hugo-testing hugo-forum-topic-36998
cd hugo-forum-topic-36998
npm install
hugo server
1 Like

@jmooring: This is a great demo–I’m trying to replicate the functionality in my docsy project. I’ve copied list.html and the partials/views folder. What else do I need? (I can’t figure out how npm install is works without package.json, and I don’t know what packages are needed.)

First, this was a proof-of-concept. If you can make use of it, great, but I won’t be supporting it.

Second, there must have been some external JS dependency at some point, but not anymore.

It looks like the important bits are:

  • layouts/views/list.html
  • layouts/partials/views/*.*

And then in the section page add this to front matter:

type: views
layout: list

hey! were you able to find a way to select multiple terms from the same taxonomy?