Hugo初心者がテーマを自作した記録 各カテゴリの最新記事の表示

2019-07-25 |
2019-11-02

The Hugo Gopher is designed by Renée French


今回はトップページに各カテゴリの最新記事を表示する方法について解説していこうと思います。

トップページに各カテゴリの最新記事を表示しておけば、トップページを見てもらうだけでなんとなくブログの雰囲気を掴んでもらえそうな感じがしています。

というわけで、個人的にどうしても表示したいと思っていました笑

Hugoのタクソノミー機能におけるカテゴリではなく、セクション機能を用いてカテゴリ分けしているので、ちょっと処理が複雑になりましたが、解説していこうと思います。

やりたいこと

やりたいことはトップページに各カテゴリの最新記事を表示するですが、具体的にどのような状況なのか説明していきます。

まず、この記事でカテゴリと書いているのはHugoのタクソノミー機能におけるカテゴリではなくて、セクション機能における記事ファイルの保存ディレクトリを指しています。

タクソノミー機能でのカテゴリ分け

タクソノミー機能でのカテゴリ分けは、まずconfig.tomlに、

[taxonomies]
    category = "categories"

と書くことで、Hugoのタクソノミー機能を有効にします。

次に、各記事のmarkdownファイルのfront matterに所属するカテゴリを書いていきます。

categories = ["Development"]

このようにすることで、Hugoのタクソノミー機能でのカテゴリが作用するようになります。

タクソノミー機能でのカテゴリ分けの問題となるのは、markdownファイルそれぞれを編集する必要があるということです。

あとから変更しようと思ったときに修正して回るのは面倒です…

また、タクソノミー機能におけるカテゴリは階層関係を表現しないので、記事を整理しづらいというのもあります。

セクション機能でのカテゴリ分け

セクション機能でのカテゴリ分けは、各記事のmarkdownファイルの保存場所であるディレクトリによって決まります。

たとえば、programmingディレクトリに記事を保存していれば、programmingセクションに属する記事というふうになり、このセクションをカテゴリとして扱っていく感じです。

ここで、注意しなければいけないのは、セクション機能を有効にするには、各セクションに_index.mdというファイルが必要になります。

この_index.mdのfront matterにtitleを設定しておくと、セクション名として扱われるので好きなように名前をつけれます。

大カテゴリ、中カテゴリ、小カテゴリといったように階層を持ったカテゴリで記事の分類をしたいと思っていたので、セクション機能を用いて記事のカテゴリ分けをしていきます。

以上を踏まえた上でのやりたいこと

トップページに各カテゴリの最新記事を表示させたいのですが、すべてのカテゴリについて最新記事を表示するようにしてしまうと、カテゴリがふえるたびにトップページに表示する量が増えてしまいます。

これでは最初に書いたように、トップページを見てもらうことでブログの雰囲気を掴んでもらうことができなさそうです。

そこで、大カテゴリに当たるようなある程度大きめな分け方での最新記事を表示させたいと思います。

具体的には、大カテゴリと、その下に属するカテゴリたちから記事を集めてきて、その中で最新のものを表示するようにします。

各カテゴリの最新記事の表示

まず、セクション機能を用いて記事のカテゴリを管理すると、どのようなファイル構成になっているのかを、私の場合を例としてみていきます。

├── content
│   ├── pages
│   │   ├── _index.md
│   │   └── about.md
│   └── posts
│       ├── _index.md
│       ├── book
│       │   └── _index.md
│       ├── life
│       │   ├── 2019-06-20-first-entry.md
│       │   ├── 2019-06-23-ap-pass.md
│       │   └── _index.md
│       ├── money
│       │   └── _index.md
│       ├── programming
│       │   ├── _index.md
│       │   └── hugo
│       │       ├── 2019-07-06-hugo-install.md
│       │       ├── 2019-07-08-create-hugo-theme.md
│       │       ├── 2019-07-11-create-hugo-theme-nav.md
│       │       ├── 2019-07-17-create-hugo-theme-breadcrumb.md
│       │       ├── 2019-07-19-create-hugo-theme-latest-area.md
│       │       └── _index.md
│       └── study
│           └── _index.md

