Template logic for Related posts

Taking code from http://justindunham.net/blog-bells-and-whistles-in-hugo/
How can I first build the slice of related posts, and then decide if length greater than 0, then show “Related articles” block, and render first 5 in the list.

Code: -

    <div id="related-posts" class="row">
         {{ $page_link := .Permalink }}
         {{ $tags := .Params.tags }}
         <h3>RELATED ARTICLES</h3>
         <ul>
              {{ range (where .Site.Pages "Section" "article") }}
              {{ $page := . }}
              {{ $has_common_tags := intersect $tags .Params.tags | len | lt 1 }}
              {{ if and $has_common_tags (ne $page_link $page.Permalink) }}
              <li><a href="{{ $page.Permalink }}">{{ $page.Title }}</a></li>
              {{ end }}
              {{ end }}
              </ul>
    </div>

I tried {{ range first 5 (where ...)}}, but this will filter out first 5 post which may not contain the related post.

Is there any way to initialize a slice/array, add related to it and then apply range first N over this new array/slice.

1 Like

I found a more performant code snippet dropped last August. I’ve adapted it in After Dark to support conditional list display. Here’s the end result:

{{ range first 1 (where (where .Site.Pages ".Params.tags" "intersect" .Params.tags) "Permalink" "!=" .Permalink) }}
  {{ $.Scratch.Set "has_related" true }}
{{ end }}

{{ if $.Scratch.Get "has_related" }}
  <aside>
    <header>Related Content</header>
    <ul>
      {{ $num_to_show := .Site.Params.related_content_limit | default 7 }}
      {{ range first $num_to_show (where (where .Site.Pages ".Params.tags" "intersect" .Params.tags) "Permalink" "!=" .Permalink) }}
        <li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li>
      {{ end }}
    </ul>
  </aside>
{{ end }}

This uses uses range to loop over pages until it finds its first match, setting a Boolean in $.Scratch, which is then used to conditionally output 7 related pages, with optional limit override, in reverse chronological order (the Hugo default). Note this will grab pages across sections and not just posts.