Craft CMS の行列(Matrix)フィールドのテンプレートを最適化してみる

これは Craft CMS Advent Calendar 2017 21日目の記事です。

Craft CMSのMatrix(行列)を使ってみた | </ Redamoon.Log>
https://redamoon.net/log/post/000039.html

昨日のぐっちーさんのブログ記事を拝見して、ふと「行列(Matrix)フィールドのテンプレートは {% include %} タグを使う方が便利かも?」と感じたので、備忘録を兼ねてまとめてみます。

はじめに

コーディング時に Sass でスタイル定義をする場合、コンポーネントごとに .scss ファイルを分けて @import で読み込んでいる方も多いかと思います。

ファイルを細かく分けておくことで、時間を空けて修正が必要になった際もコードの可読性が高くなったり、プロジェクトをまたいで再利用できたりと、メリットがありますよね。

そこで、Matrix フィールドも同様に「ブロック単位でファイルを切り分けて、テンプレートを管理する」というのが今回の主旨です。

行列(Matrix)フィールドの作成

テンプレートを用意するにあたり、サンプルの 行列(Matrix) フィールドを作成します。
下記を参考に「新しいフィールドを作る」画面に移動してください。

Craft CMS のフィールドについて理解しよう | BUN:Log
https://bunlog.dreamseeker.dev/learn-about-craftcms-fields

次に フィールドタイプ までの項目を設定します。

ラベル
グループDefault
名前本文用コンポーネント
ハンドルmatrix_component
フィールドタイプ行列

フィールドタイプのプルダウンから 行列 を選択すると、直下に 構成 が表示されますので4つのブロックを作成します。

見出しブロック

名前を 見出し、ハンドルを heading でブロックタイプを作成し、フィールドを1つ追加します。

ラベル
名前見出し
ハンドルheading
フィールドタイププレーンテキスト

設定後の画面サンプルも参考にしてください。

見出しブロック

本文ブロック

名前を 本文、ハンドルを body でブロックタイプを作成し、フィールドを1つ追加します。

ラベル
名前本文
ハンドルbody
フィールドタイププレーンテキスト
改行を許可するON
最初の行4

設定後の画面サンプルも参考にしてください。

本文ブロック

画像ブロック

名前を 画像、ハンドルを image でブロックタイプを作成し、フィールドを1つ追加します。

ラベル
名前画像
ハンドルimage
フィールドタイプファイル管理
アップロードを単一フォルダに限定しますか?ON
ロケーションをアップロードする本文画像
本文画像 という名称のアセット・ソースを用意しておいてください。
許可されるファイルの種類を制限しますか?ON
※ここでは 画像 のみ許可する形で設定します。
リミット1
モードを見る。リスト

設定後の画面サンプルも参考にしてください。

画像ブロック

アセット・ソースの作成は、下記も参考にしてください。

Craft CMS のファイル管理について理解しよう | BUN:Log
https://bunlog.dreamseeker.dev/learn-about-craftcms-assets

表組みブロック

名前を 表組み、ハンドルを table でブロックタイプを作成し、フィールドを1つ追加します。

ラベル
名前表組み
ハンドルtable
フィールドタイプテーブル

テーブルの欄 は、以下のように定義してください。

欄の見出しハンドルタイプ
ヘッダhead一行テキスト
データ1data1一行テキスト
データ2data2一行テキスト

設定後の画面サンプルも参考にしてください。

テンプレートファイルの構成

テンプレートの編集にあたり、ディレクトリ構成を確認しておきましょう。

craft
└── templates/
    ├── _entry.twig        # エントリ詳細ページ
    └── _matrix_component  # matrix_component フィールドのパーツを格納するディレクトリ
        ├── body.twig      # 本文ブロック
        ├── heading.twig   # 見出しブロック
        ├── image.twig     # 画像ブロック
        └── table.twig     # 表組みブロック

_entry.twig に読み込みの定義を行い、エントリで追加されているブロックにあわせて _matrix_component 配下の対応するパーツを読み込むイメージです。

テンプレートファイルの作成

それぞれのテンプレートを作成していきましょう。

_entry.twig(エントリ詳細ページ)

{% extends "_layout" %}

{% block content %}
  {# エントリに紐づく行列(Matrix)のブロックすべてをループ処理 #}
  {% for block in entry.matrix_component.limit(null) %}
    {# ブロックタイプごとのパーツを読み込み #}
    {% include '_matrix_component/' ~ block.type ignore missing %}
  {% endfor %}
{% endblock %}

entry.matrix_component.limit(null) で、エントリに追加されている「本文用コンポーネント」フィールドのブロックすべてを取得します。それをループ処理し、{% include '_modules/matrix_component/' ~ block.type %} でブロックタイプごとのテンプレートファイルを読み込みます。

このとき ignore missing とすることで、読み込み対象のファイルが存在しない場合でも Twig エラーを回避できます。

_matrix_component/heading.twig(見出しブロック)

各ブロックごとのパーツは、存在するフィールドにあわせて調整する形となります。

{# フィールドの値を変数にセット #}
{% set block_heading = block.heading %}

{# 任意のマークアップで出力 #}
<h1>{{ block_heading }}</h1>

読み込み元で定義されている変数 block をそのまま利用できるため、見出し フィールドの値を block.heading で取得しています。

_matrix_component/body.twig(本文ブロック)

{# フィールドの値を変数にセット #}
{% set block_body = block.body %}

{# 任意のマークアップで出力 #}
<p>{{ block_body | nl2br }}</p>

本文 フィールドは改行を有効にしているため、nl2br フィルタで改行コードを br タグに変換します。

_matrix_component/image.twig(画像ブロック)

{# フィールドの値を変数にセット #}
{% set block_image = block.image.first() %}

{# 画像がセットされていれば、任意のマークアップで出力 #}
{% if block_image | length %}
  <figure><img src="{{ block_image.url }}" alt="{{ block_image.title }}" ></figure>
{% endif %}

画像 フィールドにセットされた最初の画像を取得するため、 block.image.first() としています。また {% if block_image | length %} は画像がある場合のみ出力するための分岐処理です。

_matrix_component/table.twig(表組みブロック)

{# フィールドの値を変数にセット #}
{% set block_table = block.table %}

{# データがセットされていれば、任意のマークアップで出力 #}
{% if block_table | length %}
  <table>
    {% for row in block_table %}
      <tr>
        <th>{{ row.head | raw }}</th>
        <td>{{ row.data1 | raw }}</td>
        <td>{{ row.data2 | raw }}</td>
      </tr>
    {% endfor %}
  </table>
{% endif %}

画像ブロックと同様に {% if block_table | length %} で入力値がない場合は table タグを出力しないよう調整しています。raw フィルタは HTML タグを入力値に含む場合を想定した記述となります。

まとめ

今回は、行列(Matrix)フィールドのテンプレートを {% include %} タグと組み合わせて最適化する方法についてまとめてみました。

ファイルが細かく分かれるため、ともすれば管理が面倒と感じられるかもしれませんが、個人的には便利だと思っているので一度試してみてください。