List related pages on blog posts

I am trying to figure out the best way to list related (headless pages on another page (blog post).
Both pages share the same taxonomy, however, the pages I am trying to list alongside the current page are headless pages.

What is the best way to go about this? Is it even possible with pages outside of RegularPages?

Hmmm, not sure. Have you tried any of the other options from https://gohugo.io/variables/site/#site-pages?

@maiki It is more that I am trying to only display the pages that share the same tags as the current post.

I sort of have it working here (see the left column under the author). https://demo.digital.gov/2018/07/10/introducing-accessibility-for-teams/
I am trying to get the related “promos” for a given article. Promos are the headless pages.

Here is the code I have so far:

{{/* Gets the tags associated with this post */}}
{{ $post_tags := .Params.tag }}

{{/* For each tag in the post... */}}
{{ range $i, $tag := $post_tags }}

  {{/* Get all the promos */}}
  {{ $promos := $.Site.GetPage "page" "promo" }}

  {{/* Get all the promos WHERE page weight == 3 */}}
  {{ $promos := where ($promos.Resources.ByType "page") ".Params.weight" 3 }}

  {{/* If there are any promos */}}
  {{ with $promos }}

    <section id="related_promos">
    {{/* For each promo */}}
    {{ range $i, $e := . }}

      {{/* get the tags associated with the promo */}}
      {{ $promo_tags := .Params.tag }}

      {{/* If the $tag is in one of these promos,... */}}
      {{/* display the promo */}}
      {{ if in $promo_tags $tag }}

      <article class="promo">
        {{ if .Params.icon }}
        <img src="/img/promos/{{ .Params.icon }}" alt="{{ .Params.head }} Icon">
        {{ end }}
        <h3><a href="{{ .Params.src }}?dg" title="{{ .Params.head }}">{{ .Params.head }}</a></h3>
        <p>{{ .Params.summary | markdownify }}</p>
        <a href="{{ .Params.src }}?dg" title="{{ .Params.head }}"><span></span></a>
      </article>
      {{ end }}
    {{ end }}
  </section>
  {{ end }}
{{ end }}

The problem is that by looping through each of the post tags, and then getting the promos that have the share tag, I am creating duplicate promos.

You can see :point_up_2: that Accessibility for Teams is duplicated, and that is because the post is tagged with the following tags:

tag:
  - methodology
  - accessibility
  - design

And the Accessibility for Teams promo is tagged with

tag:
  - accessibility
  - design

So it is showing up once during the “accessibility” loop, and then again for the “design” loop

Maybe I should be making an empty variable and pushing the promos (headless pages) that match into that var, and doing something on that var (uniq?) to make sure the items in that loop are not duplicates?
That is what I would be doing in JS or PHP…

I was thinking there is probably a function you run your results through that does what you need… is your demo repo available?

Oh, how about uniq?

Edit: ah, you said that in your post, I saw it as var(uniq?), so I didn’t recognize it. :slight_smile:

1 Like

@maiki yes it is: https://github.com/GSA/digitalgov.gov/tree/demo [demo branch]

Yes, possibly Uniq, but I am unclear how to push to an empty var, like I would in PHP or JS… and can that var hold the page object/reference, or just strings?

Heya @jeremyzilar, I’m a bit tired, so I’m just poking around. Why are there three related_promos sections?

I’d copy and paste them here, but there are also hundreds of blank lines… and I can’t figure out where that is getting added. Is another partial messing with your get_promos.html?

So I figured this out — but I would LOVE for someone to check me on this, as I feel like this solution is probably very taxing on performance…

{{/* Gets the tags associated with this post */}}
{{ $post_tags := .Params.tag }}

{{/* IMPORTANT */}}
{{/* This is an empty array (a.k.a. slice) */}}
{{ $.Scratch.Set "related_promos" (slice " ") }}

{{/* For each tag in the post... */}}
{{ range $i, $tag := $post_tags }}

  {{/* Get all the promos */}}
  {{ $promos := $.Site.GetPage "page" "promo" }}

  {{/* Get all the promos WHERE page weight == 3 */}}
  {{ $promos := where ($promos.Resources.ByType "page") ".Params.weight" 3 }}

  {{/* If there are any promos */}}
  {{ with $promos }}

    {{/* For each promo */}}
    {{ range $i, $e := . }}

      {{/* get the tags associated with the promo */}}
      {{ $promo_tags := .Params.tag }}

      {{/* If the $tag is in one of these promos,... */}}
      {{/* display the promo */}}
      {{ if in $promo_tags $tag }}

      {{/* This appends/adds the .File.LogicalName to the array */}}
      {{ $.Scratch.Add "related_promos" (slice .File.LogicalName ) }}

      {{ end }}
    {{ end }}
  {{ end }}
{{ end }}

{{/* Removes the duplicate file names in the array */}}
{{ $related_promos := uniq ($.Scratch.Get "related_promos") }}

{{ if $related_promos }}

  <section id="related_promos">

  {{/* Let's loop through the file names! */}}
  {{ range $i, $e := $related_promos }}

    {{/* Identifies the area to look for the file name */}}
    {{ $headless := $.Site.GetPage "/promo" }}

    {{/* Gathers all the files that match the file name ($e) */}}
    {{ $reusablePages := $headless.Resources.Match $e }}

    {{/* Finally we can loop through all of the promos/files */}}
    {{ range $reusablePages }}

      <article class="promo">
        {{ if .Params.icon }}
        <img src="/img/promos/{{ .Params.icon }}" alt="{{ .Params.head }} Icon">
        {{ end }}
        <h3><a href="{{ .Params.src }}?dg" title="{{ .Params.head }}">{{ .Params.head }}</a></h3>
        <p>{{ .Params.summary | markdownify }}</p>
        <a href="{{ .Params.src }}?dg" title="{{ .Params.head }}"><span></span></a>
      </article>

    {{ end }}

  {{ end }}
  </section>
{{ end }}

I would really recommend looking into this:

It should be thousand times faster than any home brew solution.

@bep It was my understanding from reading that page that Related only worked with .RegularPages, not headless pages… Maybe I am mistaken.

OK, I read your post a little to fast. Yes, your use case may not be a candidate for “releated content” – but it isn’t true that that is only for .RegularPages – it works for any collection of type Pages of which there are plenty ways to get (.Pages, .RegularPages, where, append etc.).

@bep
I am also reading into that page and see that Related matches ALL pages across the site…

Is it possible to get only a subset of pages matched in related pages
Like, only get related /content/promos/ on one template or get related /content/reviews. on another?

@jeremyzilar I don’t have a lot of experience with related content (defaults normally work for me), but I believe you can set the indices and weights, and use front matter to relate pages. But that is presuming your related content is regular content file, and not headless nodes.

It is an evolving practice to keep what normally is “data” in a headless bundle, so it can be edited like a normal content file, rather than a data formate like JSON. At first it looks like it solves that issue of wanting a place to stash content without creating a web page (and sitemap entry and RSS entry) for it, but it doesn’t quite work that way, yet.

1 Like

@maiki thanks for taking a look last night. I do think this will work for me now…
And as a result, I have a better understanding of how Hugo works.

1 Like