WordPressからHugoへ:Hugoでブログテーマを作る (3)

前回までで、たとえば hugo サイトの content/blog/sample というフォルダの中に置かれた index.md という記事を使い、 個別ページをレンダリングする方法をみてきました。

ここでちょっとだけ寄り道して、Hugo がコンテンツを整理するときの前提と、それをレンダリングしているテンプレートファイルとの関係を把握しておきましょう。なにせ、このあたりの情報はドキュメントを読むだけではなかなかわかりづらく、間違いをおかしてもデバッグが難しいためです。

この内容を把握した上で、ブログのトップページを作る段階に進みましょう。

ブログ記事のセクションと、テンプレートのルックアップ順

Hugo で、記事は content ディレクトリのしたに Markdown で書きます。このとき、content 直下のフォルダは「セクション」という、記事を整理するための大きな分類になります。


 hugo-site/
    └ content
         ├ about/                   ← content直下にあるのでセクション
         │   └ index.md                http://example.org/about/ でアクセス
         │
         ├ blog/                    ← content直下にあるのでセクション
         │   ├- sample1/
         │   │    ├- index.md       ← index.md があるので、sample1 という名前の記事
         │   │    └- featured.jpg      http://example.org/blog/sample1/ でアクセス
         │   │  
         │   └- sample2.md          ← sample2 という名前の記事
         │                             http://example.org/blog/sample2/ でアクセス
         │  
         └ books/                   ← content直下にあるのでセクション
             ├- sample3/
             │     ├- index.md      ← books というセクションの sample3 という記事
             │     └- featured.jpg     http://example.org/books/sample3/ でアクセス
             │
             └- mystery/            ← 直下に _index.md があるので、これはセクション(!)
                   └- _index.md

たとえば私のブログは blog 「ブログ記事」と books「書評」という2つの大きなセクションで分かれています。

sample1 や sample3 といった記事は、中に index.md がありますのですでに説明した page bundle という機能で記事として認識されます。このとき frontmatter で明示しない限り、ディレクトリの名前がWordPressでいうところのslug、URLのなかの記事名として解釈されます。

あまり使うことはないと思いますが、_index.md という特殊なファイルを作成すると、セクションのページを作る際に「まえがき」のようなコンテンツを生み出すことができます。また、_index.md が存在するファイルは深い場所にあってもセクションになります。

どうしてこういう約束事があるかというと、セクションによって記事の見た目を変えたり処理を分岐させたりすることができるからです。

Hugo のドキュメントのルックアップ順の項目をみてみると、posts という名前のセクションにおける single page 「個別ページ」のテンプレートは以下の順で最初に見つかったものが適用されると書かれています。


  layouts/posts/single.html.html
  layouts/posts/single.html
  layouts/_default/single.html.html
  layouts/_default/single.html

なんだか .html.html という変なファイルがありますが、これを無視すると:


  layouts/posts/single.html
  layouts/_default/single.html

つまり上の例だと、テーマのなかの layouts ディレクトリのなかに blog/single.html や、books/single.html があればそれが適用されますが、見つからなかった場合は次に _default/single.html が適用されるわけです。前回作ったのはこのファイルですね。

たとえば記事の frontmatter の中で “style: nosidebar” といったように、サイドバーがない見た目を指定したい場合があります。このときのルックアップ順は(.html.html のような拡張子のものをあえて消すと):


  layouts/posts/nosidebar.html
  layouts/posts/single.html
  layouts/_default/nosidebar.html
  layouts/_default/single.html

このようになります。記事の frontmatter をみて、もし “style: nosidebar” という項目があったら、layouts/posts/nosidebar.html というテンプレートを探しにいきます。もしセクションが books なら、layouts/books/nosidebar.html というわけですね。

もしその設定がないか、nosidebar.html というファイルがみつからなかったら、次に layouts/posts/single.html というファイルを探します。次に _default/nosidebar.html、_default/single.html という順に探して、最初にみつかったものが適用されます。

ルックアップ順は基本的に「最も個別なものから、一般的なもの」の順に探していると覚えてください。しかし上の例だと、たとえば layouts/posts/single.html が存在する状態で layouts/posts/nosidebar.html のファイル名を間違えて nosidbar.html にしてしまうといったうっかりをしてしまうと、いくらレイアウトを指定しても single.html の内容しか返ってこなくて首をかしげることになります。

ホームページ、セクションページのテンプレート

ここまでは個別ページのテンプレート、デフォルトだと single.html で探し出すテンプレートの話でした。次に、ブログのトップページなどにある、記事が一覧表示されているページのテンプレートについてみてみましょう。

一番ありがちなのは、ブログの URL のトップの部分にアクセスしたら、記事の一覧が表示されている場合です。いわゆるホームページですね。ホームページは以下の順序でルックアップされると決まっています(また .html.html という拡張のものは使わないという想定で消して見やすくしています)。


  layouts/index.html
  layouts/home.html
  layouts/list.html
  layouts/_default/index.html
  layouts/_default/home.html
  layouts/_default/list.html]

