How to group content by param when all the content lives in front matter one markdown page?

My site is setup to utilize Forestry’s Blocks feature so that it works more in a modular way. So, the pages are created by stacking reusable page templates together to create block sections. All the content lives in the front matter.

I’m essentially using a version of the Sawmill theme: https://forestry.io/blog/sawmill-layout-composer-for-hugo-and-forestry/

For example, in my index.md, I have a block called “team” that I’m using to create a team section that includes things like name, image and bio.

[[blocks]]
background_style = "White"
heading = "Team"
team_by_location = [Chicago]
template = "team"
[[blocks.team]]
bio = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
image = "/uploads/image.jpeg"
job_title = "Media Manager"
name = "Jackson Clark"

This is my “team.html” template block where the content is being used:

<section id="{{ .Params.heading | urlize }}" class="section {{ partial "blocks/meta/background-style" .Params.background_style }}">
<div class="mx-auto mx-auto container">
  {{- with .Params.heading -}}
  <h2 class="title md:text-4xl title-center">{{ markdownify . }}</h2>
  {{- end -}}
  <div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-10 lg:gap-20">
    {{ range .Params.team }}
    <div>
      <img class="w-full border-b-2 border-primary object-cover" style="height:350px;" src="{{ .image }}">
      <div class="text-center py-4">
        <h4 class="text-xl lg:text-2xl leading-tight font-medium">{{ .name }}</h4>
        <p class="mb-4 text-base">{{ .job_title }}</p>
        <button class="bg-transparent text-primary uppercase px-4 py-1 border border-primary hover:bg-primary hover:text-white transition-all duration-300" data-featherlight="#{{ .name | urlize }}-modal">About</button>
      </div>
    </div>
    {{- end -}}
  </div>
</section>

This works great. But, the people I’m building this for also want to be able to group/view the team members by location. So, for example, the people with a location set to “Chicago” should only be viewed in a tab labeled “Chicago.”

So, I tried this:

  <div class="flex justify-center text-lg md:text-xl">
    {{ range .Params.team_by_location }}
    <button class="tablinks mr-10 focus:outline-none" onclick="openTeam(event, '{{ .location }}')" id="defaultOpen">{{ .location }} Team</button>
    {{ end }}
  </div>
  <div id="location-name" class="tabcontent">
    <div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-10 lg:gap-20">
      {{ range .Params.team_by_location }}
      <div>
        <img class="w-full border-b-2 border-primary object-cover" style="height:350px;" src="{{ .image }}">
        <div class="text-center py-4">
          <h4 class="text-xl lg:text-2xl leading-tight font-medium">{{ .name }}</h4>
          <p class="mb-4 text-base">{{ .job_title }}</p>
          <button class="bg-transparent text-primary uppercase px-4 py-1 border border-primary hover:bg-primary hover:text-white transition-all duration-300" data-featherlight="#{{ .name | urlize }}-modal">About</button>
        </div>
      </div>
      {{- end -}}
    </div>
  </div>

But, this doesn’t really work. First, if there is more than one person per location, it will display the same location multiple times. Second, the tabs need to be linked to the corresponding div to work properly. So, the div that holds the people from Chicago must have an id=“Chicago”, otherwise the content won’t switch. Similar to the first problem, I can’t figure out how to just display the location just once and how to filter the people by the location parameter.

Hopefully that all made sense! Any thoughts on how I could do this?

Here’s a simplified example of what I think you are trying to accomplish. I used a shortcode instead of a template to display the team members, but the logic is the same.

content/post/test.md:

+++
title = "Test"
date = 2020-07-09T16:13:51-04:00
draft = false

[[blocks.team]]
first_name = "Mary"
last_name = "Smith"
location = "Chicago"

[[blocks.team]]
first_name = "John"
last_name = "Doe"
location = "Chicago"

[[blocks.team]]
first_name = "Robert"
last_name = "Jones"
location = "New York"

[[blocks.team]]
first_name = "Cathy"
last_name = "Nguyen"
location = "Los Angeles"

[[blocks.team]]
first_name = "Mary"
last_name = "Smith"
location = "Chicago"

[[blocks.team]]
first_name = "Janice"
last_name = "Williams"
location = "New York"
+++

{{< teams >}}

I have intentionally duplicated one of the team members, Mary Smith.

layouts/shortcodes/teams.html:

{{/* Build unique, sorted slice of locations. */}}
{{- $locations := slice -}}
{{- range $.Page.Params.blocks.team -}}
  {{- $locations = $locations | append .location -}}
{{- end -}}
{{- $locations = $locations | uniq | sort -}}

{{/* Display team members, grouped by location, sorted by last name, duplicates removed. */}}
{{- range $locations }}
  <h2>{{ . }}</h2>
  {{- range sort (uniq (where $.Page.Params.blocks.team "location" "eq" .)) "last_name" "asc" }}
    {{ printf "%s %s" .first_name .last_name }}<br>
  {{- end }}
{{- end -}}

Result:

<h2>Chicago</h2>
  John Doe<br>
  Mary Smith<br>
<h2>Los Angeles</h2>
  Cathy Nguyen<br>
<h2>New York</h2>
  Robert Jones<br>
  Janice Williams<br>
1 Like