今回は、私のブログと同じように、postsセクションの一つ下の階層にある、bookセクション、lifeセクション、moneyセクション、programmingセクション、studyセクションを大カテゴリとして、それぞれについての最新記事を3件表示するようにします。

では、さっそくコードを見ていこうと思います。

{{ with .Site.GetPage "/posts" }}
  {{ range .Sections }}
    {{ $list := slice }}
    {{ range .Pages }}
      {{ $list = $list | append . }}
    {{ end }}
    {{ if gt (len .Sections) 0 }}
      {{ range .Sections }}
        {{ range .Pages }}
          {{ $list = $list | append . }}
        {{ end }}
      {{ end }}
    {{ end }}
    {{ if gt (len $list) 0 }}
    <div>
      <div>
        <div>
          {{ .Title }}
        </div>
        {{ range first 3 (sort $list "Date" "desc") }}
          <a href="{{ .Permalink }}">{{ .Title }}</a><br>
        {{ end }}
      </div>
    </div>
    {{ end }}
  {{ end }}
{{ end }}

{{ with .Site.GetPage "/posts" }}とありますが、"/posts"の部分は私のファイル構成を参考に、みなさんの相当するものに書き換えてください。

今回のコードにはそこまで新しい要素はでてきていませんが、配列の変数を宣言したり、その配列を操作したりしているので、そこについて解説してみたあとに処理の流れを見ていこうと思います。

slice

今回は、{{ $list := slice }}によって、配列の変数$listを宣言しています。

この配列に要素を足す操作が、{{ $list = $list | append .Page }}の部分です。

今回は配列で処理を書いていったので、.ByDate.Reverseのような感じでコレクションをソートしたりできなかったです。

よって、sort $list "Date" "desc"によって作成日について降順に並び替えています。

処理の流れ

まず、{{ with .Site.GetPages "/posts" }}によって、大カテゴリが属するセクションのページを参照します。

withを用いているので、postsページが取得できなかったときはこの処理は走りません。

次に、{{ range .Sections }}によって、postsページの1つ下の階層にあるセクションを参照して、それぞれについて{{ end }}までに書かれた処理を回していきます。

{{ $list := slice }}で配列の変数$listを宣言します。

この$listに大カテゴリの下にぶらさがっている各カテゴリの記事を追加していきます。

{{ range .Pages }}によって、そのセクションに属する記事ファイルのコレクションを参照して、それぞれについて{{ end }}までに書かれた処理を回していきます。

記事ファイルのコレクションに対する処理は、記事ファイル自身を$listに追加していく処理です。

そして、そのセクションの記事ファイルを$listに追加し終わったら、{{ if gt (len .Sections) 0 }}によってそのセクションの1つ下の階層のセクションがあるかどうか判定します。

gtはgreater thanの意味で、len .Sectionsは1つ下の階層のセクションのコレクションの長さを返すので、下に1つ以上セクションがあるかどうかを判定しています。

もし、下にセクションがあればこれまでの処理のように、各ページを$listに追加して、そのセクションの1つ下の階層にセクションがあるか判定して…という再帰的な流れになると思います。

私の場合は、postsセクションより3つ下の階層まで使うだろうということで、その分だけ処理を書いています。

今回はごちゃごちゃするとイヤなので、2つ下の階層まで探しに行くコードを書いています。

もっと下の階層まで取りに行きたい場合は、templateを使って再帰的に書くか、必要な階層分だけ処理を追加してください。

$listにページを追加し終わったら、{{ range first 3 (sort $list "Date" "desc") }}によって、作成日について皇潤で並び替えたコレクションの先頭から3件について、リンクを表示するhtmlタグを出力していきます。

おわりに

各カテゴリの最新記事を表示するやり方を解説しました。

あるカテゴリの最新記事はその下位カテゴリにある記事を反映する感じにしたかったので、一度下まで潜って対象となる記事を全て配列に追加してからソートして取り出しました。

Hugoのセクション機能を用いてカテゴリ分けをしていますが、その仕組みを自分の言葉で説明しようとするとしっくり来る表現が見つからず、なんだか分かりづらい表現になってしまったので反省。

Please share, if you like this.