layouts ディレクトリの直下に index.html というテンプレートがあれば、まずそれが選ばれます。なければ home.html、それもなければ list.html を探し、それもなかったら _default ディレクトリのなかの index.html を探すという順になっています。

ところで、このブログでは blog というセクションのトップページと books というセクションのトップページがそれぞれ違う見た目で用意されています。これはどうすればいいのでしょうか?

これを実現するには、セクションページのテンプレートを使いますが、そのルックアップは次のように決まっています。


  layouts/posts/posts.html
  layouts/posts/section.html
  layouts/posts/list.html
  layouts/section/posts.html
  layouts/section/section.html
  layouts/section/list.html
  layouts/_default/posts.html
  layouts/_default/section.html
  layouts/_default/list.html

分かりづらいですが、このリストのうち、“posts” という部分だけがセクション名に置き換わります。たとえば books というセクションのページを作るならば、まず layouts/books/books.html というファイルを探します。それがなければ、layouts/books/section.html というファイルを探します。

それらがないと、デフォルトのセクションページ、layouts/section/books.html というファイルを探します。なければ layouts/section/section.html というファイルを探します…という順です。

とても複雑にみえますが、ようは books/books.html というテンプレートがないなら、section/section.html という一般的なセクションページを探して、それもないなら一般的なページを _default ディレクトリに探しにいくという順を追っています。個別から一般へ、ですね。

ファイル整理とパーマリンクは分離できる

ところでこのブログ記事のセクションと置き場所は、あくまでファイル上でコンテンツを整理するためのもので、最終的なデプロイのためのものではありません。

たとえば、ブログのパーマリンクを http://example.org/2020/05/01/sample/ という具合に年月日にしているひとが、記事のディレクトリ構造も年月日にしなければいけないわけでは ない のです。


  [permalinks]
        blog = "/:year/:month/:filename/"

たとえば hugo の config.toml ファイルの下のほうにこのように追加しておくと、記事のディレクトリ上の整理方法がどうなっていたとしても、blog というセクションについては http://example.org/2020/05/sample/ というパーマリンクで記事が表示されます。これはブロガーだとありがたみがわかる、本当に強力な機能です。

実際、blog というセクションに属する記事は content/blog ディレクトリのなかにありさえすれば、どれだけ深い場所にあっても探してくれますので、フォルダ整理は年別だったり、テーマ別にしておいて、公開されているブログ上のパーマリンクはべつのものにできます。

ただし、ファイル整理上は別のディレクトリの記事であっても、パーマリンク上で重複する場合は片方しか表示されないようですので、注意が必要です。詳しくは Hugo のURLマネージメントのドキュメントを御覧ください。

デフォルトのブログを作るためのテンプレート構成

さて、以上のような話を前提として、トップページと個別ページだけが存在し、しかもセクションは blog のみという簡単な場合のファイル構成を考えてみましょう。

それでも将来のことを考えて、すべてを _defaults のテンプレートで済ますのではなく、blog というセクションのテンプレートで定義してみます。


 hugo-site/
     ├ content
     │   ├ blog/              blogというセクション
     │   └- sample1/                   個別記事
     │         ├- index.md
     │         └- featured.jpg
     └ theme/
         ├- index.html                 トップページ
         │
         ├- layout/
         │     ├- blog/
         │     │    ├- blog.html       ブログセクションのトップページ(なくてもいい)
         │     │    └- single.html     個別ページ。mainあり
         │     │
         │     └- _default/
         │            ├- baseof.html   htmlの枠組み
         │            ├- list.html     デフォルトで作成される(空ファイル)
         │            └- single.html   デフォルトで作成される(空ファイル)
         └- static/                    css, js, 固定の画像など

もし将来、ブログとは違う youtube というセクションが増えて、その見た目もブログとは違うものにしたい場合は、たとえば layout/youtube というディレクトリを作り、そこに single.html を作ればいいわけです。

逆にセクションが増えても見た目が同じでいいならば、blog/single.html ではなく、最初から _default/single.html で全てに共通する個別ページを作るというのでもいいわけです。

今回は必要以上に複雑な話を書きましたが、どうしてこの横道に入ったかと言うと、これからとても簡単なテンプレート構成を作るにあたって、ほんの少し、single.html というファイル名を別のものにしただけでテンプレートが無視されたり、まったくの白紙のページがでるといったトラブルが必ず起こるからです。

意図に反して変更が反映されない、まったく表示がされないといった場合には、このルックアップ順を疑って、根気強くデバッグをしてください。

おそらく一度は、「これはhugoそのものがバグっているのではないか?」と思う瞬間があると思いますが、あまりに柔軟性が高いためにルックアップ順で想定外なことが起こっていることがほとんどですので。

さて、こうした前置きを経て、ようやくブログのトップページを作れます。

Author Image

2011年アルファブロガー・アワード受賞。ScanSnapアンバサダー。ブログLifehacking.jp管理人。著書に「ライフハック大全」「知的生活の設計」「リストの魔法」(KADOKAWA)など多数。理学博士。