I’m looking for a way to dynamically filter pages by their taxonomy.
Let’s say I have a taxonomy ‘brands’ and I have several pages with the brand ‘nike’, and others with the brand ‘reebook’
If I list nike like this, it works:
{{ range .Site.Taxonomies.brands.nike.Pages }}
{{ . }}
{{ end }}
But I want ‘nike’ to be a variable, so I can use it on a template also for ‘reebook’ and other brands.
Something like this:
{{ range .Site.Taxonomies.brands.$brand.Pages }}
{{ . }}
{{ end }}
I do have a Taxonomy for brands.
The problem is that all brand pages need a logo and a link. How I solved this problem was creating single pages for each brand with frontmatter for the logo and link. For example nike.md Like so:
+++
title = "Nike"
logo = "path-to-logo.svg"
link = "https://nike.com"
brands = ["Nike"]
+++
Then I want to list all pages that have a taxonomy term of nike.
Basically, all I want to do is to list all pages that are within the same series as the index page. If I’m in the nke page,
show me all pages that have ‘Nike’ in ‘brands’. The docs example says that you can do it like this:
<ul>
{{ range .Site.Taxonomies.series.golang }}
<li><a href="{{ .Page.RelPermalink }}">{{ .Page.Title }}</a></li>
{{ end }}
</ul>
But that doesn’t work for me because you would have to hard code the taxonomy term. I need it to be dynamic.
I tried several things along those lines. But something like this may work for menus, but not for taxonomies:
{{ range (index $.Site.Taxonomies.brands $brand) }}
I tried $brand = "Nike" but of course I then realized that it shouldn’t be a string. It should be a taxonomy object. I also got confused trying to do that. I guess I should have ranged trough taxonomies and then scratched the taxonomy that matches… right? Something like that… I’ll have to play with that.
Anyway, I managed to find a solution but it is horrible, and I’m sure there should be an easier method. I mean, listing all the pages under the same taxonomy is something very common. So if somebody has a nicer solution, please show me the light!
Here’s what I did:
{{ range .Site.Taxonomies }}
{{ range $key, $value := . }}
{{ if eq (urlize $key) (urlize (lower $.Title)) }}
{{ range $value.Pages }}
{{ .Title }}{{ .Params.logo }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
I’m comparing the page title against the taxonomy term. {{ if eq (urlize $key) (urlize (lower $.Title)) }} I needed to urlize and lower them because some had latin characters.
As I said, it works, but it’s ugly. I’m pretty sure that it isn’t very efficient either. Luckily hugo is lightning fast, so I don’t really care if the build takes 0.5s longer.
i thought if you tell hugo the taxonomies you are using in your config file, it’ll automagically make all the taxonomy list pages for each taxonomy and for each term… to be found at example.com/brand/nike that’s how it works for a site i have with example.com/tag/easy
@guayom I’m wondering if you need to deal with the hassle of all that data entry in the front matter. Are you naming these logo files individually as you add files? Why not create the logo link dynamically accordingly to other values from the front matter since it’s not really beneficial to the content type?
Also, in the interest of code terseness, I believe that lower is redundant with urlize, maybe?
You’re absolutely right, about the urlize and the lower. Thanks for the advice!
About the logos, I’m using brands as an example, so anyone can easily understand what I’m trying to do. But in reality, the logo is not the only info I need for each taxonomy. I also need descriptions, urls, and other metadata. So even if I fix the issue by naming the images dynamically, I would still need to find a solution for all the other data.
I’m trying to add metadata to each taxonomy (I asked for help here), and so far, the best way I’ve found is to put all that metadata in a page. But of course, if you know any tricks, or if you can point me to a repo that has solved that issue differently I would definitely appreciate it a lot!
Depends. Are you doing this all from scratch or are you importing as serialized data from elsewhere? If the latter, you may be able to do this with data files. Generally speaking, I think it’s best to keep front matter to just metadata about that exact instance of content, although of course you have the right to organize this however you’d like. I just know it can be a real pain in the neck when you have to do all that manual data entry. As far as taxonomies are concerned, keep in mind you can set up metadata and content per term using _index.md files which can be accessed using the .GetPage function…
I’m importing data from an old joomla site, so yeah, making data files would be as easy as creating the pages I already created. I wrote a ruby script for that, so none of that is being done manually and I wouldn’t mind changing my current structure.
But you leave me with a doubt… I have files for each brand, like /brands/nike.md. That’s where I put all the metadata for each taxonomy and term. Is that somehow different from having /brands/nike/_index.md ? If that’s so, please tell me more.
Well /brands/nike/_index.md replicates your taxonomy in a Hugo section and _index.md refers to the list page of said taxonomy term. This is currently the documented way to enter metadata and other parameters in taxonomy list pages.
What you already have is a section called /brands/ and all the .md within are more like content pages of this section.
From what you’re saying if your taxonomy is called brands it seems that Hugo thinks that the content file under /brands/nike.md refers to the list page that is available under /brands/nike/
If you got this to work, i.e. you managed to get the different logo per taxonomy list page I don’t see a reason why you would need to change it.
Actually I find what you did quite interesting since it’s undocumented.
The “official way” of inserting metadata to taxonomy list pages would require you to create a folder per brand. And that is a lot of folders.
You my friend, have just found a way to pass custom parameters to taxonomies without replicating the taxonomy URL as a folder structure.
I have just tested what you did and I am able to render any frontmatter parameter I want per taxonomy through my /_default/list.html and also I can pass different meta descriptions in the head partial.
I always hated having to replicate the taxonomy URL as a folder structure and I was resorting to dirty hacks like doing URL checks per taxonomy.
It’s very nice to hear that! It sure works for me! I also tried with data files last night, but I started getting into other complications, so I decided to stick to this method.
I also noticed that given this structure, instead of trying to filter pages by taxonomy, I will just list pages from ‘brands’ section. Maybe I was overcomplicating everything. I try it out.
so… what’s the magical trick here? Having a taxonomy with the same name as a section? Can you explain the process step by step of what you are doing to help illuminate what’s going on and how to use it?
That’s it, you create a taxonomy (ie brands) and then for each term, you create a page (ie /brands/nike.md). Now in that page you can add all the metadata you need for that specific brand, for example a logo and a description.
How is that useful? You can add metadata to your taxonomies.
I don’t know if @alexandros would have something to add here.
I’ll create a more detailed description in tips and tricks.