Nunjucks (JSテンプレートエンジン) でニュースを管理する

昨年の後半から立て続けに、MT(Movable Type)絡みのご相談をいただいたのですが、その中で1件、結果的にCMSでの管理自体をやめちゃった案件がありました。CMSをやめた場合に課題となるのが、ニュースなどの「記事が時系列・カテゴリ別で蓄積されていくアーカイブ系のコンテンツ」の管理です。

NunjucksなどのJSテンプレートエンジンはCMSに代わるものでは決してありませんが、この案件ではNunjucksでニュースを管理することで脱CMSを実現しました。
社内的にも面白い取り組みだったので、JSテンプレートエンジンの活用方法の1つとしてご紹介したいと思います。

脱CMS「ニュース」の課題

ニュースのようなアーカイブ系コンテンツには、次のような特徴があります。

  1. カテゴリ別や年別など条件別の一覧ページがある
  2. 1つの記事が複数のページに表示される(グランドトップ・カテゴリトップなど)
  3. 一覧ページの表示件数に応じて、ページングが発生する
  4. 記事ページに、前後記事へのリンクがある

WP(WordPress)やMTといったCMSでは、ページの表示要素以外に、属するカテゴリやタグ・作成日などの付帯情報を持ち、それらを条件として表示を制御することができます。しかし静的に作った場合は全ての反映を手作業で行うことになり、時間ばかりがかかるうえ、必ずどこかでミスが生じます。
これらをどう運用していくのか。ここが、CMSをやめる場合の大きな課題になります。

CMSをやめる=すべてが静的ファイルになるわけですが、その前工程にJSテンプレートエンジンを使うことで、この課題を何とかしようというのが今回の試みです。

出来上がりのイメージ

この記事を書くにあたって、実物があった方が分かりやすいと思いサンプルサイトを作成しました。
→ Nunjucksでニュースを管理するサンプルサイト

サンプルサイトの構造とニュースのカテゴリ

  • グランドトップ/ニュース/製品情報/IR情報/企業情報、というメニュー構成
  • ニュースには「製品情報/IR情報/企業情報」の3つのカテゴリがある
  • また「製品情報」には「ピボットフォーム/その他」というサブカテゴリがある

ニュースの表示条件は各ページ次のようになっています。

グランドトップ

/

サンプルサイト:グランドトップ
  • 全てのニュースが対象
  • 最新5件のみを表示

ニューストップ

/news/

サンプルサイト:ニューストップ
  • 全てのニュースが対象
  • 10件ずつページングして全件表示

ニュースの製品情報カテゴリ一覧

/news/products/

サンプルサイト:ニュース>製品情報
  • 「製品情報」のニュースが対象
  • 10件ずつページングして全件表示

ニュースの製品情報のサブカテゴリ一覧

/news/products/pivotform/

サンプルサイト:ニュース>製品情報>サブカテゴリ
  • 「製品情報」のサブカテゴリ「ピボットフォーム」のニュースが対象
  • 10件ずつページングして全件表示

よく見る仕様ですね。
CMSを使った場合と変わらないように見えますが、このサンプルサイトは実際にCMSを使用せず、かつ手動で一覧ページを編集することなく更新することができます

では具体的にどのように管理されているのか、実装方法を見ていきます。

全体の仕組み

この機能を実現するため、タスクランナーのGulpとJSテンプレートエンジンのNunjucksを使います。全体の流れは次のようなイメージ。

Nunjucksでニュースを管理する全体の仕組みイメージ

ニュースのデータが書かれたJSONファイル(news.json)の変更をGulpで検知し、Nunjucksテンプレートを更新、HTMLを生成するという流れです。

DBの代わりにJSONファイルを使う

冒頭で、CMSは「ページの表示要素以外に、属するカテゴリやタグ・作成日などの付帯情報を持ち、それらを条件として表示を制御する」と書きました。CMSではこれらのデータがDBに保存されますが、今回はその代りにJSONファイルを使って一覧ページの表示を制御します。

サンプルサイトのJSONファイルは次のようになっています。

