WP_Query() で特定の記事一覧を表示する場合、ページネーション(1ページ目、2ページ目など表示しているページ数を示す数字のリンク表示)では、get_query_var() でページ番号を取得してpaginate links() でページリンクの表示をしたりします。
でも自作の関数やプラグインを functions.php に記述して同じことをやろうとすると、ページネーションのページ数字のリンクは表示されるけど2ページ目とか3ページ目をクリックしてもなぜか表示されるのは1ページ目だけ。(2ページ目とかが表示されないのだよ、ワトソン君)
どうやら WP_Query() は投稿や固定ページと管理ページとでは使い方が異なるようで、色々調べてみると get_query_var() に問題があったようです。
ここでは問題となった症状や、その解決法のご紹介。
管理画面ではページネーションができない?
WP_Queryを使ってページネーション表示をする場合、
基本形は以下みたいになると思いますが...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
<?php //------------------------------------ //ページ番号を取得:最初は1ページ目 //------------------------------------ $paged = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1; //------------------------------------ //WP_Queryの検索条件 //------------------------------------ $args_query = array( 'post_type' => array( 'post', 'page' ), //投稿、固定ページ 'post_status' => array( 'publish', 'draft' ), //公開済、下書き 'paged' => $paged, //表示するページ番号 ); //------------------------------------ //一覧の取得と表示 //------------------------------------ $my_query = new WP_Query($args_query); if ( $my_query->have_posts() ) : echo '<ul>'; while ( $my_query->have_posts() ) : $my_query->the_post(); //何を表示するか echo '<li>' . get_the_title() . '</li>'; endwhile; echo '</ul>'; wp_reset_postdata(); //WP_Query のリセット else: echo '<p>no data</p>'; endif; //------------------------------------ //ページペーション //------------------------------------ $big = 999999999; $args_paginate = array( 'base' => str_replace($big, '%#%', esc_url(get_pagenum_link($big))), 'current' => max(1, get_query_var('paged')), 'total' => $my_query->max_num_pages, ); ?> |
関数リファレンス/WP_Query
関数リファレンス/get_query_var
関数リファレンス/paginate_links
これでプラグイン化して管理画面で表示させてみると、
以下のような感じで良さそうには見えます。
期待通り WP_Query で記事の一覧が表示され、
ページネーション(ページのリンク)も表示されますね。
でも② のページネーションの数字をクリックしても、
2ページ目以降が表示されず、表示されるのは常に1ページ目。
こんな感じで、ページリンクの「2」とか「次へ」をクリックしてもURLは「paged=2」とか変わりますが、実際の表示は1ページ目しか表示されないんですね。
(ショートコード化して記事で表示すると2ページ目とかも表示されて問題ないんですけど)
WP_Queryは動作しているしページネーションの数字のリンク自体は問題なさそうですが、管理ページで表示すると以下がうまく動作しないようです。
- 1)WP_Queryに渡す引数の paged (表示するページ番号)が正しくない
- 2)paginate_links に渡す引数の current (現在のページ番号)が正しくない
- どちらのページ番号も get_query_var で取得しているので、管理ページでは get_query_var が期待通りに動作しないのかも
get_query_var の関数リファレンスを改めて見てみると、
get_query_var は固定ページでは get_query_var( 'paged' ) ではなく、get_query_var( 'page' ) にする、という仕様なため、管理ページもそうなのかな?と変えてみても結果は同じ。
また get_query_var は「WP_Queryで認識する”パブリッククエリ変数のみ”を取得する」とも書かれてます。
この場合の変数は「paged=2」となるのでこれが認識されてないのかな?と関数リファレンスに書かれているコードをちょっと変えて以下追加してみても結果は同じ。
1 2 3 4 5 6 |
// 新しい独自クエリ変数をWP_Query に含める function add_query_vars_filter( $vars ){ $vars[] = "paged"; // paged を含めてみる return $vars; } add_filter( 'query_vars', 'add_query_vars_filter' ); |
そもそも関数リファレンスをよく読むと「paged」もパブリッククエリ変数の1つのようなので、これは全く意味がなかったかも ^-^;)
ということで解決策を色々調べてみてもこのあたりの情報はなさそうでしたが、英語で調べてみると(WP_Query pagination admin とかで調べてみると)2つ解決法がありました。
解決法その1)$_GET['paged'] を使う
ページ番号を取得するのを get_query_var ではなく、
URLに「paged=2」があるので $_GET['paged'] を使う。
最初これで良いのかな、と思って試してはいたものの、何かワードプレスのルールに従ってないかもと不安になってましたが、英語文化圏ではこの解決策が出ていて一安心(笑)。
1 |
$paged = ( $_GET['paged'] ) ? $_GET['paged'] : 1; |
$_GET['paged'] の値があればその値を使い、なければ1(1ページ目)にする、といった3項演算子ですが、これを使って ページ番号( $paged)の取得箇所を置き換えれば良さそうです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<?php //------------------------------------ //ページ番号を取得:最初は1ページ目 //------------------------------------ //$paged = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1; $paged = ( $_GET['paged'] ) ? $_GET['paged'] : 1; //------------------------------------ //WP_Queryの検索条件 //------------------------------------ $args_query = array( 'post_type' => array( 'post', 'page' ), //投稿、固定ページ 'post_status' => array( 'publish', 'draft' ), //公開済、下書き 'paged' => $paged, //表示するページ番号 'posts_per_page' => 5, //一度に表示する件数 ); //------------------------------------ //一覧の取得と表示 //------------------------------------ $my_query = new WP_Query($args_query); if ( $my_query->have_posts() ) : echo '<ul>'; while ( $my_query->have_posts() ) : $my_query->the_post(); //何を表示するか echo '<li>' . get_the_title() . '</li>'; endwhile; echo '</ul>'; wp_reset_postdata(); //WP_Query のリセット else: echo '<p>no data</p>'; endif; //------------------------------------ //ページペーション //------------------------------------ $big = 999999999; $args_paginate = array( 'base' => str_replace($big, '%#%', esc_url(get_pagenum_link($big))), // 'current' => max(1, get_query_var('paged')), 'current' => max(1, $paged ), 'total' => $my_query->max_num_pages, ); echo paginate_links( $args_paginate ); ?> |
置き換えた個所は6行目と44行目。
これで2ページ目以降も正しく動作するようです。
ただ、最初の1ページ目の表示で「paged=」がURLにない場合にはエラー(pagedなんて知らないよエラー)が出てしまいます。
ということから、以下のようにすると良さそうですね。
1 |
$paged = isset($_GET['paged'] ) ? $_GET['paged'] : 1; |
isset を使って、$_GET['paged']があればその値を、なければ 1(1ページ目)にするってわけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
<?php //------------------------------------ //ページ番号を取得:最初は1ページ目 //------------------------------------ //$paged = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1; //$paged = ( $_GET['paged'] ) ? $_GET['paged'] : 1; $paged = isset($_GET['paged'] ) ? $_GET['paged'] : 1; //------------------------------------ //WP_Queryの検索条件 //------------------------------------ $args_query = array( 'post_type' => array( 'post', 'page' ), //投稿、固定ページ 'post_status' => array( 'publish', 'draft' ), //公開済、下書き 'paged' => $paged, //表示するページ番号 'posts_per_page' => 5, //一度に表示する件数 ); //------------------------------------ //一覧の取得と表示 //------------------------------------ $my_query = new WP_Query($args_query); if ( $my_query->have_posts() ) : echo '<ul>'; while ( $my_query->have_posts() ) : $my_query->the_post(); //何を表示するか echo '<li>' . get_the_title() . '</li>'; endwhile; echo '</ul>'; wp_reset_postdata(); //WP_Query のリセット else: echo '<p>no data</p>'; endif; //------------------------------------ //ページペーション //------------------------------------ $big = 999999999; $args_paginate = array( 'base' => str_replace($big, '%#%', esc_url(get_pagenum_link($big))), // 'current' => max(1, get_query_var('paged')), 'current' => max(1, $paged ), 'total' => $my_query->max_num_pages, ); echo paginate_links( $args_paginate ); ?> |
これで上手くページネーションができるようになりました。
(やったね!^-^))
解決法その2)get_query_var が使える?
もう1つ解決策があるようなので参考までに。
get_query_var の英語版の関数リファレンスをチェックしてみると、下の方の「User Contributed Notes」(ユーザーメモ)に以下が書かれてます。
Because get_query_var() uses the WP_Query class, which only operates within The Loop, this function cannot be used to get a url variable outside of The Loop (e.g., a WordPress admin page).
Instead use $_GET[‘var_name’] as in typical PHP.
- get_query_var()はループ内でのみ動作するWP_Queryクラスを使用することから、WordPress管理ページなどループ外のurl変数を取得することはできない。
- 代わりに$ _GET [‘var_name’] を使用する。
最初にここをチェックすればよかった(日本語版の関数リファレンスにも書いておいてほしいぞよ)...と思いつつ、これに対してのフィードバック(以下)に、get_query_var はループ外でも使用でると書かれてるんですね。
We actually can use get_query_var() outside The Loop, this function only requires the main $wp_query to be already intialized. See in the source code that the $wp_query->get() method gets the value from the $this->query_vars field, which is intialized on constructor and on call of init method. — By jorovipe — 1 year ago
- get_query_var はループ外でも使用でる
- この関数では、メインの$wp_queryが初期化されている必要がある。
- $wp_query-> get()メソッドが$ this-> query_varsフィールドから値を取得することをソースコードで確認してみてよ。
- このフィールドは、コンストラクターとinitメソッドの呼び出しで初期化されるんだ。
$wp_query が初期化されていれば、get_query_var が使える、ということのようですが、たとえば(これは変だよねと思いつつ試しに)コードの最初に初期化のための wp_reset_postdata() とかを入れてみても、get_query_var でページ番号の値は取得できないのは変わらず。
何か管理画面でも get_query_var が使える手段、というか、コードの書き方があるようですが、具体的なサンプルコードとかないかなと調べてみても残念ながら分かりませんでした。
今回のポイント
- 投稿や固定ページでは、$wp_query のページ番号は get_query_var で取得できるので問題ない
- プラグイン作成や関数追加、といった管理画面で $wp_query を使う場合、ページ番号は $_GET['paged'] で取得する!
解決策を見つけるまでに物凄く時間がかかってしまいましたが、ひとまず $_GET['paged']を使えばよい、ということでスッキリです(笑)
何か他に、こうすればよい、というコードの書き方などあればコメント欄でお知らせいただけると嬉しいです。
ネットビジネス、ブログでの収益化については、以下のメルマガからジャンジャン情報取ってみてくださいね。