WP_Queryの2ページ目以降が表示できないのでメインループを変更してみる
WP_Queryでカスタム投稿タイプを取得した際に、2ページ目以降の表示が行われなかった。
で、よく取り上げられているredirect_canonicalのフックでis_singlar()とpagedを見て404.phpに転送させない方法を試したところ、これがどうしてうまく効かなかった。
で、なぜWP_Queryを使った際によく取り上げられているredirect_canonicalが効かなかったかと言うと、
- 404ページが表示される時点でis_404はtrueとなり、is_singular()の値はfalseとなる。(メインループであるglobal $wp_queryの仕様)
- redirect_canonicalのフックはそもそも前方一致でのURLの補正を行うものであり、補正前のURLを補正後のURLに転送するか、そのまま補正せずに404として扱うかどうかを指定するためのものである。(つまり、これでカスタム投稿タイプの転送を行うこと自体があまり好ましくない。)
- 単にカスタム投稿タイプを一覧表示するだけならWP_Queryを使わんとwhile使おうよ。(カスタム投稿タイプも通常の投稿タイプみたくwhileで取得すれば、2ページ目以降はきちんと表示される。WP_Queryを使って取得してる時点で別のテンプレートでカスタム投稿タイプを呼び出しているわけで、メインループとサブループの仕様をガン無視してる…。)
以上の点が考えられる。
ちなみにWP_Queryを使う以上は通常の投稿タイプだろうがカスタムタクソノミーだろうが同じ現象が起こりうる。
まぁ、主な原因は上記の1.が強く、2のredirect_canonicalフックの用途が作用している。
2ページ目以降に表示されるページは、表示されるのは転送は行われていれども「404テンプレート」そのもの。
そんなところにredirect_canonicalフックでis_singular()とかで条件付けてやっても404が表示されている限りはis_singular()はfalseなので効かないのは当然だよね、という話である。
で、どうしても3.のパターンを承知で、何らかの理由でどうしてもWP_Queryでループを回して、かつ2ページ以降を表示したい場合もある。
これの解決のため、テンプレート転送のtemplate_redirectのフックを利用して、以下のようにして2ページ目以降の404を切るコードを作った。
function remove_template_redirect() { global $wp_query; // var_dump( $wp_query ); if ( is_404() && ( isset( $wp_query->query['paged'] ) && $wp_query->query['paged'] >= 2 ) ) { status_header( 200 ); $wp_query->is_404 = false; } } add_filter( 'template_redirect', 'remove_template_redirect' );
404テンプレートに2ページ目以降でアクセスした際、強制的にステータスレスポンスを正常にした上でメインループであるglobal $wp_queryを変更、というかis_404を書き換える。
このままでも一応は使えるが、条件を見る通り全体に対して適用するため、それをやりたくないときはコメントアウトしてあるvar_dump( $wp_query );で表示状況を見て適宜条件を指定するのが望ましい。