これは 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 }}"><<</a></li>
<li class="prev"><a href="{{ pageInfo.prevUrl }}{{ query }}"><</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 }}">></a></li>
<li class="last"><a href="{{ pageInfo.lastUrl }}{{ query }}">>></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 テンプレートなどにも転用できるハズですので、参考にしてみてください。