{
  "news" : [
    {
      "category1" : "ir",
      "category2" : "",
      "date" : "2019年02月12日",
      "title" : "第9期 第3四半期報告書",
      "url" : "/news/detail.html"
    },
    {
      "category1" : "pro",
      "category2" : "pf",
      "date" : "2019年01月31日",
      "title" : "「ピボットフォーム」プリセットデザインを追加しました",
      "url" : "/news/detail.html"
    },
    .....
  ]
}
JSONキー
category1 メインカテゴリ(製品情報pro/IR情報ir/企業情報company
category2 製品情報のサブカテゴリ(ピボットフォームpf/その他others
date 日付
title ニュースのタイトル
url ニュース詳細ページのURL

サンプルサイトのニュース一覧はとてもシンプルな作りですが、別サイトへリンクする場合に<a target="_blank">を指定できるようにしたり、「new」アイコンを表示するといった条件もここで設定することができます。

NunjucksでHTMLを生成する

このJSONファイルからニュースリストを受け取って、条件に合致するデータを抽出、それを使ってHTMLが生成されるよう、Nunjucksのテンプレートコードを設定します。

全てのニュースの最新5件を表示する場合

グランドトップのように、全てのニュースのうち最新の5件(※1)のみを表示する場合のテンプレートコードは次のようになります。(必要な部分のみ抜粋)
※1:ここでの「最新5件」はJSONファイルの記述順です。ニュースの日付はチェックしてません。

ポイント

  • L1-2:category1, category2 の値を設定。全てのニュースが対象なのでどちらも空です。
  • L3:表示するニュースの数を設定。ここでは5件です。
  • L12:for文で配列newsのキーを繰り返し処理しますが、このnewsにはJSONの全データが渡されています。
  • L13:現在処理中のインデックス番号が「5」以下の場合のみ処理を実行=最新5件のみが処理されます。
  • L16-24:各ニュースのデータをitemで呼び出しています。

set news_category1 = 'ir'のようにカテゴリを指定すると指定されたカテゴリのニュースのみが対象になり、set news_amount = 5の値を変えることで、表示件数をページ単位で指定することができます。

全件表示で10件ずつページングする場合

例えば「製品情報」のニュース全件が対象で、10件ずつページングする場合のテンプレートコードは次のようになります。(必要な部分のみ抜粋)

ポイント

  • L1:category1にpro(製品情報)を指定しています。
  • L3:ページング処理に使う、現在のページ番号を指定しています。(1ページ目)
  • L14:ニュースリストから製品情報のニュースを取り出して繰り返し処理します。
  • L17:現在のページ番号に合致する10件を表示。
  • L44:該当するニュースの件数から、ページングのページ数を算出。
  • L45:ページの数分、リンクブロックを表示。
  • L46-57:現在のページ番号に応じたカレント処理など。

このように、データに応じた処理をJSテンプレートエンジンで行いHTMLを生成することで、簡易的なCMSに似た機能を作ることができます。

Gulpで自動化する

あとは、JSONファイルの更新からHTMLファイルの生成までのタスクをGulpで自動化します。
gulpfile.jsは次のようになります。(必要な部分のみ抜粋)

ポイント

  • L3:GulpでNunjucksのレンダリングを使うためのプラグインを読み込む
  • L4:GulpでJSONデータを扱うためのプラグインを読み込む
  • L5:Node.jsでファイルを操作するためのモジュールを読み込む
  • L23-25:JSONファイルからデータを取得してテンプレートに渡す
  • L34:JSONファイルに変更があったら、タスクnunjucksを実行

!JSONの変更が反映されない?

JSONファイルのデータを取得する際、単純に次のようにデータを渡すと、JSONに更新を掛けても生成されるHTMLに変更が反映されません。

pipe(data(function(){
  return require(paths.src.json_news);
}))

Node.jsでJSONファイルを読み込むrequireはオブジェクトをキャッシュするため、JSONファイルを消したり中身を更新してもNunjucksテンプレートに渡される値が変わりません。
JSONファイルの更新をリアルタイムに反映する場合は、Node.jsのfsモジュールを使ってfs.readFileSyncメソッドでファイルを読み込みます。

これで準備は完了。ニュースの追加変更に合わせてJSONファイルを更新するだけで、関連するHTMLが自動で出力されるようになります。簡易的なCMSの出来上がりですね。

このような実装をすることになった経緯

WebサイトにCMSを実装することは、今では難しくなくごく一般的なことなのに、なぜCMSをやめる提案になったのか。最後にその理由をご紹介します。

もともとは、「MTで管理されている企業サイトのサーバを(中身は変えずに)引越したい」というご要望でした。「サーバを引っ越す」という仕事です(渋い)。MTも新サーバにそのまま移設して継続という予定でしたが、よくよく聞くと「今後は社内で更新するのではなく、MTでの更新も含め社外に任せたい」と。

どうやら構築から複数年経過し、担当者の変更もあって、CMSがあっても積極的にそれを触って更新していく、という状況が無くなってしまったようです。

「すべての運用作業をご依頼いただくのであれば…MTは要りません」
ということで、わざわざMTを新サーバに引っ越すことはせず、出力済みのHTMLのみを移設し管理できるようにした、というのが事の経緯です。

CMSが一般的になってしばらく経ちますが、「機能は充実させたがほとんど使っていない」「時間がなくて結局更新できない」という声も多く聞こえてくるようになりました。一周回ってまた、全ての運用業務をプロに任せるケースが出てきそうです。

ちなみに、このプロジェクトのお客さまは弊社で運用業務をするようになってから、Webサイトの更新・発信量がかなり増えました。各部署から予想外に依頼が増えたとのことで、ご担当者さまは予算取りをしていなかったのもあり「嬉しい悲鳴」とおっしゃっています。