【Craft 3 サイト構築の基本】「ニュース」セクションの作成(一覧ページテンプレート編)

これは Craft CMS Advent Calendar 2018 14日目の記事です。
連載「サンプル制作で覚える Craft 3 サイト構築の基本」の「ニュース」セクションの作成ということで、一覧ページのテンプレートを作成します。

ここでは、次の作業を行います。

  1. コーディングデータの流用
  2. 「固定表示フラグ」が ON の最新エントリを出力
  3. 「ニュース」セクションのエントリ一覧を出力
  4. 重複するエントリの除外

工程ごとの差分データは「素材データ専用リポジトリ vol-9 ブランチ」にコミットしてあります。

コーディングデータの流用

コーディングデータ(web/html/news/index.html)から、メインコンテンツ部分のソースコードをコピーします。【参考コミット】

article.featured.news-entry は「固定表示フラグ」が ON の最新エントリ。その後に続く article.news-entry が「ニュース」セクションのエントリ一覧となります。

「固定表示フラグ」が ON の最新エントリを出力

詳細ページテンプレート以外でエントリを出力するには、対象となるエントリを明示的に取得する必要があります。

対象エントリの取得

「固定表示フラグ」が ON の最新エントリを取得するために、次の3つの条件で絞り込みを行います。

  • セクションが「ニュース」
  • 「固定表示フラグ」が ON
  • 投稿日の降順

これを Twig コードに置き換えると

{# 「固定表示フラグ」が ON の最新エントリを取得 #}
{% set featuredEntry = craft.entries({
  section: 'news',
  featuredEntry: 1,
  orderBy: 'postDate desc'
}).one() %}

となります。別な書き方として

{# 「固定表示フラグ」が ON の最新エントリを取得 #}
{% set featuredEntry = craft.entries.section('news').featuredEntry(1).orderBy('postDate desc').one() %}

でも同じ結果が得られます。「投稿日の降順」は Craft 3 のデフォルトのため、orderBy の指定を省略しても問題ありません。

取得したエントリの出力

{# 「固定表示フラグ」が ON の最新エントリ #}
{% if featuredEntry %}
  {# 「メイン画像」を取得 #}
  {% set image = featuredEntry.featuredImage.one() %}

  <article class="featured news-entry">
    {# 「メイン画像」がセットされていれば、出力 #}
    {% if image %}
      <figure>
        <a href="{{ featuredEntry.url }}">
          <img src="{{ image.url }}" alt="{{ image.title }}" width="570" height="348">
        </a>
      </figure>
    {% endif %}
    <div class="summary-wrap">
      <h3><a href="{{ featuredEntry.url }}">{{ featuredEntry.title }}</a></h3>
      <span class="author">{{ featuredEntry.author.name }}</span>
      {{ featuredEntry.shortDescription }}
      <p>
        <a href="{{ featuredEntry.url }}" class="more-link">Read More</a>
      </p>
    </div><!-- /.summary-wrap -->
  </article><!-- /.featured.news-entry -->
{% endif %}

{% if %} タグで対象エントリが存在する場合のみ出力するよう分岐しています。

変数 featuredEntry にエントリをセットしていることを除けば、前回の詳細ページテンプレートと似たような記述になっていることが判ると思います。【参考コミット】

「ニュース」セクションのエントリ一覧を出力

「ニュース」セクションのエントリ一覧は article.news-entry をループ処理するため、1件分のマークアップだけを残して削除しておきます。【参考コミット】

対象エントリの取得

「ニュース」セクションのエントリ一覧を絞り込むための条件は、次の2つです。

  • セクションが「ニュース」
  • 投稿日の降順

これをテンプレートに定義すると

{# 「ニュース」セクションのエントリを取得 #}
{% set newsEntries = craft.entries({
  section: 'news',
  orderBy: 'postDate desc'
}) %}

となります。先の変数 featuredEntry にセットしたときとの違いとして .one().all() を付けていないことに注意してください。

取得したエントリの出力

複数のエントリが対象となるため、{% for %} タグでループ処理します。【参考コミット】

{# 「ニュース」エントリの一覧 #}
{% for entry in newsEntries.all() %}
  {# 「メイン画像」を取得 #}
  {% set image = entry.featuredImage.one() %}

  <article class="news-entry">
    {# (中略) #}
  </article><!-- /.news-entry -->
{% endfor %}

{% for entry in newsEntries.all() %} としていることから、このループ内では変数 entry でエントリデータを取得できます。

また、入力タイプに応じて Check it out もしくは Read More と分岐する処理は次のようになっています。

{% if entry.type == 'link' %}
  {# 「リンク」入力タイプの場合 #}
  <a href="{{ entry.url }}" class="more-link">Check it out</a>
{% else %}
  {# 「デフォルト」入力タイプの場合 #}
  <span class="author">{{ entry.author.name }}</span>
  <span class="separator">|</span>
  <a href="{{ entry.url }}" class="more-link">Read More</a>
{% endif %}

入力タイプのハンドルを entry.type で取得し、それを任意の文字列と比較する形です。

重複するエントリの除外

ここまでの状態でフロントエンドにアクセスすると、赤枠で囲まれたエントリが重複表示されているのが判ります。

エントリ一覧

特定エントリを除外するには

特定エントリの除外は、パラメータに id: 'not <entry.id>' を付けることで実現できます。

{# 「ニュース」セクションのエントリを取得 #}
{% set newsEntries = craft.entries({
  section: 'news',
  orderBy: 'postDate desc',
  id: (featuredEntry ? 'not ' ~ featuredEntry.id : null)
}) %}

この場合、変数 featuredEntry がセットされていればそれを除外、セットされていなければすべてを表示とするため、三項演算子を利用して id: (featuredEntry ? 'not ' ~ featuredEntry.id : null) としています。【参考コミット】

エントリ一覧

これで、重複表示が解消されました。

まとめ

今回は、「ニュース」セクション一覧詳細ページ向けのテンプレート作成について見てきました。
それぞれのエントリデータの出力自体は詳細ページと変わらないため、エントリの絞り込みに慣れれば難しくなさそうですよね?

次回は、同じテンプレートファイルを利用して「エントリ一覧をページ分割する方法」について解説します。