なるべくプラグインに頼らない勢
WordPressでページネーションを行いたい時プラグインを使う人も多いかと思います。
プラグインをつかうと簡単にページネーションを実現できるので、もちろんそれでもいいのですが、ページネーションの仕組みを知っておくとよりカスタマイズが捗るかもしれません。
実のところプラグインを使わなくても意外と簡単にページネーションを実装することができます。
@MINOはなるべくプラグインに頼らない勢です。
ちょっとした予備知識
WordPressはURLを解析している
WordPressではURLを解析して表示すべきページを決定しています。
例えばWordPressはデフォルトで以下のようなパーマリンクを生成します。
http://hogehoge.com/?p=1027
このURLでアクセスされると、WordPress内部では解析結果を元に表示すべき「IDが1027の投稿」をデータベースから探し、適切なテンプレートファイルにて出力します。
ページネーションを表すURL
さてページネーションを表すURLとはどういった感じでしょうか?
こんな感じになります。
http://hogehoge.com/?paged=2
このURLはデフォルトではTOP画面(index.php
)に対してのアクセスになるはずです。
このURLでアクセスされた場合、paged=2
という情報からWordPressは「1ページに表示する投稿数」を元にして、2ページ目に表示される投稿をデータベースから探します。
たとえば「1ページに表示する投稿数」が10の場合、(デフォルトでは新しい投稿順にて)11投稿目から20投稿目までが2ページ目に表示されるべき投稿になります。
paged=3
なら3ページ目で21投稿目から30投稿目まで、paged=8
なら8ページ目で71投稿目から80投稿目までと言った具合です。
投稿の総数も関係します。例えば100記事あるブログでは11ページ目には表示できる投稿はなくなります。
つまり100記事あるブログでは以下のURLを何らかの方法で動的に生成できればページネーションを実現できるということになります。
http://hogehoge.com/?paged=1
http://hogehoge.com/?paged=2
http://hogehoge.com/?paged=3
http://hogehoge.com/?paged=4
http://hogehoge.com/?paged=5
http://hogehoge.com/?paged=6
http://hogehoge.com/?paged=7
http://hogehoge.com/?paged=8
http://hogehoge.com/?paged=9
http://hogehoge.com/?paged=10
便利なことに、これらのURLをアクセスされたURL解析の結果から動的に生成してくれるpaginate_links
という関数があります。
paginate_linksをつかってページネーションを実装する
paginate_linksオプション
まずはpaginate_links
のオプションです。結構多いですが、全部使わないといけないわけではないデス。
オプション | 意味 | 初期値 |
---|---|---|
base | ページ番号付きのリンクを生成するために使われるベースの URLの指定 | %_% |
format | ページネーションの構造を指定 | paged=%#% |
total | 全体のページ数 | 1 |
current | 現在のページ番号 | 0 |
show_all | true の場合、すべてのページ番号を表示 | false |
end_size | ページ番号のリストの両端(最初と最後)にいくつの数字を表示するか。 | 1 |
mid_size | 現在のページの両側にいくつの数字を表示するか(現在のページは含まない) | 2 |
prev_next | リストの中に「前へ」「次へ」のリンクを含むかどうか | true |
prev_text | 前のページへのリンクとして表示する文言(’prev_next’ 引数が true 場合に有効) | __(‘« Previous’) |
next_text | 次ページへのリンクとして表示する文言。(’prev_next’ 引数が true 場合に有効) | __(‘Next »’) |
type | 戻り値の形式指定 ‘plain’ 改行文字区切りのリンク文字列 ‘array’ リンクの配列 ‘list’ ul タグリスト |
‘plain’ |
add_args | 追加のクエリ引数の配列 | false |
add_fragment | それぞれのリンクに付け加える文字列 | なし |
before_page_number | ページ番号の直前に付け加える文字列 | なし |
after_page_number | ページ番号の直後に付け加える文字列 | なし |
ページネーションのコード
paginate_links
でページネーションを実装するには以下の様にします。このコードはWordPressCodexにて紹介されているコードです(一部違うところもあります)
WordPressCodex 関数リファレンス/paginate links
<?php
$big = 9999999999;
$arg = array(
'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
'current' => max( 1, get_query_var('paged') ),
'total' => $wp_query->max_num_pages
);
echo paginate_links($arg);
?>
このコードで以下のような出力が得られます。(パーマリンクがデフォルトの場合)
<span class="page-numbers current">1</span>
<a class="page-numbers" href="http://hogehoge.com/?paged=2">2</a>
<a class="page-numbers" href="http://hogehoge.com/?paged=3">3</a>
<a class="page-numbers" href="/http://hogehoge.com/?paged=4/">4</a>
<a class="next page-numbers" href="http://hogehoge.com/?paged=2">次へ »</a></div>
コードの設置はループ内である必要はありません。ページネーションが出力されて欲しい場所に記述すればOKです。
paginate_linksのコードの詳細説明
コードでやっていることを説明します。
$bigの設定
$big = 9999999999;
変な数字。これは後で文字列(URLを)を変換するときに用います。
ベースURLの生成
以下の部分でベースのURLを生成します。
'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
str_replace
関数は文字列を指定した文字列でリプレイス(差し替え)する関数です。ちょっとこれは置いおいて、かっこの中身を先に見て行きましょう。
esc_url関数
esc_url
関数はWordPress の関数でURLの無害化(サニタイズ)を行います。
これはなくてもページネーションは動きますが、もし仮に悪意のあるURLでアクセスされたら予期しないURLを生成できてしまうかもしれません。
セキュリティを固くする為、書いておいたほうが良いです。
get_pagenum_link関数
get_pagenum_link
関数もWordPressの関数で引数で与えられた数字を元にページ番号のリンクを返します。つまりこうなります。
get_pagenum_link( $big )
//出力 http://hogehoge.com/?paged=9999999999/
str_replace関数
さてstr_replace
関数ですが、今までのことを踏まえると、「ページ番号のリンクの$big
に該当する場所を'%#%'
で置き換える」という処理をしています。
なんで999999999
なんて変な数字をつかっている理由は、ありえない数字であればURL内のどこにもかぶることがないから、リプレイスの間違いがなくなるためです。
短い数字とかアルファベット(そもそもget_pagenum_linkはアルファベットを引数にできない)だとURLにそれが含まれていた場合、そこがリプレイスされて欲しいURLが得られないことになりかねません。
今までの処理でbase
には以下のようにURLが設定されたことになります。
'base' => http://hogehoge.com/?paged=%#%
現在ページの把握
以下のコードで現在ページを取得しています。
'current' => max( 1, get_query_var('paged') ),
get_query_var
関数はWordPressの関数で、指定したクエリデータを取得します。ここではpaged
を取得しているので、「現在のページ」を得ることができます。
これはアクセスされたURLを解析した結果です。なので0
が返ってくる場合もあります。というのも
http://hogehoge.com/
というURLはなんのクエリも含みません。この場合paged
は0
で取得されます。現在ページが0
になってしまうとpaginate_links
の挙動がおかしくなります。そのためにmax
関数を使って、1
以上の値を出す様にしています。
max
関数は与えられた数値(配列)の中で一番大きな数字を返します。その為、paged
が0
の場合は予め設定していた1
が返ることになります。
もちろんif
で条件分岐できますが、max
関数で要件を満たしているので大丈夫です。
こういった処理でcurrent
には1
以上の現在ページ番号が入ることになります。
最大投稿数の取得
最後は最大投稿数の取得です。「最大投稿数」÷「1ページに表示する投稿数」がページネーションのページ数になりますので必須のオプションです。
$wp_query
オブジェクトのプロパティmax_num_pages
から取得します。
'total' => $wp_query->max_num_pages
つまり100記事で「1ページあたりの表示投稿数」が10
なら、10ページ目(つまり10)がmax_num_pages
となるわけです。「1ページあたりの表示投稿数」は管理画面からでも変更できますので、この数値は可変です。
出力
さてこれで
- ベースになるURL http://hogehoge.com/?paged=%#%
- 現在のページ 1〜10
- 最大のページ数 10
が判明するので、これらの情報をもとにpaginate_links
がよしなにページリンクを出力してくれるのです。
応用編
リスト形式で出力
デフォルトではa
タグで出力されますが、リストで出したい場合もあると思います。そんな時はtype
オプションにlist
を設定すると実現できます。
<?php
$big = 9999999999;
$arg = array(
'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
'current' => max( 1, get_query_var('paged') ),
'total' => $wp_query->max_num_pages,
'type' => 'list'
);
var_dump(paginate_links($arg));
?>
このようにul
リスト形式で出力されます。
<ul class="page-numbers">
<li><span class="page-numbers current">1</span></li>
<li><a class="page-numbers" href="http://hogehoge.com/?paged=2">2</a></li>
<li><a class="page-numbers" href="http://hogehoge.com/?paged=3">3</a></li>
<li><a class="page-numbers" href="http://hogehoge.com/?paged=4">4</a></li>
<li><a class="next page-numbers" href="http://hogehoge.com/?paged=2">次へ »</a></li>
</ul>
配列で出力
リンクのみが欲しい場合はtype
オプションにarray
にします。
<?php
$big = 9999999999;
$arg = array(
'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
'current' => max( 1, get_query_var('paged') ),
'total' => $wp_query->max_num_pages,
'type' => 'array'
);
var_dump(paginate_links($arg));
?>
このように配列でリンクを得ることができます。
array(5) {
[0]=>
string(43) "<span class="page-numbers current">1</span>"
[1]=>
string(67) "<a class="page-numbers" href="http://hogehoge.com/?paged=2">2</a>"
[2]=>
string(67) "<a class="page-numbers" href="http://hogehoge.com/?paged=3">3</a>"
[3]=>
string(67) "<a class="page-numbers" href="http://hogehoge.com/?paged=4">4</a>"
[4]=>
string(85) "<a class="next page-numbers" href="http://hogehoge.com/?paged=2">次へ »</a>"
}
foreach
などで回してあげれば、独自にページネーションを組むことができるでしょう。
CSS
paginate_links
で出力されたa
タグおよびspan
タグにはpage-numbers
というクラスが付きます。
現在ページを表す場合にcurrent
クラスが付きます。
次へリンクにはnext
クラスが、前へリンクにはprev
クラスが付きます。
<a class="prev page-numbers" href="http://hogehoge.com/?paged=1">« 前へ</a>
<a class="page-numbers" href="http://hogehoge.com/?paged=1">1</a>
<span class="page-numbers current">2</span>
<a class="page-numbers" href="http://hogehoge.com/?paged=3">3</a>
<a class="page-numbers" href="http://hogehoge.com/?paged=4">4</a>
<a class="next page-numbers" href="http://hogehoge.com/?paged=3">次へ »</a>
なのでこれらのクラスをつかってcssを定義することで見た目をカスタマイズすることが可能です。
あんまりいい例ではないですがこんな感じで装飾できます。
補足・ハマったポイント
独自クエリでのページネーション
WordPressではWP_Query
クラスに引数を与えて独自にnew
することができます。こうして得られたオブジェクトはURL解析とは別な条件で投稿等を表示させることができ便利です。
この独自クエリにページネーションを施す際の注意点があります。
以下のようにして独自にWP_Query
オブジェクトを得たとします。
$args = array(
'posts_per_page' => 15,
'orderby' => 'date',
'order' => 'DESC',
'post_type' => 'post',
'post_status' => 'publish'
);
$my_query = new WP_Query($arg);
この$my_query
(WP_Queryオブジェクト)には公開されている投稿が日付順にすべて格納されます。
下記はこのオブジェクトでループを回した例です。
ここでも前述した方法でページネーションを出力しています。
ページネーション機能せず
しかしこのままではページネーションは出力はできますが、リンクをクリックしてもページ遷移は行われません。つまり2ページ目には行かないのです。困った…。
これはこの記事の最初で説明した件が関わっています。
WordPressではURLを解析して表示すべき投稿(またはページ)を決めていると説明しましたが、その解析を行っているのは(正確には解析の結果が入るのが)WP_Query
オブジェクトである$my_query
です。
一方新たに独自で作った$my_query
には与えられた引数の解析の結果(引数からSQL文がつくられデータベースから投稿を取得します)が入ります。URLを解析した結果が入るわけではありません。
以下のようなURLの解析結果は
http://hogehoge.com/?paged=2
$my_query
に入るのではなく、グローバルの$wp_query
に入ります。
なので、このままでは$my_query
にはpaged=2
(2ページ目)という解析結果は伝わりません。 2ページ目であることが伝わらないのでずっと1ページ目が表示されてしまうのです。
なんらかの方法で2ページ目であることを取得する必要があります。
get_query_var関数
その時便利なのが、WordPress get_query_var
関数です。
この関数はグローバルオブジェクトの$wp_query
から欲しい情報を取得してくれます。
今回欲しいのはpaged
の情報です。以下のようにして取得できます。
get_query_var('paged')
$myQuery
にいま何ページ目なのかを伝えるには以下のように'paged'=>get_query_var('paged')
を引数に加えます。
'paged'
は「現在ページ」を示します。つまり2なら2ページ目で、4なら4ページ目です。この場合、「1ページあたりの投稿表示数」(’posts_per_page’ )を15にしていますから2ページ目は16投稿目〜30投稿目で、4ページ目は46投稿目〜60投稿目までが表示されます。
ページ遷移が可能になる
これでURLの解析結果は$wp_query
を介して$my_query
に伝わります。
もしURLが
http://hogehoge.com/?paged=2
なら'paged'
に2
が入りますし、
http://hogehoge.com/?paged=4
なら'paged'
に4
が入ります。
ページネーションのリンクをクリックされるごとに'paged'
が更新され、表示すべきページが表示されることになりマス。
まとめ
- プラグインを使わなくてもpaginate_linksで簡単にページネーションができる
- CSSで見た目も変えられる
- URLの解析に関してすこし知識がつく
- 独自クエリでもページネーションができる