Just Plain Notes

個人的に気になったことのメモなど

Hugoブログを自分でカスタマイズするためのメモ

11168文字 |
Hugo

このブログは Hugo という Go 製の静的サイト生成ツールを使って構築してるんですが、自分のブログを作るなら当然デザインも自分好みにカスタマイズしたくなるよね、と言うことで Hugo の基本的な構造について調べた内容をメモとして残しておきます。最初はちょっと複雑に見えるかもしれませんが、慣れてしまえば結構シンプルです。

なお、この記事執筆時点では Hugo v0.148.0 を使用しています。

Hugo の基本的なディレクトリ構造

Hugo ではすべての記事(md ファイル)は content/ ディレクトリに格納する。このディレクトリがサイトのすべてのコンテンツの起点となる。最も基本的な構成は下記のようになる。

<プロジェクトルート>
├── content/ # 全ての記事
├── themes/<テーマ名>/layouts # テーマが提供するテンプレート
├── layouts/ # テーマを上書きするためのカスタムテンプレート
├── public/ # ビルド結果のサイト

生成されたサイトではcontent/ 配下のディレクトリ構造が、そのままサイトの URL 構造になる。例えば content/posts/article.md/posts/article/ という URL でアクセスできる。

Hugo でページ生成の対象になるのは、個別の記事(.md ファイル)またはディレクトリである。つまり、.md ファイルを配置するか、ディレクトリを対象にする場合は_index.md を置くことで、対応する URL のページが生成される。

テーマについて

生成対象になった記事やディレクトリをページに変換する際には、テンプレートが使われる。テンプレートは基本的にはテーマによって提供される。テーマが提供するデザインや機能に不満がない場合、何もする必要はない。しかし、特定のページのみデザインを差し替えたい、または新しい機能を追加したい場合はテンプレートをカスタマイズする必要がある。

テーマ内のテンプレートを直接編集することは可能だが、カスタムテンプレートを作成して差分のみを実装する方が良い。カスタムテンプレートを使うにはプロジェクトルート直下にlayoutsディレクトリを作成し、テンプレートを配置するだけでいい。これでテーマ内のテンプレートをピンポイントで上書きできる。

この差分実装方式を採用することでテーマ本体の更新に追従することが簡単になる(追従する気がないなら直接テーマを更新してもかまわない)。

テンプレート選択のルール

Hugo はページの種類に応じて自動的にテンプレートを選択する。当初この記事でテンプレート選択のルールを完璧に解説してやろう意気込んでいたが、思ったより書くのが難しく、さっさと諦めることにした。ここでは基本的なルールについてのみ解説する。詳細が知りたい場合は公式ドキュメントを参照してほしい。このブログのようなシンプルなサイトを構築する場合、ここに書いた知識だけで十分対応できるだろう。

テンプレートは基本的に、テンプレート種類別にファイル名が仕様で決められており、任意の名前をつけることはできない(厳密に言うとcontent直下のディレクトリは「セクション」と呼ばれセクションのテンプレートに関してはセクション名と同じファイル名のテンプレートを持てるがここでは扱わない。知らなくてもブログの構築に特に支障はない。多分)。

本ブログでは以下のテンプレートを使用している。

  • index.html : サイトのトップページ
  • list.html : 記事一覧ページ
  • single.html : 個別記事ページ
  • terms.html : タクソノミー一覧ページ
  • baseof.html : 共通テンプレート

※タクソノミーについては重要な機能であるため後述する

例えば記事一覧ページを生成する場合、list.html が使われるが、

  • カスタムテンプレートからlist.htmlを探し見つかった場合はそのテンプレートを使う
  • 見つからない場合、テーマ内のテンプレートからlist.htmlを探し見つかった場合はそのテンプレートを使う

という二段階のステップでテンプレートの検索を行う。それぞれのステップでルールに従った検索が行われるが、このページではセクションに関する説明は省略することにしたので、以下のルールで検索が行われると考えておけば良い。

  • list.htmlを探す
  • _default/list.htmlを探す

なおlist.htmlを使って一覧ページを生成させたい場合、ディレクトリに_index.mdを配置する必要がある(これはすでに述べた)が、セクションディレクトリの場合は_index.mdを置かなくても自動でlist.htmlを使用した一覧ページが生成される。

タクソノミーによる記事の分類

Hugo にはタクソノミー(Taxonomy)という記事を分類・整理するための仕組みがある(ブログで一般的なタグやカテゴリを使った記事の分類などを簡単に実現する仕組み)。タクソノミーを使うには、まずは設定ファイル(hugo.toml)で、どんな分類を使うかを定義する必要がある。

