How to select both pages and sections on the same level

I’m porting a very small site from nanoc to Hugo. The content layout looks something like the tree below. My problem is with the software section. I want to build a navigation that lists “project1”, “related_project_group”, and “project4”, but not “project2” and “project3”. I want to select just the pages (a mix of regular and section pages) below the “software” level.

I tried for a while now and I couldn’t figure out how to do this. When I try .Site.Home.Pages, I’m not getting the “related_project_group” item because it is not a regular page. When I try something like .Site.Pages I’m getting not just one level but all levels.

What is the best way to accomplish this?

content
├── _index.md
├── info
│   └── page1
│       └── index.md
├── software
│   ├── project1
│   │   └── index.md
│   ├── related_project_group
│   |   ├── _index.md
│   |   ├── project2
│   |   │   ├── ...
│   |   │   └── index.md
│   |   ├── project3
│   |   │   ├── ...
│   |   │   └── index.md
│   |   └── update.plist
│   └── project4
│       └── index.md
└── ...

Try:

{{ range where .Pages "Section" "software" }}
  {{ .Title }}
{{ end }}

Thanks for the tip. I had already tried that and that gives me

project1
project2
project3
project4

but not “related_project_group”. I.e. it omits the section that I want, and it adds the two lower-level pages that I don’t want.

Do you think your snippet should give me what I want? If so, something else in my content might be wrong and I’ll try to reproduce it in a small standalone project (However my project is pretty simple already and I just changed the names in the example above).

Given this content:

├───content
│   └───software
│       ├───project1
│       │       index.md
│       │
│       ├───project4
│       │       index.md
│       │
│       └───related_project_group
│           │   _index.md
│           │
│           ├───project2
│           │       index.md
│           │
│           └───project3
│                   index.md

Then this template code:

{{ range where .Pages.ByTitle "Section" "software" }}
{{ .File.Path }}
{{ end }}

Gives this output:

software\project1\index.md

software\related_project_group\project2\index.md

software\related_project_group\project3\index.md

software\project4\index.md

Edit Re-reading your initial question, I see what you want now. I’ll come back to this with an update.

So this template code:

{{ range where .Pages.ByTitle "Section" "software" }}
  {{ if not (in (string .CurrentSection) "related_project_group") }}
    {{ .File.ContentBaseName }}
  {{ end }}
{{ end }}

Will give you:

    project1
    project4

But as you can see it won’t give you the related_project_group/_index.md page, if you were looking for this.

I do want the related_project_group page itself included, just not its children. I’ll play around with your snippet a bit to see if I can get it to do that. Thanks again for taking time to look at this.

Hi,

So I have two ideas:

The first one builds on the idea that your nested project software/related/project2/index.md has a different value for .Parent ( Page(/software/related/_index.md) ) than software/project1/index.md ( Page(/software) ).

{{ $posts := slice }}
{{ $nested := slice }}

{{ range where .Pages "Section" "software" }}
  {{ if eq (print .Parent) (print ($.Site.GetPage "software")) }}
    <!-- this means that the page is directly below software -->
    <!-- therefore add the page to the $posts list -->
    {{ $posts = $posts | append . }}
  {{ else }} <!-- this means that the page is nested -->
    {{ if not (in $nested (print .Parent)) }}
    <!-- add to $nested list if not there yet (avoid duplicates) -->
      {{ $nested = $nested | append (print .Parent) }}
    <!-- add the .Parent page to the $posts list -->
      {{ $posts = $posts | append .Parent }}
    {{ end }}
  {{ end }}
{{ end }}

{{ range $posts}}
  {{.Title}} <br>
{{ end }}

The second suggestion is a bit simpler: to use the menus feature. Just add menu: software (for example) to the frontmatter of the pages you want included, and then {{ range .Site.Menus.software }}.

2 Likes

Thanks for the code snippet, I’ll take a look at that.

In the mean time, I did end up implementing your second suggestion, I just added all the pages I wanted to group to a menu and put that on the page. That worked great and it’s similar to how I was doing it before the migration of this site, in nanoc.

Are you able to use Section Page Variables and Methods to differentiate the children from the grandchildren of section “software?” Or as @pointyfar metioned, use .Parent.

What does this do?

{{ range ($.Site.GetPage "software").Pages }}
// Don't remember if this returns all descendants or just immediate descendants

I just tried this, and it does not include the related_project_group/_index.md page.

I also tried @pointyfar’s longer snippet above, and that does produce exactly the list I want.

I think I’ll still stick with the menu approach, it seems simple and understandable.

Thanks for all the help!