Nested menus - partial rendering

Suppose that I have a nested menu structure:

  • Colours
    • Red
      • Red
      • Scarlet
      • Maroon
    • Blue
      • Blue
      • Navy
      • Ultramarine
  • People
    • A
      • Alice
      • Alison
    • B
      • Bob
      • Bill

On each page, I would like to render a partial view of the menu.

  • Parts of the menu not on the current path, should be excluded from the output.
    • Note: not “included, then hidden with Javascript”. I mean never included in the output HTML at all. Reason: The full menu contains thousands of items.
  • The parent(s) of the current page, should be highlighted. (i.e. bold.)

Example: on the page for “Maroon”, the menu should render as:

  • Colours
    • Red
      • Red
      • Scarlet
      • Maroon
    • Blue
  • People

How can I accomplish this?

The documentation for menus mentions some functions IsMenuCurrent and HasMenuCurrent, which were implemented (#367) but not documented (#1393). I’m willing to submit a PR documenting these, if someone can help me understand how they work.

The thread Confusion regarding proper use of menus also refers.

Edit: See also.

I think I have this mostly licked.

Remaining problems:

  • If the current item is a Node (i.e. /categories/colours/) then IsMenuCurrent() and HasMenuCurrent() don’t work.

/layouts/partials/menu_top.html

<nav>
  {{ partial "menu_recursive.html" (dict "menu" .Site.Menus.main "page" . ) }}
</nav>

/layouts/partials/menu_recursive.html

{{ $page := .page }}
<ul>
{{ range .menu.ByName }}
  {{ $iz := $page.IsMenuCurrent "main" . }}
  {{ $haz := $page.HasMenuCurrent "main" . }}
  {{ if .HasChildren }} 
    <li>
      <a href="{{ .URL | relURL }}" class="{{ if or $iz $haz }}hot{{end}}"> {{ .Pre }} {{ .Name }}</a>
      {{ if or $iz $haz }}
        {{ partial "menu_recursive.html" (dict "menu" .Children "page" $page) }}
      {{ end }}
    </li>
  {{ else }}
    <li class="{{ if $haz }}hot{{end}}">
      <a href="{{ .URL | relURL }}" class="{{ if $iz }}hot{{end}}">{{ .Name }}</a>
    </li>
  {{ end }}
{{ end }}
</ul>

Live example

Working well:

Not so good: