11ty(eleventy)のcollectionsとfront-matterで、有機的なナビゲーションを自動生成する


ナビゲーションを自動化したい目的で、自分のサイトのドキュメントを11tyとPugで書き直しています。

11tyではcollections.allでサイト全体の情報をオブジェクトで取得できます。
また、各ページの先頭に以下のようにfront-matterを記述することで、ページごとの変数を渡すことができます。

---
sample: "これはページ内のテンプレートエンジンや、11tyのcollectionsで変数sampleとして取得できます"
---

これらを利用して、下の画像のように擬似的な階層を持ちつつ、順番に読ませるリンクも表示するナビゲーションを、ページを増やすごとに自動更新できないかと考えました。

  • 同じ小カテゴリーの
    • 次のページが存在していれば、次ページへのリンクボタンを表示する
    • 次のページが存在しなければ、次の小カテゴリーの1番目へのリンクボタンを表示する
  • いずれもなければボタンは表示しない

以下、実装できたのでコードを記載します。

front-matterの内容

各ページにorder変数を定義しておきます。小カテゴリー内で連番とし、カテゴリーが変わった場合は10の位を1増やした1番目のページから再度カウントします。
つまり、先ほどの図の場合は「コーディングルール」のページはorder: 16で、「カラーテーブル」のページはorder:21となります。

---
order: 16
pageTitle: "コーディングルール"
---

mixinを作成する

次ページの情報を表示するmixinは以下の通りです。Pugで記述していますが他のテンプレートエンジンも同様の考え方となります。

mixin nextNav(order)
  -
    let nextID = Number.parseInt(order)+1;
    let next = collections.all.filter((a) => Number.parseInt(a.data.order) === nextID);

  if next.length === 0
    -
      nextID = (Math.trunc(order/10)*10)+11;
      next = collections.all.filter((a) => Number.parseInt(a.data.order) === nextID);

  each item in next
    p 
      a(href=item.url) Next: #{item.data.pageTitle}

処理の流れ

まず、order変数がorder+1となっているページをリクエストします。このmixinでは、collections.allにJavaScriptのfilterをかけていますが、もっとスマートな方法があるかもしれません。

  -
    let nextID = Number.parseInt(order)+1;
    let next = collections.all.filter((a) => Number.parseInt(a.data.order) === nextID);

結果が空であれば、10の位を上げ、さらに1増やして再試行します。
10で割ってからMath.truncで整数部分を取り、もう一度10倍すると、10の位のぴったりの数字となります(3なら0、16なら10です)。これに11を足して位を上げています。

  if next.length === 0
    -
      nextID = (Math.trunc(order/10)*10)+11;
      next = collections.all.filter((a) => Number.parseInt(a.data.order) === nextID);

最後にページ情報を展開します。1件か0件であるはずです。リンクのラベルテキストはfront-matterで定義しているページタイトルを出したいのでdata.pageTitleとなります。

  each item in next
    p 
      a(href=item.url) Next: #{item.data.pageTitle}

テンプレートで呼び出す

テンプレート側ではorder変数を渡して呼び出します。Pugは継承が使えるので、レイアウトテンプレートに書いておけばよいと思います。

+nextNav(order)

サイトマップの生成は、JSONでデータを書いて展開する方法がよく紹介されているのですが、これだと実際のHTMLを変更・削除したときに漏れが出そうなので、ジェネレーターらしい手段を考えてみました。

11tyは、サイト内のページ情報を常に整理してくれているようです。うまく利用すれば静的なサイトも破綻やリンク切れを起こさずに作成できるかなと感じています。