WordPressからHugoへ:Hugoでブログテーマを作る (2)
今回はhugoのテンプレートの基礎であるpartialとmainのブロックについて、そして個別記事の作り方について見ていきます。
基本的なブログを表示するのに必要なページは、トップページと、記事の個別ページだけといっていいでしょう。トップページの見せ方を少し変えて、ブログの一覧のページとは別にしたいという場合もあると思いますが、そうしたことも Hugo では簡単にできます。
baseof.html で大枠をつくる
まず最初に、ブログ上のすべての html ファイルで共通する大枠の部分を _default/baseof.html に記述します。私の使った HTML テンプレートの場合、最後の部分で Javascript ライブラリを呼んでいましたので、このような感じになっています。
<!DOCTYPE html>
<html lang="ja">
{{- partial "head.html" . -}}
<body>
{{- partial "header.html" . -}}
<div id="content">
{{- block "main" . }}{{- end }}
</div>
{{- partial "footer.html" . -}}
<!-- all js here -->
<script src="/js/vendor/jquery-1.12.0.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
<script type="text/javascript">
// grab an element
var myElement = document.querySelector(".intelligent-header");
// construct an instance of Headroom, passing the element
var headroom = new Headroom(myElement);
// initialise
headroom.init();
</script>
<script src="/js/main.js"></script>
</body>
</html>
Hugo のテンプレートとしては、2種類存在することに注目してください。一つは Partial です。
{{ partial "header.html" . }}
この一行で、partial ディレクトリに存在する header.html の内容がここに流れ込まれます。ファイル名のあとに存在する「.」は自分自身への参照といって、現在レンダリングしているページの情報、例えばタイトルや、パーマリンクなどといったものが渡されます。
たとえば head.html の内容は以下のようになっているかもしれません。
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>{{ .Title }}</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" type="image/x-icon" href="/images/favicon.png">
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/font-awesome.min.css">
<link rel="stylesheet" href="/style.css">
<link rel="stylesheet" href="/custom.css">
<script src="/js/vendor/modernizr-2.8.3.min.js"></script>
</head>
メタ情報や CSS を読み込んでいるのがわかると思いますが、途中に <title>
タグの中身に {{ .Title }} と書かれている部分が渡された参照に基づいてタイトルを入れています。たとえばブログの個別記事をレンダリングしているときには、その記事の題名がここに入るわけです。
さきほどの「.」を忘れてしまうと、この {{ .Title }} は空欄になってしまいますので、 partial を呼び出した先で現在レンダリングしているページの情報を利用するならば、呼び出す際に忘れずに「.」をつけるようにしてください。
もう一つのテンプレートとして、block というものがあります。
{{ block "main" . }}{{ end }}
これは個別記事ならば記事本文、ブログのトップページならば記事が列挙されている部分といったように、それぞれのテンプレートで main と定義されている部分が流し込まれる場所です。ここでも「.」を使って参照を渡しているのに注意してください。これがないと、記事はいつまでたっても空欄のままということになりかねません。
{{ end }} というのは、main という領域の範囲を閉じている命令ですが、もっとわかりやすい例が別の場所にありますので、この行はこういうものと思ってください。
partial で再利用可能なパーツを呼び出してくる
partial は基本的にその内容を流し込むだけですが、渡された情報によって処理を分岐させることも可能です。たとえば OGP 情報を設定する場合、トップページでは website、個別ページでは article に設定しますが、それは if 構文を使って以下のように書けます。
{{ if .IsHome }}
<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# website: http://ogp.me/ns/website#">
{{ else }}
<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# article: http://ogp.me/ns/article#">
{{ end }}
.IsHome は Hugo の変数で、参照がサイトのホームのときだけ「真」の値になります。なので、ホームのときには前半が、そうでないときには後半の行が流し込まれます。{{ else }} と {{ end }} は、それぞれが「もしくは」と「ここまで」の、プログラミングの構文を表現しています。
こうした方法を応用して、「タグが3つ以上あるときだけ表示」「デプロイしてるサーバー上のときだけ Google Analytics コードを挿入」といったことでも、なんでも可能です。
個別記事を作ってみる
次に、main が定義されているテンプレートについて見ていきます。個別ページは
layouts/
├ _default/
│ ├ baseof.html 共通する html の枠組み(htmlタグなど)
│ └ single.html 個別記事のテンプレート
│
├ partials/
├ head.html headタグの中身
├ header.html ブログのロゴなどのヘッダの共通部分
└ footer.html ブログのフッターなどの共通部分
この構造だと _default/single.html に作るのがもっともわかりやすいでしょう。ここに、以下の内容でファイルを作ってみます。
{{ define "main" }}
<section class="main">
<div class="left-col">
<div class="blog-meta">
<h1>{{ .Title }}</h1>
<div class="blog-date">
<span>{{ .Date.Format "2006 年 01 月 02 日"}}</span>
</div>
<div class="blog-img">
{{ if .Params.featured_image }}
<img src="{{- .RelPermalink -}}{{- .Params.featured_image -}}" alt="">
{{ else }}
<img src="/img/default.jpg" alt="">
{{ end }}
</div>
</div>
<div class="blog-content">
{{ .Content }}
</div>
</div>
<div class="right-col">
{{ partial "sidebar" . }} ← partial ディレクトリに sidebar.html がないとエラーになるので注意
</div>
</section>
{{ end }}
最初と最後に、{{ define “main” }} とその締めくくりの {{ end }} があることに注目してください。この間にあるものが main 部分として、先程の baseof.html の {{ block “main” }} に挿入されます。
他にもいくつか重要な構文があります。
{{ .Content }}
ここには、Markdown の frontmatter 以降、つまり本文が html にレンダリングされて入ります。
{{ .Date.Format "2006 年 01 月 02 日"}}
ここは記事の日付を、フォーマットを指定して表示させています。この2006、01という部分は勝手に2020といった数字に書き換えてはいけなくて、ここが置き換えられる仕組みになっています。詳しくはHugoの.Formatについての説明を御覧ください。
{{ if .Params.featured_image }}
<img src="{{- .RelPermalink -}}{{- .Params.featured_image -}}" alt="">
{{ else }}
<img src="/img/default.jpg" alt="">
{{ end }}
ここは、「もし記事の frontmatter に featured_image という項目があるなら」という if 文を使って、アイキャッチが存在するときとしないときで処理を分けています。
アイキャッチ画像は記事と同じフォルダにいれることを想定していますので、存在するならば {{ .RelPermalink }} という相対パスで指定される記事のパスと、{{- .Params.featured_image -}} で指定されるそのファイル名をつなげたものを img タグで呼び出しています。
変な空白が入ってはいけませんので、念のため {{- .RelPermalink -}} と、前後の空白が削除されるように「-」をつけて呼び出しています。
アイキャッチの情報がない場合はデフォルトの画像を表示させています。この「/img」というディレクトリはテーマ直下にありますので、もしテーマの名前が hoge だとするなら、theme/hoge/img という場所にあります。
初めての記事を書いてみる
それでは、このテンプレートで記事を表示させてみましょう。この連載の過去の記事でも触れましたが、Hugo の config.toml が存在するディレクトリで、次のような命令を打ち込んでみます。
hugo new blog/sample/index.md
これで、content/blog/sample/index.md というファイルが作られ、デフォルトのfrontmatterが、現在の日付とともに作成されます。デフォルトの frontmatter は archetype/default.md を使って変更することも可能です。また、このファイルとディレクトリ、frontmatter を手で自分で作ってもかまいません。
hugo -D server
で、サーバーを立ち上げた状態でブラウザを開くと、この記事は localhost:1313/blog/sample/ でアクセスできます。たとえば:
---
title: "テストページ"
date: 2020-04-01T00:00:00+09:00
featured_image: featured.jpg
draft: true
---
frontmatterをこのように変えて、sample.jpg という適当なファイルを index.md が置かれているのと同じディレクトリに置けば、アイキャッチが表示されるはずです。まとめると、single.html の仕組みはこのようになっています。
Hugoはテンプレートに従ってHTMLを作り出しますので、あとはCSSで見た目を決めるだけとなります。
サーバーを立ち上げている間は、index.md の本文を書き換えたり、single.html の各部分に修正を加えると自動的にページがアップデートされてゆく様子もわかると思いますので、さまざまな場所に書き込みをして、対応関係を掴んでみてください。
これで、single.html というテンプレートファイルを使ってブログの個別ページの作り方の初歩が理解できたと思いますので、次はブログのトップページに複数の記事を列挙する仕方、膨大なページを遷移するためのページネーションの方法をみてみましょう。