Possible to only display 1 post from each taxonomy from list.html?

My first thought was to call a range function to lookup all posts, and then filter only the first post from each taxonomy (and then only list the taxonomy itself, rather than the post title / link). But I can’t figure out how to write the call properly.

Ultimately I’m just trying to display my taxonomies by date, but since Hugo doesn’t support that I’m trying to hack a workaround (and not doing so well at it).

1 Like

@Justin_Parks I think Hugo can take of everything you just mentioned if you look through the docs.

Use the first keyword to isolate only one item. https://gohugo.io/templates/functions#first

You can also sort your taxonomy pages by date or publishdate…if you look at the docs for sort: https://gohugo.io/templates/functions#sort

{{ range sort .Data.Pages "Date" "desc" }}
YOUR STUFF HERE
{{ end }}

Howdy, rdwatters!

Unfortunately, I don’t think either of those solutions will work for me, and likely I’m explaining my issue improperly. And my terminology is probably way wrong. :\

This isn’t for the main list.html content, but rather for a tag cloud in the siderail (on the list.html page). I’m trying to reference posts whose data isn’t directly tied to the current list.html page I’m on.

Example:

Post 1: has a taxonomy of ‘chapter’ that is set as ‘The beginning’.
Post 2: has a taxonomy of ‘chapter’ that is set as ‘The beginning’.
Post 3: has a taxonomy of ‘chapter’ that is set as ‘The beginning’.
Post 4: has a taxonomy of ‘chapter’ that is set as ‘Chapter 2’.
Post 5: has a taxonomy of ‘chapter’ that is set as ‘Chapter 2’.
Post 6: does not have a taxonomy of ‘chapter’ defined.
Post 7: has a taxonomy of ‘chapter’ that is set as ‘Moving on’.

Using the above example, I want my tag cloud to read:

  • The beginning
  • Chapter 2
  • Moving on

It should list only the 3 entries that are defined for the ‘chapter’ taxonomy.

If I use the call:

{{ range .Data.Pages.ByDate }}
    {{ with .Params.chapter }}
        {{ index . 0 }}
    {{ end }}
{{ end }}

That returns:

  • The beginning
  • The beginning
  • The beginning
  • Chapter 2
  • Chapter 2
  • Moving on

That returns a result for every post (minus Post 6, which didn’t have a taxonomy for ‘chapter’ defined). Not quite what I’m looking for.

Here I’ve attempted to implement the ‘first’ filter:

{{ range first 1 .Data.Pages.ByDate }}
    {{ with .Params.chapter }}
        {{ index . 0 }}
    {{ end }}
{{ end }}

But that returns only the first tag and stops there:

  • The beginning

I can’t figure it out how to get Hugo to compare each new result against the result before; to tell Hugo “if you’ve encountered a post with this taxonomy definition already, skip it”.

Hope that explains it better?

@Justin_Parks Possibly. Do you have an open GH repo you can point me to? Can you do me a favor and send me an example of the metadata/front matter in a content file. When you say “taxonomy,” are you setting this up as a taxonomy in your config file or are you just talking about a key-value pair in a content file?

I’m thinking maybe the .GroupBy will help you in this case, but I’m still not completely groking what you’re trying to get done…

<ul>
{{ range .Data.Pages.GroupBy "chapter" }}
<li>{{.Key}}</li>
{{ end }}
</ul>

But you mentioned something about sorting by date, which you could do within the pages of each group (ie, within each “chapter”) and even grab the first one as follows:

<ul>
    {{ range .Site.Pages.GroupByParam "chapter" }}
        {{range first 1 .Pages.ByDate.Reverse }}
        <li>{{.Params.chapter}}</li>
        {{ end }}
    {{ end }}
</ul>

This would then print out the following per your request above:

  • The beginning
  • Chapter 2
  • Moving on

That said, if chapters are set up as an actual taxonomy in your config.toml file…

[taxonomies]
  chapter = "chapters"

Then add chapters: The Beginning, etc to the frontmatter/yaml/metadata of your content files.

