Create custom menu order from source file

I am trying to create a custom menu order based off a source file. Having browsed much of the Hugo forums on custom menu’s, I’ve seen many people saying it just isn’t possible. For context on the why of this, I have several big projects I am migrating documentation to Hugo, and each of those projects has between 5-30 sections with 10-50 individual pages in each section.

I understand using weight in the front-matter of each content file is an option, like so:

---
title: "Sample Title"
draft: false
weight: 10
---

However, I’m trying to avoid this due to time constraints and I’m looking for a more programmatic way to accomplish this.

This question here showed promise, with potentially creating a source file in the /data/ directory and reading that into the menu partial:

I’ve also seen the menu configuration you can do in the config.toml, like so:

[menu]
          [[menu.sites]]
              identifier = "firstsection"
              name = "First Section"
              url = "/firstsection/"
              weight = 10

          [[menu.sites]]
            identifier = "secondsection"
                name = "Second Section"
                url = "/secondsection/"
                weight = 20

And then in the menu.html partial something like this:

{{ range .Site.Menus.sites }}
  <li>
    <a href="{{ .URL }}">{{ .Name }}</a>
  </li>
{{ end }}

However, this could make the config.toml somewhat unwieldy.

If I have to, I can use one of the previously mentioned solutions, but wanted to see if anyone smarter than I am has come across this problem and has a good solution.

Thank you!

You can split the menu definitions into a separate file. See:
https://gohugo.io/getting-started/configuration/#configuration-directory

config/
└── _default/
    ├── config.toml
    └── menus.toml

Then menus.toml will look something like:

[[sites]]     --> Notice that this is `sites` not `menu.sites`
name = 'Home'
pageRef = '/'
weight = 10

[[sites]]
name = 'Test'
pageRef = '/post/test'
weight = 20
Or if you prefer YAML...
sites:
  - name: Home
    pageRef: /
    weight: 10
  - name: Test
    pageRef: /post/test
    weight: 20

Or if you prefer JSON...
{
  "sites": [
    {
      "name": "Home",
      "pageRef": "/",
      "weight": 10
    },
    {
      "name": "Test",
      "pageRef": "/post/test",
      "weight": 20
    }
  ]
}

When defining the menu in site config:

  1. You do not need to specify identifier for each entry unless there are duplicate name values.
  2. Use url for external links, but use pageRef for internal links. If you use url for internal links you will run into this issue: https://github.com/gohugoio/hugo/issues/9150
1 Like