Rendering filtered Page lists

With https://s.natalian.org/2020-12-08/branch-bundle.zip

As you can see under /tips or public/tips/index.html I have

  • Bar tips
  • Foo tips

And what I want instead is:

  • Bar tips
    • Test 2
  • Foo tips
    • Test 1

How do I achieve that please?

Some background to how I got here: Minimal site with section listings

Hello again @hendry

This is kind of a pretty basic Page filtering question.

There are a couple of challenges in the sense that you want to list all pages both Regular and Nested Section lists below a given Section. Basically you want to hide the .FirstSection i.e. /tips/ from the rendered list.

The way I would go about it, would be to use Hugo’s Build Options to disable the listing of the .FirstSection page /tips/.

So in /content/tips/_index.md I would add the following:

_build:
  list: never

Then in the template under /layouts/_default/list.html I would change the range function to:
range where .Site.Pages "Type" "in" "tips" to get all pages under /tips/.

Note that in Hugo Type is an alias of Section.
Content files under the /tips/ Section also have the Type of tips.

However on the Nested Sections Lists you probably need to render only the .RegularPages residing under the given Nested Section.

To achieve this, I would assign the following layout parameter to the _index.md files of the Nested Sections foo and bar: layout: subsection.

Then under /layouts/_default/ i would create a new template called subsection.html that would be identical to the one in /layouts/_default/list.html except for the following range function: range .RegularPages

If you prefer not to have a separate template for subsection then in layouts/_default/list.html you can achieve the same by using the following condition:

{{ if eq .Layout "subsection"}}
{{ range .RegularPages }}
<--- HTML --->
{{ end }}
{{ else }}
{{ range where site.Pages "Type" "in" "tips" }}
<--- HTML --->
{{ end }}
{{ end }}

Personally I prefer to work with as few templates as possible in my projects.

Also whichever approach you choose I would recommend that you create a Partial template for your intended HTML output within the above Page lists, so that you can have it in one place and to maintain it easily.

Do read about .Pages compared to .Site.Pages.

Also in the above construct .Site can be replaced with the site function to access any pages from the global scope within a Hugo project i.e. site.Pages

Also do read about the where function. There are plenty of examples on that page, that should give you enough info about filtering Page lists according to your needs.

2 Likes

This boggles my mind. Now I’m trying to get a simpler page.

I dropped a section:

content/
├── bar
│   ├── _index.md
│   └── test2.md
├── foo
│   ├── _index.md
│   └── test1.md
└── _index.md

I feel like quite the idiot as the simplest way I could out how to render how I wanted to was:

(ins)[hendry@t14s basic]$ cat layouts/_default/list.html
{{ define "main" }}

{{ .Content }}

<h1>foo</h1>

<ul>
{{ range where .Site.RegularPages "Section" "foo" }}
<li><a href="{{.RelPermalink}}">{{ .Title }}</a></li>
{{ end }}
</ul>

<h1>bar</h1>

<ul>
{{ range where .Site.RegularPages "Section" "bar" }}
<li><a href="{{.RelPermalink}}">{{ .Title }}</a></li>
{{ end }}
</ul>

{{ end }}

please tell me there is a simpler way to write this. I.e. dynmaically get the <h1> stuff from the section names etc

There is. You need to filter out Pages that you do not want rendered in your list.
In your case these are Taxonomies and the Homepage.

So you need to use a filtered condition like so:

{{ $pages := where site.Pages "Kind" "not in" (slice "taxonomy" "home") }}
{{ range $pages }}
<-- Page list -->
{{ end }}

Also the above offers the base to add more filtering in the future.

Have a look at the intersect function:

I still don’t get it. How do you echo out the h1? and pages below?

What do you mean by echoing out?
It is up to you to render whatever you wish in a Page list.

Also if you want to get the Section title separately from the RegularPages list then you can use GetPage for example:

{{ with .Site.GetPage "/bar" }}<h1>{{ .Title }}</h1>{{ end }}

I got something I wanted:

image

{{ define "main" }}
{{ .Content }}
{{ $pages := where site.Pages "Kind" "not in" (slice "taxonomy" "home") }}
{{ $parent := .Page }}
{{ range $pages }}
{{ if eq .Parent $parent }}
<h1>{{- .Title -}}</h1>
<p>{{ .Description | markdownify }}</p>
{{ else }}
<p><a href="{{ .RelPermalink }}">{{- .Title -}}</a></p>
{{ end }}
{{ end }}
{{ end }}

I find {{ $pages := where site.Pages "Kind" "not in" (slice "taxonomy" "home") }} bizarre. Surely there is a saner way of writing that?

Since you removed the tips section the above is as far as I know the simplest way to render all Sections and their children.

Note that if you add any other Page like an About or Contact Page it will show up with the above construct.

You will need to specify another filter on top of the present one.

Couldn’t I start $pages by a path? Like /tips?

I’m confused why Yikes isn’t a header as it’s a parent now.

$ cat content/tips/foo/another/_index.md
---
Title: Yikes
---

https://s.natalian.org/2020-12-14/yikes.zip

Is there a way to list the pages in some sort of debug mode?

You can try the debug-drawer-demo theme component by @pointyfar

No it is not. It is the .Title of a second level Nested Section under /tips/foo/another/.

Please have a look at the role of an _index.md -this file does not override the folder tree to generate a new .Section, its purpose is for adding custom frontmatter and content on a list page-.

Also have a look at Nested Sections

I copied across https://github.com/kaihendry/dabase.com/tree/master/content/tips to debug drawer and it just listed all the .Pages, including the children. I don’t understand since https://github.com/kaihendry/dabase.com/blob/master/layouts/_default/list.html only renders the sections: https://dabase.com/tips/

What am I missing?

I solved the original question using:

{{range .Sections}}
<ul>
    <li>{{.Title }}
        <ul>
            {{ range .Pages }}
            <li>
                <a href="{{.RelPermalink}}">
                    {{ $alternate_title := replace .File.BaseFileName "_" " " | title }}
                    {{ .Title | default $alternate_title }}
                </a>
            </li>
            {{ end }}
        </ul>
    </li>
</ul>
{{ end }}

The .Sections page variable contains the children of the current page that are sections. Within tips, those are sections bar and foo.

Maybe that’s what you were looking for?

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.