Nested Sections with a Content-Type: Template and Fetching sub pages

Hello there,

I am enjoying using Hugo. It’s pretty solid and I love the freedom we get to organise the content. I am pretty new to it and despite having read the documentation, I might have misunderstood some concepts.

Here is a sample of the data structure of my website:

├── games
│   ├── alone-in-the-dark
│   │   ├──
│   │   ├── images
│   │   │   └── main.jpg
│   │   ├── ratings
│   │   │   └──
│   │   └── reviews
│   │       └──
│   ├── autobahn-tokio
│   │   ├──
│   │   ├── images
│   │   │   └── main.jpg
│   │   └── reviews
│   │       └──
│   ├── flashback
│   │   ├──
│   │   ├── images
│   │   │   └── main.jpg
│   │   └── reviews
│   │       └──
│   ├── samurai-shodown
│   │   ├──
│   │   ├── images
│   │   │   └── main.png
│   │   └── reviews
│   │       └──
│   └── space-pirates
│       ├──
│       ├── images
│       │   └── main.png
│       ├── ratings
│       │   └──
│       └── reviews
│           └──
└── images
    ├── boitier-du-jeu-alone-in-the-dark-2.jpg
    ├── comparatif-de-boitier-3do-et-playstation.jpg
    ├── coupon-de-precommande-pour-gex.jpg

We have videogame systems. Each System contains Games and Images. Each Game contains Ratings, Reviews and Images.

Each Game, Rating and Review entry has a type, respectively type: game, type: rating and type: review.

What I managed to do:

  • display a System thanks to Section Template
  • fetch Games from a System page
    {{ $Games := (index (where .Sections "Title" "Games") 0).Sections }}
  • fetch Ratings and Reviews from a Game page
    {{ $RatingsAndReview := union (where .Pages "Type" "review") (where .Pages "Type" "rating") }}

What I’m missing:

  • I can’t get to give the Game section its own template. Their section is always systems. In spite of having a type, the top section template is always in use. (I’ve tried layouts/games/list.html, ``layouts/system/games/list.htmlandlayouts/game/single.html`)
  • When I rename a game from to, I get a Type template (layouts/game/single.html) but then .Data.Pages is empty. .Sections as well. I did not find a way to populate $RatingsAndReview.

I am not sure if I have architectured the content well or if I am missing something with the behaviour of the Nested Sections. Let me know if you have pointers. I an happy to try out and investigate further.

Thanks for your help :slight_smile:

I kept digging a bit and found a few interesting things.

Adding empty seems to be the way to go to make sections explicit. I added one in the folder games and was able to fetch games easily this way. I don’t know if that’s what I was supposed to do.

While using {{ printf "%#v" . }} to debug templates, I noticed the unexported key targetPathDescriptor contains a Sections dict. It is an ordered list of all the sections leading to the .CurrentSection (Sections:[]string{"systems", "3do", "games", "alone-in-the-dark"} when I am viewing a game for example).

And .CurrentSection (courtesy of! It’s great and I wonder if that should be part of the lookup algorithm for templating as well:


Instead of the current lookup order:


Reading Different templates for nested sections?, it seems there is no way to assign a specific layout for a nested section, wether layout and/or type are set in front-matter.

Using content/systems/3do/games/alone-in-the-dark/ with type: game enables me to use layouts/game/single.html as a template. I’m unsure if it is the right way to go though as it makes fetching sub pages more complicated.

I suspect a Single Page is considered to be a leaf in a content tree. Is that why I can’t list the reviews and ratings in this tree? (it is alright if is named

├── images
│   └── main.jpg
├── ratings
│   └──
└── reviews

Not sure what the question was here, but as to nested sections and your tree:

  1. You need “” in both ratings and reviews (i.e. the bottom sections) to get a fully navigational tree.
  2. You currently cannot assign a specific layout to, say, the ratings section.

Thanks @bep :slight_smile: I documented my thinking along the way, hence the confusion.

I think I have been wondering wether to declare stuff as pages to benefit from custom layout (upside: custom layout, downside: struggle to get children contents) or to declare content as sections (upside: content navigation is :+1:, downside: no custom layout).

It seems a Type attribute cannot be assigned to a section. Neither a Layout.

I’ll probably end up using nested sections. I will determine which partial/template to use to render based on a content Type.

But note that there are open issues about this and it will eventually improve, but I had to stop somewhere on my first nested sections trip …

No problem :slight_smile: Once I have managed to migrate my content to Hugo, I’m happy to share the code and content hierarchy. Especially if it can fuel your thinking in how to handle nested sections.

I finalised the migration of my website:
It is now entirely built with Hugo.

I preprocess a few things to compute average values and ratings breakdowns. I store that in the data directory in yaml files, the keys matching the .Dir value of the sections they belong to.

Hugo spends most of its time on the _default/section.html. This is where is decided which template will be used depending on the section/content type:

{{- $Type := .Type | default "" -}}
{{- $Dir := index (split (.Dir | default "") "/") 1 | default "" -}}
{{- if (eq $Type "system") -}}
{{ template "systems/section.html" . }}
{{- else if (eq $Type "game") -}}
{{ template "systems/game.html" . }}
{{- else if (eq $Dir "games") -}}
{{ template "systems/games.html" . }}
{{- else if (eq $Dir "images") -}}
{{ template "systems/images.html" . }}
{{- else -}}
{{ template "_default/single.html" . }}
{{ end }}

Can be found here:

Template Metrics:

Built site for language fr:
0 of 1 draft rendered
0 future content
0 expired content
15920 regular pages created
4087 other pages created
5699 non-page files copied
0 paginator pages created
total in 11336 ms

Template Metrics:

     cumulative       average       maximum
       duration      duration      duration  count  template
     ----------      --------      --------  -----  --------
   6.991336544s    1.711465ms   59.232057ms   4085  _default/section.html
   5.426283295s     271.219µs    78.56242ms  20007  partials/header.html
   3.954926227s    1.004553ms   41.216736ms   3937  review/single.html
   3.701049329s     308.858µs   82.584664ms  11983  _default/single.html
   1.879872947s     478.095µs    8.597059ms   3932  partials/games/ratings-breakdown.html
   1.244552956s      44.789µs    7.073497ms  27787  partials/games/rating-star.html
   1.182791667s     300.811µs    8.668732ms   3932  partials/games/megamenu.html
   589.810851ms      25.096µs    4.561045ms  23502  partials/games/rating.html
   551.063031ms     138.007µs    5.209349ms   3993  partials/breadcrumb.html
   368.084248ms  368.084248ms  368.084248ms      1  _internal/_default/sitemap.xml
   120.302718ms      30.556µs     883.708µs   3937  partials/back-to.html
    53.150553ms       6.702µs    2.223975ms   7930  partials/icon.html
    12.010339ms   12.010339ms   12.010339ms      1  index.html
     7.915659ms     127.671µs    1.291515ms     62  partials/systems/megamenu.html
      1.39518ms     1.39518ms     1.39518ms      1  _internal/_default/rss.xml
      328.874µs     328.874µs     328.874µs      1  404.html
       263.76µs      263.76µs      263.76µs      1  partials/home/news-section.html
       65.899µs      65.899µs      65.899µs      1  partials/footer.html
       43.482µs      43.482µs      43.482µs      1  partials/logo.svg