メニュー

はじめに

Hugoは、HTML上に階層型のメニューを作成するために必要なデータ構造を持っています。ここでは、メニューの設定方法と利用方法を記載します。

設定

設定項目

Hugoのメニューでは、フロントマターもしくは設定ファイルに、以下のような項目を設定します。名称は、フロントマターもしくは設定ファイルで設定する名称、フィールド名は、テンプレートで利用する際のフィールド名です。

名称 フィールド名 説明
url .URL ページのURL。
name .Name メニューに表示するページの名前。
identifier .Identifier メニュー項目を識別するためのID。メニュー内で一意である必要がある。
pre .Pre メニュー内で利用するコード。HTMLのコードを書くことが多い。
post .Post メニュー内で利用するコード。HTMLのコードを書くことが多い。
weight .Weight メニュー内でのウエイト(重み)。ソートに利用する。
parent .Parent 親となる項目のID。メニューに親子関係があるときに、子が親のIDを指定する。
- .Children 子メニューのエントリ。parentを設定すると自動設定される。
params .Params ユーザ定義の項目を定義できる。

一つのページを、複数のメニューに登録することもできます。

フロントマターでの設定

このページのフロントマターに実際に設定している値は、以下の通りです。

1
2
3
4
5
[menu.hugocontents]
  identifier = "menu"
  name = "メニュー"
  parent = "contents"
  weight = 500

hugocontentsというのが、メニュー名です。この設定を行うことで、.Site.Menus.hugocontentsという変数に、メニューが設定されます。

urlは設定していません。この場合、このページのURLが設定されます。設定する場合は、コンテキストルート(baseURL)からの相対パスを記述する必要があるようです。

また、ユーザ定義の項目を定義する場合は、以下のように設定します。この例では、classという変数に、“highlight"を設定しています。

1
2
[menu.hugocontents.params]
  class = "highlight"

設定ファイルでの設定

メニューは、基本的には、フロントマターで設定しますが、設定ファイル(config.tomlなど)に設定することもできます。

設定ファイルで、sectionPagesMenuという項目を設定すると、設定した名前のメニューに、セクションの情報が設定されます。例えば、以下のように設定すると、mainにセクションのメニューが定義されます。

1
sectionPagesMenu = "main"

利用

データ

設定したメニューは、.Site.Menus.<メニュー名>という変数に格納されています。テンプレート内で、この変数を利用して、HTMLファイルに展開します。

関数

メニューに利用できる関数として、以下が用意されています。

関数名 説明
.HasChildren .Children があると true。
.KeyName .Identifierもしくは .Nameを返す。
.IsEqual 2つのメニューが同じとき true。
.IsSameResource 2つのメニューが同じ.URLを持つとき true。
.Title メニューのtitleキーもしくは、.LinkTitleを返す。
.IsMenuCurrent MENU内のMENUENTRYがPAGEと同じ場合true。(Pageオブジェクトの関数)
.HasMenuCurrent MENU内のMENUENTRYのPAGEが子メニューに含まれる場合true。(Pageオブジェクトの関数)

上記の情報を使って、.Site.Menus.main をHTMLに展開するための、テンプレートの例です。.Site.Menusは、情報を持っているだけなので、それをHTMLに展開するのはユーザの仕事です。さらに、見栄えを変えるために、CSSも記述する必要があります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!-- sidebar start -->
<aside>
    <ul>
        {{ $currentPage := . }}
        {{ range .Site.Menus.main }}
            {{ if .HasChildren }}
                <li class="{{ if $currentPage.HasMenuCurrent "main" . }}active{{ end }}">
                    <a href="#">
                        {{ .Pre }}
                        <span>{{ .Name }}</span>
                    </a>
                </li>
                <ul class="sub-menu">
                    {{ range .Children }}
                        <li class="{{ if $currentPage.IsMenuCurrent "main" . }}active{{ end }}">
                            <a href="{{ .URL }}">{{ .Name }}</a>
                        </li>
                    {{ end }}
                </ul>
            {{ else }}
                <li>
                    <a href="{{ .URL }}">
                        {{ .Pre }}
                        <span>{{ .Name }}</span>
                    </a>
                </li>
            {{ end }}
        {{ end }}
        <li>
            <a href="#" target="_blank">Hardcoded Link 1</a>
        </li>
        <li>
            <a href="#" target="_blank">Hardcoded Link 2</a>
        </li>
    </ul>
</aside>

コンテンツごとにメニューを変える

i
この部分は、私の知識不足の可能性があり、無駄なコーディングをしている可能性があります。もっとエレガントな方法があれば、教えてください。

まず、フロントマターで、コンテンツ内で、そのコンテンツで利用するメニューの名前を定義します。

1
menuname = "hugocontents"

テンプレートでは、上記のmenunameを利用して、メニューを作成します。

例えば、以下のようなテンプレートを作成することで、フロントマターで定義したメニュー名に対応するメニューを展開することができます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{{ $currentPage := . }}
{{ $menuname := string .Params.menuname }}
{{ $menu := index .Site.Menus $menuname }}
<div class="menu">
  {{ range $menu }}
  <div class="menu-level1">
    {{ .Pre }}
    <div class="menu-item {{ if ($currentPage.IsMenuCurrent $menuname .) -}}active{{- end -}}">
      <a class="menu-link" href="{{- .URL -}}">{{ .Name }}</a>
    </div>
    {{ .Post }}
  </div>
  {{ end }}
</div>

最終更新日

November 5, 2023

inserted by FC2 system