Get first three posts in a tag in a section

Potentially peculiar request, but here we go.

I want to list the first three posts in a tag (mytag). This is trivial, but I then find my top-level pages are included, so I only want those in section /news.

My initial thought was to do (as per number 3)
{{ range .Site.Sections.news }}
{{ $.Scratch.Set “page-title” .Page.Title}}
{{ range $key, $taxonomy := .Page.Params.tags }}
{{ if eq $taxonomy “mytag” }}
{{ $.Scratch.Get “page-title” }} //Display page title.
{{ end }}
{{ end }}
{{ end}}

Which is fine, but because I want to do range first 3, this doesn’t seem to work.
At least, I can’t figure out an appropriate place to put it.

I then thought to delay the display until below this, storing each displayed title in an array and then doing a for loop over the first three, but that sounds highly inefficient.

Has anyone got any ideas? Vastly appreciated!

Are you trying do build a featured articles box? Me, too. So +1 for this issue.

As I haven’t understood yet how to “read” from tags (i.e. look if a certain tag is amongst the given tags - I guess that’s what you’re doing with “if eq”), I created a pretty clumsy workaround with an additional params called “featured” and then used:

`` {{ range first 5 (where .Site.Pages “Params.featured” “!=” nil) }}

(So If I add something to the “featured” params, the post is marked as a featured post)
I know, that’s not what you are looking forward, but maybe a similar approach can be applied to your issue?

1 Like

@samozzy I was trying to figure out a solution for this last night to no avail. Have you tried ranging through .Site.Taxonomies.tags.mytag and then using intersect?

https://gohugo.io/templates/functions#intersect

@inspiritana

I guess that’s what you’re doing with “if eq”

if eq $this “that” checks if $this is equal to “that”. Hope that helps with that syntax?
I used this way with $key and $taxonomy because I wasn’t sure the best way to go about it otherwise. I think there are some scope issues with doing it within the range of .Site.Sections.news.
That might work, actually. I guess .Site.Pages “Params.tags” “==” “mytag” should be accessible within the scope…

@rdwatters
intersect seems to be the most efficient way of doing things - doing two ranges at the same time, effectively. Something like intersect (.Page.Params.tags “mytag”) (.Page.Section.news, perhaps.
What would be the correct syntax for this - especially allowing to do a range first 3?

{{ range (where .Site.Pages "Section" "news") }} 
    {{ range (where .Params.tags "mytag") }}
        .... Stuff ....
    {{ end }} 
{{ end }}

This goes badly. (error where: can’t evaluate the array by no match argument or more than or equal to two arguments)
There aren’t enough arguments for where, and where .Params “tags” “mytag” results in more errors (can’t iterate over map).

Using intersect, I can’t think of a way that allows for use of the first command.

I’m stuck trying to figure out how to list the first three posts in a tag (which is apparently trivial! :confounded:)

What I have is:

{{ range first 3 (where .Site.Pages "Params.tags" "Review") }}
  {{ .Render "featured" }}
{{ end }}

This works if I were to do another parameter with only one value such as "Params.author" "Author Name", but I can’t get this to work when ranging through Params.tags.

I have also tried "Params.tags" "in" "Review" and "Params.tags" "==" "Review", but I get no results — these all work when the parameter has only one value. I’ve been searching the forum for other similar use cases, but I’m just not figuring this out. I have done a similar method as @inspiritana when trying to prevent certain pages from displaying a summary on the homepage, but I’m really interested in understanding how to range through arrays properly.

1 Like

I think you’re on the right lines with using in:

     {{ range .Site.Pages }}
      {{ if in .Params.tags "mytag" }}
        {{ .Title }}
      {{ end }}
     {{ end }}

For instance works as intended.
Getting the first 3 is now the difficult part again.

Hi, did you solve this issue?

I have the same and didn’t find a solution yet. :frowning:

Good afternoon. Is there a solution? I also want to output 2 articles that have tags for the current article (the current article may have several tags set)

{{ range first 3 (where .Site.Taxonomies.tags.featured.Pages "Section" "news") }}
  {{ .Title }}
{{ end }}

Or:

{{ $mytag := "featured" }}
{{ range first 3 (where (index .Site.Taxonomies.tags $mytag).Pages "Section" "news") }}
  {{ .Title }}
{{ end }}
3 Likes

Hello! I have config

[taxonomies] category = "category"

I have the categories in each page:

category = ["CDN", "Hosting"]

I want to display two entries from the BLOG section, which have CDN categories, and Hosting. It is important that there is no current record among these records.
In the end, we get something like the “Similar Posts” block.

My code is not work
{{ range first 2 (where .Site.Taxonomies.category.category.Pages "Section" "blog") }} {{ .Title }} {{ end }}

Try .Site.Taxonomies.category.hosting.Pages

This only works on one taxonomy term at a time; you’d need to use intersect if you need the first two entries that contain both taxonomy terms. I don’t have time to work out an example for that at the moment (bedtime!).

-j

1 Like

Ok. thanks.

Yes, ideally, you need to automatically take all categories of the record and look for them. This really is not enough.

Unfortunately, I haven’t been able to get in to work with taxonomy tags in a where; I always end up with an empty set. I banged my head into a wall for a while before I decided to invert the selection process.

-j

I have overcome the one taxonomy term limitation, by simply using a custom featured parameter in the frontmatter of posts I want to display in the index.

          {{ range first 4 (where .Data.Pages "Params.featured" "eq" "true") }}
           .....
           {{ end }}

If you also need different titles for every two posts look here: https://discuss.gohugo.io/t/conditionnal-range-data-css-class-at-n-elements/6496/3

Okay, this is gross, but since intersect and in didn’t work (string/interface array issues that are apparently known bugs), it’s the best I could come up with. So, given an entry in config.toml like this (lower-case because taxonomy terms are normalized):

[params]
featured = ["cdn","hosting"]
{{ range where .Site.RegularPages "Section" "news" }}
  {{ $.Scratch.Set "tmp" 0 }}
  {{ range .Params.categories }}
    {{ if in $.Site.Params.featured . }}
       {{ $.Scratch.Add "tmp" 1 }}
    {{ end }}
  {{ end }}
  {{ if eq ($.Scratch.Get "tmp") (len $.Site.Params.featured) }}
    {{ $.Scratch.Add "match" (slice .) }}
  {{ end }}
{{ end }}
<ul>
{{ range first 2 ($.Scratch.Get "match") }}
  <li>{{ .Title }}</li>
{{ end }}
</ul>

Warning: it’s slow, since it’s looping over every article in the section. Not significant for smallish sites, but when I tested it on the paginated homepage of my large blog (2,850 articles, 357 pages), the build time went from 13 seconds to 43!). You only want to run this once per site, perhaps in a partialCached template.

-j

thanks for that, bro

You can use intersect here.

{{ $news := where .Site.Pages "Section" "news" }} // news content
{{ $taggedContent := .Site.Taxonomies.tags.mytag.Pages }} // content by tag
// OR you can pass in a variable if you don't want to hard-code the tag
{{$taggedContent := (index .Site.Taxonomies.tags (lower $mytag)).Pages }}
{{ $pages := intersect $news $taggedContent}} // Give you the pages that meet both queries

{{ range first 3 $pages }}
   {{ .Render "summary" }} or whatever you want to render...
{{ end }}
1 Like