Craft CMS 向け汎用ページナビゲーション

これは Craft CMS Advent Calendar 2019 1日目の記事です。

Craft CMS の一覧用テンプレートでページ分割をする場合、{% paginate %} タグを利用します。
その際、ページナビゲーションの処理は大きく変わることなく似たようなコードを書いているため、汎用モジュールテンプレートを用意しています。

今回はそれのご紹介です。

はじめに

{% paginate %} タグの使用方法は、以前掲載した【Craft 3 サイト構築の基本】エントリ一覧をページ分割する方法や公式リファレンスをご覧ください。

{% paginate %} タグ | Craft 3 ドキュメント
https://docs.craftcms.com/v3/ja/dev/tags/paginate.html#ナビゲーションの実例

ページナビゲーションの汎用モジュール

以下のコードを craft/templates/_partials/common/paginate.html として、Craft CMS 本体のインストール先にある templates 配下に保存します。

コーディングデータに合わせたマークアップの調整は、適宜行ってください。

{#
 # Paginate template
 # ---------------
 #
 # 「ページナビゲーション」のテンプレートモジュールです。
 #}

{% if pageInfo.totalPages > 1 %}
  {# ------------------------------------------
  変数など
  --------------------------------------------- #}
  {# 現在のページの前後に、それぞれ表示するリンク数 #}
  {% set viewLinkCount = 4 %}
  {# 前後に表示するリンク数の倍数 #}
  {% set viewLinkDoubleCount = viewLinkCount * 2 %}
  {# 現在のページからみた、残りのページ数 #}
  {% set remainingPageCount = pageInfo.totalPages - pageInfo.currentPage %}
  {# 現在のページよりも前に表示するリンク数(画面あたりの表示数を9にするため、最後から4ページまでは動的に算出) #}
  {% set viewPrevLinkCount = (remainingPageCount <= viewLinkCount) ? viewLinkDoubleCount - (remainingPageCount) : viewLinkCount %}
  {# 現在のページよりも後に表示するリンク数(画面あたりの表示数を9にするため、最初から4ページまでは動的に算出) #}
  {% set viewNextLinkCount = (pageInfo.currentPage <= viewLinkCount) ? (viewLinkDoubleCount + 1) - pageInfo.currentPage : viewLinkCount %}

  {# URL パラメータがセットされる想定の変数 query が未定義であれば、初期化 #}
  {% if query is not defined %}
    {% set query = null %}
  {% endif %}

  {# ------------------------------------------
  出力
  --------------------------------------------- #}
  <ul>
    {# 先頭ページ・前のページへのリンク #}
    {% if pageInfo.currentPage > 1 %}
      <li class="first"><a href="{{ pageInfo.firstUrl }}{{ query }}">&lt;&lt;</a></li>
      <li class="prev"><a href="{{ pageInfo.prevUrl }}{{ query }}">&lt;</a></li>
    {% endif %}

    {# 表示できない前のリンクがある場合は、三点リーダを表示 #}
    {% if pageInfo.currentPage - 1 > viewLinkCount and pageInfo.totalPages > viewLinkDoubleCount + 1 %}
      <li class="ell">…</li>
    {% endif  %}

    {# 前のページへのリンク #}
    {% for page, url in pageInfo.getPrevUrls(viewPrevLinkCount) %}
      <li><a href="{{ url }}{{ query }}">{{ page }}</a></li>
    {% endfor %}

    {# 現在のページ番号 #}
    <li><a href="#" class="current">{{ pageInfo.currentPage }}</a></li>

    {# 次のページへのリンク #}
    {% for page, url in pageInfo.getNextUrls(viewNextLinkCount) %}
      <li><a href="{{ url }}{{ query }}">{{ page }}</a></li>
    {% endfor %}

    {# 表示できない次のリンクがある場合は、三点リーダを表示 #}
    {% if remainingPageCount >= viewNextLinkCount + 1 %}
      <li class="ell">…</li>
    {% endif  %}

    {# 次のページ・最終ページへのリンク #}
    {% if pageInfo.currentPage < pageInfo.totalPages %}
      <li class="next"><a href="{{ pageInfo.nextUrl }}{{ query }}">&gt;</a></li>
      <li class="last"><a href="{{ pageInfo.lastUrl }}{{ query }}">&gt;&gt;</a></li>
    {% endif %}
  </ul>
{% endif %}

以下、簡単な解説です。

{% if pageInfo.totalPages > 1 %}

これで全体を囲んでいるため、分割後の総ページ数が2ページ以上の場合のみ出力されます。

{% set viewLinkCount = 4 %}

ここでは前後のページリンクの出力数(初期値)を設定しています。サンプルの場合、現在のページと合わせて9つのページリンクが表示されます。

{# 現在のページよりも前に表示するリンク数(画面あたりの表示数を9にするため、最後から4ページまでは動的に算出) #}
{% set viewPrevLinkCount = (remainingPageCount <= viewLinkCount) ? viewLinkDoubleCount - (remainingPageCount) : viewLinkCount %}
{# 現在のページよりも後に表示するリンク数(画面あたりの表示数を9にするため、最初から4ページまでは動的に算出) #}
{% set viewNextLinkCount = (pageInfo.currentPage <= viewLinkCount) ? (viewLinkDoubleCount + 1) - pageInfo.currentPage : viewLinkCount %}

ここでは「最後から4ページまで」と「最初から4ページまで」の場合でも、表示されるページリンクが9つになるよう分岐処理を加えています。なお、実際の表示数は viewLinkCount の値によって自動的に変化します。

{# URL パラメータがセットされる想定の変数 query が未定義であれば、初期化 #}
{% if query is not defined %}
  {% set query = null %}
{% endif %}

ここは URL パラメータがない場合、変数を初期化するための記述です。
Craft CMS が動的に生成するページナビゲーション内の URL には URL パラメータが含まれないため、必要に応じてテンプレートモジュールの呼び出し元でセットする想定となります。

{# 表示できない前のリンクがある場合は、三点リーダを表示 #}
{% if pageInfo.currentPage - 1 > viewLinkCount and pageInfo.totalPages > viewLinkDoubleCount + 1 %}
  <li class="ell">…</li>
{% endif  %}

{# 表示できない次のリンクがある場合は、三点リーダを表示 #}
{% if remainingPageCount >= viewNextLinkCount + 1 %}
  <li class="ell">…</li>
{% endif  %}

これらは総ページ数が多い場合(例えば、30ページ中の10ページ目など)、必要に応じて前後に三点リーダを表示するための分岐処理です。

使い方

{% paginate %} タグを定義した後、モジュールをインクルードします。

{# リクエストパラメータをセット #}
{% set query = (craft.request.getParam('news')) ? craft.request.getParam('news') : '' %}

{# 任意のエントリをページ分割 #}
{% paginate craft.entries.limit(20) as pageInfo, pageEntries %}

{# ページャを出力 #}
{% include '_partials/common/paginate' with { 'query': query } %}

{# ページに含まれるエントリのループ処理 #}
{% for entry in pageEntries %}
  (中略)
{% endfor %}

フィルタや並び替えなど必要な URL パラメータがあれば、あらかじめ変数 query にセットしておきましょう。

まとめ

ページナビゲーションに限らず、よく使うコードをテンプレートモジュールとして使いまわせるのは便利ですね。

ここでは Craft CMS の {% paginate %} タグを利用する前提ですが、ページ総数と現在のページが変数化されていれば他の CMS テンプレートなどにも転用できるハズですので、参考にしてみてください。