2016/04/08 13:31:36

WordPressでプラグインを使わずに簡単にページネーション(ページ送り)を行う


Warning: Attempt to read property "post_excerpt" on null in /home/kpkyvkzp/public_html/unskilled.site/wp-content/themes/unskilled2/content-header-eyecatch.php on line 5
目次(クリックするとジャンプします)
  • 1:なるべくプラグインに頼らない勢
  • 2:ちょっとした予備知識 
  • 2.1:WordPressはURLを解析している
  • 2.2:ページネーションを表すURL
  • 3:paginate_linksをつかってページネーションを実装する
  • 3.1:paginate_linksオプション
  • 3.2:ページネーションのコード
  • 4:paginate_linksのコードの詳細説明
  • 4.1:$bigの設定
  • 4.2:ベースURLの生成
  • 4.2.1:esc_url関数
  • 4.2.2:get_pagenum_link関数
  • 4.2.3:str_replace関数
  • 4.3:現在ページの把握
  • 4.4:最大投稿数の取得
  • 4.5:出力
  • 5:応用編
  • 5.1:リスト形式で出力
  • 5.2:配列で出力
  • 5.3:CSS
  • 6:補足・ハマったポイント
  • 6.1:独自クエリでのページネーション
  • 6.1.1:ページネーション機能せず
  • 6.1.2:get_query_var関数
  • 6.1.3:ページ遷移が可能になる
  • 7:まとめ

なるべくプラグインに頼らない勢

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);
?>

このコードで以下のような出力が得られます。(パーマリンクがデフォルトの場合)

pagenation

<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はなんのクエリも含みません。この場合paged0で取得されます。現在ページが0になってしまうとpaginate_linksの挙動がおかしくなります。そのためにmax関数を使って、1以上の値を出す様にしています。

max関数は与えられた数値(配列)の中で一番大きな数字を返します。その為、pagedの場合は予め設定していたが返ることになります。

もちろんifで条件分岐できますが、max関数で要件を満たしているので大丈夫です。

こういった処理でcurrentには以上の現在ページ番号が入ることになります。

最大投稿数の取得

最後は最大投稿数の取得です。「最大投稿数」÷「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を定義することで見た目をカスタマイズすることが可能です。

あんまりいい例ではないですがこんな感じで装飾できます。

pagenation-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の解析に関してすこし知識がつく
  • 独自クエリでもページネーションができる