category

Craft CMS でカテゴリ代わりにエントリをつかってカテゴリアーカイブ(一覧)ページを作成する #craftcms

2019-08-22




Craft CMS をつかうとどういいのか?を解説するコンテンツを作ってみようということでサンプルを作ってみている。

使い方サンプル:bp出版社 | bit part 合同会社
https://bit-part.net/craftcms/...

これまで案件でも MTAppjQuery サンプルとかでも出版社サンプルみたいなのを作っていたのでそれを作ってみた。

このサンプルでは「カテゴリ」セクションを作って「書籍」セクションに「カテゴリセクションのエントリ」を選択するフィールドを用意して、カテゴライズするという方法にしてみた。

セクション名、フィールド名

カテゴリセクション:sample_publisher_category

書籍セクション:sample_publisher_book
フィールド「カテゴリ」(エントリ選択フィールド):sample_publisher_category
(たまたまセクション名と同じになった)

こういう感じ。
書籍セクションのエントリのフィールド「カテゴリ」でカテゴリセクションのエントリ(カテゴリ名)を選択している。

書籍の一覧は「書籍」セクションのエントリ一覧を取ればいいのでそこまで難しい話ではない。

カテゴリごとの書籍一覧を作成するというのが今回。リレーションから取り出すというまだまだ慣れていない話。

この辺でも色々やったり、今回も参考にしたりした。

同じセクション内で自エントリを選択しているエントリを取り出す #craftcms | mersy note
https://note.mersy418.com/arti...
Craft CMS の Matrix フィールドで特定のフィールドの値が一致するエントリをループで取得する #craftcms | mersy note
https://note.mersy418.com/arti...
【CraftCMS】エントリフィールドをキーとしてエントリを取得する - Qiita
https://qiita.com/SHIN_DEVELOP...
Craft CMS で日付や数値を指定してエントリを絞り込む | BUN:Log
https://bunlog.dreamseeker.dev...
Craft CMS で lightswitch がONのエントリを取り出す #craftcms | mersy note
https://note.mersy418.com/arti...

URL設計

今回URLとしては /sample_publisher/category/hogehoge のようにする予定。

このURLに含まれる category からカテゴリアーカイブなのかどうか?を判定して出力する。
著者アーカイブも作る予定でそれは author にする予定。

テンプレート

テンプレート(sample_publisher/_list.twig)全体としてはこんな感じ

{# セクションを取得 #}
{% set sectionSegment = craft.request.getSegment(2) %}

{# URLからcategoryなのか著者一覧かをふりわけてセクション名をセット ちとダサい #}
{% if sectionSegment == 'category' %}
  {% set sectionHandle = "sample_publisher_category" %}
{% elseif sectionSegment == 'author' %}
  {% set sectionHandle = "sample_publisher_author" %}
{% endif %}

{# slugからエントリID、タイトルを取得 #}
{% set slugID = craft.entries.section(sectionHandle).slug(slug).one().id %}
{% set sectionEntryTitle = craft.entries.section(sectionHandle).slug(slug).one().title %}

{# 書籍エントリのうち当該エントリIDが関連付けられているエントリリストを取得 #}
{% set entries = craft.entries.section(sectionHandle).id(slugID) %}
{% set sectionEntries = craft.entries.section('sample_publisher_book')
  .relatedTo({
    targetElement : entries,
    field: sectionHandle
  }).all()
%}

中略

{% for book in sectionEntries %}
表示処理
{% endfor %}

segmentの取り出し

最初にカテゴリアーカイブなのかどうか?を判定するためにURLからsegmentを取り出す。

craft.request.getSegment(2) で category のところが取り出せる

この書き方は古い書き方みたいなので craft.app.request.getSegment(num) が推奨されていると @BUN @tinybeans に教えてもらった。

Changes in Craft 3 | Craft 3 Documentation
https://docs.craftcms.com/v3/c...

とりあえずはここで取り出したものを元にカテゴリアーカイブなのか著者アーカイブなのかを分けることにする。

そのために

{% if sectionSegment == 'category' %}
  {% set sectionHandle = "sample_publisher_category" %}
{% elseif sectionSegment == 'author' %}
  {% set sectionHandle = "sample_publisher_author" %}
{% endif %}

の部分で対象とするセクションを切り替える、という感じにしてある。

sample_publisher_{{slug}}

みたいにやればスマートなのかもしれない。

エントリのID、タイトルを取り出す

/sample_publisher/category/hogehoge の hogehoge をみてそれぞれのエントリを取り出す。

ここは slug となるようにルートの設定をしてあるので slug が一致するものを取得する、という方法。
(slug = mt:entrybasename みたいな話)

{% set slugID = craft.entries.section(sectionHandle).slug(slug).one().id %}
{% set sectionEntryTitle = craft.entries.section(sectionHandle).slug(slug).one().title %}

このテンプレート内ではルートの設定から変数 slug に slug (今回のhogehoge)が渡されてくる。

ルートの設定ではこのURLルールのときに処理するテンプレート(sample_publisher/_list.twig)も設定してある。

書籍エントリのうちカテゴリhogehogeが設定されているものを取り出す

ここが毎回サクッと行かずに悩むところなのだけど。

テンプレートとしてはこの部分。

{# 書籍エントリのうち当該エントリIDが関連付けられているエントリリストを取得 #}
{% set entries = craft.entries.section(sectionHandle).id(slugID) %}
{% set sectionEntries = craft.entries.section('sample_publisher_book')
  .relatedTo({
    targetElement : entries,
    field: sectionHandle
  }).all()
%}

後半のところで sectionEntries に設定さえできてしまえばあとはよしなにできるのでここが重要。。。でいつも頭がこんがらがる。

取り出したいセクションは書籍セクションなので、 .section('sample_publisher_book') になる。

relatedTo で関連付けられてるものを取り出すのだけど、今回はたまたまセクション名の handle とフィールド名の handle が一致してるのもあるので関連付けされてるかどうかを見るフィールドは「カテゴリ」フィールドでそのハンドルは sectionHandle で渡ってきているので field: sectionHandle になる。

たまたま同じだから良かったけど、ここはなんか別の書き方があったかもしれない。変数名が良くないのと汎用性を考えるとカテゴリフィールド、著者フィールドの命名も考える必要がありそう。

そこで関連付けられているエントリ(この場合のhogehoge)を targetElement : entries, で渡す感じになるのだけどここはエントリ名とかslugとかそういう話ではなくて、オブジェクト?というかエントリ自体を渡す必要がある(ということをようやく理解した)。

厳密には渡せるものはもっとあるらしいが一旦それはおいておく。

ということでそのために

{% set entries = craft.entries.section(sectionHandle).id(slugID) %}

で hogehoge エントリを id 指定で取り出したものを entries にセットしておく、という感じになる。


ブログ書きながら直せばよかったところや、勘違いしていたところとかがわかったのでまだまだわかっていない。

もう少しテンプレート書きながら慣れないと使いこなせないなー。

ただ、このサンプルコンテンツを作ってみて、設計するときになんとなくで作っていたところがもう少しいい方法があるんじゃないか?とか、その設計にした根拠は?とかを考え直すきっかけになるのでいい感じ。

もう少しいろいろな種類のコンテンツ、要件をサンプルとして作ってみたいと思う。