Then you could pull up each value in the key-value (ie, chapter => chapter name) as follows within another template (I’d recommend adding this as an include if you want to repurpose it across multiple layouts:

<ul>
    {{ range $chapter, $taxonomy := .Site.Taxonomies.chapters }}
    <li>{{$chapter}}</li>
    {{ end }}
  </ul>

Also, I’m not sure what you mean by “tag cloud.” Are you trying to get the total number of pages/content files for each chapter? Is this so that you can visually show how the total number of pages are weight? Something like this? If so, I’d recommend using an actual Hugo taxonomy in your config and front matter so that you can easily pull up the total number of pages for each as follows…

<ul>
    {{ range $taxonomy, $chapter := .Site.Taxonomies.chapters.ByCount }}
    <li data-count="{{$chapter.Count}}">{{$chapter.Name}} </li>
    {{ end }}
  </ul>

Hope that helps.

Yup, that one. Except they’re both singular, so:

[taxonomies]
  chapter = "chapter"

Can’t recall my reasoning for that right now. But that’s how it’s set up.

And then the front matter on each post I have the chapter defined like so:

+++
title = "Post 1"
date = "2004-07-05T04:21:02+00:00"
chapter = ["The beginning"]
+++

Currently I have my tag cloud (‘tags’ is a taxonomy… so is ‘chapter’… therefore, ‘tag cloud’. again, my terminology is probably wrong) built like in your example:

{{ range $name, $taxonomy := .Site.Taxonomies.chapter }}
    <li>{{ humanize (string $name) }}</li>
{{ end }}

But that exports the following:

  • Chapter 2
  • Moving on
  • The beginning

The entries are alphabetized, rather than in the order they’re meant to be read (by date).

The example you showed above using ‘GroupByParams’ looked promising, but I take it that’s not meant to be used in the manner that I’ve set up my chapter taxonomy? I keep getting an “error calling GroupByParam: There is no such a param” error.

I tried adding a param to my post:

[params]
	chapter = "The beginning"

…but I’m throwing the same error. I’m clearly doing something wrong there.

Edit

My live repo is a mess, so I cleaned up a mock repo quick to show what I’m trying to do and how I’m currently doing it:

Got it working, but I’m hoping there’s a faster way:

{{ range where $.Site.Pages.ByDate ".Params.chapter" "!=" nil }}
    {{ $link := .Permalink }}
    {{ range $name, $taxonomy := .Site.Taxonomies }}
        {{ if eq "chapter" $name }}
            {{ range $key, $value := $taxonomy }}
                <ul>
                    {{ range first 1 $value.Pages }}
                        {{ if (eq .Permalink $link) }}
                            <li>
                                <a href="/chapter/{{ $key | urlize }}" class="tag" title="{{ humanize (string $key) }}">
                                    <span>{{ humanize (string $key) }}</span>
                                </a>
                            </li>
                        {{ end }}
                    {{ end }}
                </ul>
            {{ end }}
        {{ end }}
    {{ end }}
{{ end }}

This essentially searches through every single post that has an entry defined for the ‘chapter’ taxonomy, then searches through every single taxonomy entry and compares them against each other to only return one post per ‘chapter’.

It gets the job done, but for only 20 chapters over 390 pages it’s adding 3000ms to my build time.

I’m 4 days into finding a solution, so I’m gonna stick with this for now barring any further help from someone with a better solution.

@Justin_Parks Sorry for the delay, but it’s been a crazy week. I think I may have a considerably DRYer solution for you:



<ul>
{{range $chap,$tax := .Site.Taxonomies.chapter}}
    {{ range first 1 $tax.Pages.ByDate.Reverse}}
    <li><a class="tag" href="{{.Permalink}}">{{.Title}}</a></li>
    {{end}}
{{end}}
</ul>

I’m not sure if the {{.Permalink}} is going to work within the anchor within the li since I’m unaware of your intended site architecture. If there is a terser solution, I’m betting @digitalcraftsman has it at the ready.

Are you trying to make each list item link to the taxonomy page for the chapter OR the actual post?

What I gave you above will link directly to the post, but if you want to link to the taxonomy list page for the entire chapter, change the <li> as follows:

<li><a href="/chapter/{{$chap}}">{{$chap | humanize | title}}</a>
<!--Assuming you want to title case the title of the chapter; if not, remove "| title"-->

Also, looking at your repo, I think you’re adding some unnecessary templating. E.g., the follwoing from your [book.html] (https://github.com/kaigon/testsite/blob/master/layouts/partials/book.html) partial:

{{ if and (isset .Params "chapter") (and (not (eq .Params.chapter "")) (not (eq .Params.chapter nil))) }}
  <div class="tags tags--chapter">
    <!--<label>chapter</label>-->
    {{ range .Params.chapter }}
      <a href="{{ "/chapter/" }}{{ . | urlize }}" class="tag" title="books in the &ldquo;{{ . }}&rdquo; chapter">
        <span>{{ . }}</span><i class="icon-tag" data-grunticon-embed></i>                            
      </a>
    {{ end }} 
  </div>
{{ end }}

I think for what you’re trying to do, you can get away with the following:

{{with .Params.chapter}}
  <div class="tags tags--chapter">
    {{range . }}
    <a href="/chapter/{{ . | urlize }}" class="tag" title="books in the &ldquo;{{ . }}&rdquo; chapter">
      <span>{{ . }}</span><i class="icon-tag" data-grunticon-embed></i>                            
    </a>
    {{end}}
  </div>
{{end}}

It seems like title="Pages in the {{. | title }} Chapter" would make more sense, but I don’t have access to the complete site :wink:

You’re also keeping all your single-page layouts/_default/single.html. I think you’d be better off creating a single.html for each respective section rather than trying to treat a partial like a layout…just a thought.

Thank you again for your reply!

And thank you for your suggestions regarding the book.html / single.html pages. I’ll give those a try. Finding the with function earlier would have made building that page much easier. And you’re right on the ‘title’ tag referencing books instead of pages. Whoops.

Regarding the taxonomies solution, however, I’m still running into the same issue where the taxonomies are being listed in alphabetical order, rather than by date:

  • Chapter 2
  • Moving On
  • The Beginning

I think this is because the initial {{ range }} call is by taxonomy first, which is sorted alphabetically by default. The subsequent range call for ‘first 1 by date’ is then grabbing the earliest dated post in each already sorted chapter.

Which means that even though Post 1 has the earliest date, it’s still listed last because it’s associated with the chapter with the highest letter.

I think ultimately I’m probably going to have to change how I’m structuring my individual posts. The code I posted above works, but I worry what that’ll do to my build time as my archives grow. And this would be a lot simpler if I simply had an additional taxonomy of ‘chapter_number’ or something.

At least now I’ll have working code for when I do. :slightly_smiling:

Thank you again, @rdwatters!

No worries. Rather than chapter number, I would recommend adding a “weight” since that has innate value in Hugo and will add more flexibility later on. It’s also the first default piece of front matter by which Hugo orders content (i.e., when explicitly available).