[taxonomies]
tag = 'tags'
category = 'categories'

= の左側に frontmatter で使うキー名を、右側に URL のパスになる値を指定する。記事の frontmatter では、こんな感じで分類を指定する:

---
tags: ["hugo", "blog"]
categories: ["tech"]
---

すると、Hugo が自動的に以下のようなページを生成する:

  • /tags/ - 全タグの一覧(terms.html を使用)
  • /tags/hugo/ - “hugo” タグが付いた記事一覧(list.html を使用)
  • /tags/blog/ - “blog” タグが付いた記事一覧(list.html を使用)
  • /categories/ - 全カテゴリの一覧(terms.html を使用)
  • /categories/tech/ - “tech” カテゴリの記事一覧(list.html を使用)

興味深いのは、タグ一覧専用のlist.html、カテゴリ一覧専用のlist.htmlを個別に作成せずとも、汎用のlist.htmlのみで、それぞれの一覧ページを生成することが可能な点である。とはいえ、特定の一覧ページに独立したデザインを適用したい場合もある。例えばタグ一覧ページのみ専用デザインで作りたい場合は、下記のパスにテンプレートを作成すれば良い。

  • layouts/tags/list.html

これでタグ一覧ページのみを独自デザインとして生成できる。

ちなみに汎用のlist.htmlでどのように個別の一覧ページを生成しているのか、について簡単に説明しておくと、Hugo がテンプレート変数.Pagesに対し、あらかじめ特定のタグやカテゴリを持つ記事一覧を設定した状態でビルド処理を開始することで実現している。

baseof テンプレートによる共通レイアウト

全てのページで共通して呼び出されるのが layouts/_default/baseof.html というテンプレートです。これは React でいう Layout コンポーネントみたいなもので、ヘッダーやフッターなど、サイト全体の共通レイアウトを一箇所で定義できる。

baseof.html の中を見ると、このような記述がある:

<main>{{ block "main" . }}{{ end }}</main>

この {{ block "main" . }}{{ end }} が、各ページ固有のコンテンツを挿入するためのスロットでスロット名として main を使うと宣言している。そして、例えば TOP ページのテンプレート index.html を見ると:

{{ define "main" }}
...TOPページの内容...
{{ end }}

こんな風に TOP ページのコンテンツにmain という名前をつけている。これが baseof.html のスロットに TOP ページのコンテンツが挿入される仕組みとなる。

partial で部品を再利用

テンプレートには、もう一つ便利な機能がある。partial という共通で使い回したいテンプレートを切り出すための仕組みである。

{{ partial "head.html" . }}

こんな感じで、ヘッダーやフッターなどの共通部品を複数の箇所で使い回すことができる。コードの重複もなくなって、メンテナンス性も向上する。補足だがこれまで紹介したコードに出てきた . はページのコンテキストをテンプレートに渡すための記法。これがあることで、テンプレート内でページのタイトルや作成日、frontmatter の情報などにアクセスできるようになる。

ショートコード(Shortcode)

Hugo にはショートコードという便利な機能がある。これはマークダウン記法だけでは表現しにくい複雑なコンテンツを簡単に埋め込むための便利な仕組みである。テンプレートがデザイナーが使うための部品であるのに対し、ショートコードは記事執筆者が使うための共通部品である。

例えば、YouTube 動画を埋め込みたい場合:

{{< youtube "動画ID" >}}

図表を挿入したい場合:

{{< figure src="image.jpg" title="図のタイトル" >}}

ショートコードは layouts/shortcodes/ ディレクトリにテンプレートファイルを配置することで、独自のものを作成することもできる。例えば layouts/shortcodes/note.html を作れば:

{{< note >}}
ここに注意書きの内容
{{< /note >}}

こんな感じで使えるようになる(Hugo には YouTube、X、Instagram などの組み込みショートコードも用意されている)。

おわりに

Hugo の基本的な構造とテンプレートについて、実際にブログを構築する上で必要な知識をまとめてみました。テンプレートの記法については詳しく触れませんでしたが、それらは実際にカスタマイズしたい箇所が出てきた時に調べれば十分だと思います。まずはテーマのテンプレートをコピーして色々変更してみるところから始めるのが良いです。

ちなみにですが、Hugo のテンプレートは Hugo 専用の構文ではなく、Go 言語標準のテンプレート構文が使われています。とはいえ、テンプレートを作成するのに Go 言語の知識が必要なわけではないので安心してください。テンプレート構文自体はシンプルで、HTML と少しの変数記法さえ覚えれば十分カスタマイズできます。