こんにちはkです。
いやータイトル通りびっくりです。
query_postsは非推奨
日本語版codexにはこのように
query_posts() はデータベースに問い合わせて投稿の一覧を生成するための、数ある方法のひとつに過ぎません。query_posts() を使うと決める前に、欠点も理解しておいてください。
メインループを変更する
query_posts() はメインループを変更するためのものです。query_posts() はそのために、メインループを生成するクエリーを置き換えます。いったん query_posts() を使うと、投稿にもとづいたグローバル変数やテンプレートタグも変更されます。query_posts() を呼び出したあとは、条件分岐タグも置き換えられてしまいます。このことが意図しない結果を引き起こすかもしれません。
派生的なループ
派生的な一覧 (例えばページの下部に関連記事を表示したり、サイドバーのウィジェットでリンクの一覧を出したり等) を表示したい場合は、WP_Query の新しいインスタンスを生成するか、get_posts() を使ってください。
もし query_posts() を使う場合は、用が済んだら必ず wp_reset_query() を呼び出してください。
‘paged’ クエリー引数を適切に指定していないと、ページ送りが正しく動作しない可能性があります。「クエリに “paged” パラメーターを追加」を参照してください。
SQLクエリーが追加発行される
もし query_posts をテンプレートで使用する場合、そのテンプレートを読み込むまでに WordPress はすでにデータベースへの問い合わせを実行し、データの取り出しを終えています(どのテンプレートを読み込むかが決まったということは、すでに処理が終わっているということですから!)。そのため、query_posts() を使ってデフォルトのクエリーを上書きして結果を得るには、どうしても再度データベースに問い合わせし再計算する必要があります。
このことは、小規模なブログベースのウェブサイトを扱っているのであれば、必ずしも問題であるとは言えません。しかしデータベースが大きい大規模でトラフィックの多いウェブサイトの開発者であれば、デフォルトのクエリーが呼び出される前に直接変更するなどの代替案を検討するほうがいいかもしれません。request フィルターでまさにこれを実現できるでしょう。
データベースへ問い合わせる SQL を生成するのに使われる内部的な $query オブジェクトを改変するには、’parse_query’ と ‘pre_get_posts‘ フィルターも利用できます。
http://wpdocs.osdn.jp/%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%82%BF%E3%82%B0/query_posts#.E6.B3.A8.E6.84.8F
ようは、完全に、使うんじゃねーよ。使うなよ?つかってもしらねー。
って意味らしい。
あ、でもよくよく見ていくとすこーしだけわかってきたかも。
query_postsの中身はこんな感じなので
global $wp_query; return $wp_query->query($query);
単にグローバル変数に格納されているクエリーに引数をつけて呼び出しているだけですね。
これをやってしまうと、条件を追加する前の状態に戻せなくなっちゃう!アナタどうしてくれるのよ!ということで、途中でコアの記述はこんなふうに変わりました。いったんメインクエリーを消しちゃって、新しくデータベースからデータを取得しよう。PHPのunsetとは、データを消しちゃうって意味です。
global変数に格納されている情報を呼び出している状態。。。。。
ということは、query_postsを使って条件を書き換えて、使っていたら、元に戻せなくなってるということか!
そこから進化して、バージョンアップして登場したのはこれかな
function wp_reset_query() { $GLOBALS['wp_query'] = $GLOBALS['wp_the_query']; wp_reset_postdata(); }
wp_reset_queryですね。
query_postsをつかってループ処理して、条件を付け加えたら、
ちゃんともとにもどしてね。
戻さないと知らないよってこと。
そのおかげでページ送りが効かなくなったりとか不具合もでるそう。
なるほどなぁと思うのですが、昔からquery_postsを愛用していた僕からしたら
そしたらどうすればよいの?と思うところ。
ありました!答えが!
pre_get_postsフィルターを使いましょう
pre_get_postsフィルターとは、WordPressがクエリーを取得するまえに必ず実行されるフィルターフックです。これも昔からあるのですが、WordPressがあらゆる投稿データを取得するときに通るフィルターなので、無警戒に使うと管理画面も派生的なクエリーも何もかも改変されてしまいます。このままでは使いにくいのですが、query_postsがもともと想定していた用途はメインクエリーの変更ですので、pre_get_postsフィルターでメインクエリーかどうかのチェックがかんたんにできるように修正されました。
したがって、いまではこのフィルターを使うのはかなりかんたんですし、
query_postsにできてpre_get_postsフィルターでできないことはありませんし、query_postsにできてget_postsにできないこともありません。
固定ページのテンプレートにquery_postsを書いて何らかのアーカイブとして使うという手法も根強く採用されているかと思いますが、それもカスタム投稿タイプの出現で過去のものです。もうquery_postsの使い方を覚える必要はないですし、一切使う必要もありません。めでたしめでたし。
では、pre_get_postsフィルターの使い方。これらのコードは基本的にfunctions.phpに書くとおぼえてください。
例:アーカイブで1ページに表示される件数を5件にする(管理画面の設定を上書きする)
function change_posts_per_page($query) {
if ( is_admin() || ! $query->is_main_query() )
return; if ( $query->is_archive() ) {
$query->set( 'posts_per_page', '5' ); }
}
add_action( 'pre_get_posts', 'change_posts_per_page' );
冒頭のこの記述がポイントです。
if ( is_admin() || ! $query->is_main_query() ) return;
基本毎回コピペでいいと思います。管理画面、またはメインクエリーでない場合は、ここで処理を中止してそれ以降のコードは実行されないようにします。これを書かないと、管理画面の一覧も、サイドバーのウィジェットも、全部5件ずつの表示になってしまいます。
どんな条件の時にクエリを変更するか設定
メインクエリーかどうかチェックしたあとは、条件分岐でアーカイブの時だけに限定しています。
if ( $query->is_archive() ) { ... }
その他にも、下記の条件分岐が使えます(WordPress3.5.1時点、抜粋)。
ポストタイプアーカイブか?(引数はポストタイプ名,または配列)(ラベルではない)
$query->is_post_type_archive( $post_types )
著者アーカイブか?(引数は著者ID,ニックネーム,表示名,またはそれらの配列)
$query->is_author( $author )
カテゴリーアーカイブか?(引数はカテゴリーID,スラッグ,名前,またはそれらの配列)
$query->is_category( $category )
タグアーカイブか?(引数はタグスラッグ,またはその配列)
$query->is_tag( $slug )
タクソノミーアーカイブか?(引数はタクソノミーのスラッグと、タームのID,名前,スラッグ,またはそれらの配列)
$query->is_tax( $taxonomy, $term )
日付アーカイブか?
$query->is_date()
フィードか?(引数はフィードの種類)
$query->is_feed($feeds)
フロントページか?
$query->is_front_page()
固定ページか?(引数はページID,タイトル,スラッグ,またはそれらの配列)
$query->is_page( $page )
検索結果か?
$query->is_search()
投稿か?(引数は投稿ID,タイトル,スラッグ,またはそれらの配列)
$query->is_single( $post )
どの投稿タイプのシングルか?(引数は投稿タイプ,またはその配列)
$query->is_singular( $post_types )
404ページか?
$query->is_404()
クエリを設定
条件が指定できたら、いよいよメインクエリーを変更しましょう。変更といっても、query_postsのように必要なパラメーターをすべて揃える必要はありません。追加したいパラメーターをセットするだけです。基本的な書き方はこうです。
$query->set( 'パラメーター名', 'パラメーターの値' );
上のサンプルコードでは、1ページに表示する件数を5件に設定しています。
$query->set( 'posts_per_page', '5' );
どんなパラメーターが使えるかは、Codexの関数リファレンス/WP_Queryのページを参考にしてください。
クエリパラメータの値を取得
この書き方で、すでに設定されているクエリーパラメーターの値を取得することもできます。
$query->get( 'パラメーター名' );
他のサンプル
IDが2のカテゴリーを表示する際、IDが6のカテゴリーにも属している記事だけを表示する
function customize_main_query($query) {
if ( is_admin() || ! $query->is_main_query() )
return;
if ( $query->is_category(2) ) {
$query->set( 'category__and', array(2,6) ); }
}
add_action( 'pre_get_posts', 'customize_main_query' );
検索結果から、IDが3の著者の記事を除外する
function customize_main_query($query) {
if ( is_admin() || ! $query->is_main_query() )
return; if ( $query->is_search() ) {
$query->set( 'author', '-3' );
}
}
add_action( 'pre_get_posts', 'customize_main_query' );
検索結果から、カスタムフィールド “exclude_search” に 1 が保存されている投稿を除外する
function customize_main_query($query) {
if ( is_admin() || ! $query->is_main_query() )
return; if ( $query->is_search() ) {
$query->set(
'meta_query',
array(
array(
'key' => 'exclude_search',
'value' => '1',
'compare' => '!=',
'type' => 'NUMERIC'
)
)
);
}
}
add_action( 'pre_get_posts', 'customize_main_query' );
ね、かんたんでしょ。ページ送りの引数を引き継がなきゃいけないとか、リセットしないと他の部分がおかしくなるとか、まったく配慮しなくてもOKです。
さらには、ユーザーやコメントの検索も、今後は似たような書き方になっていきますよ。いま覚えておかないとWordPressの世界についていけなくなりますよ〜。
function customize_user_query($query) {
$query->set( 'exclude', array(5,6) );
}
add_action( 'pre_user_query', 'customize_user_query' );
function customize_comment_query($query) {
$query->set( 'order', 'ASC');
}
add_action( 'pre_get_comments', 'customize_comment_query' );
こんな感じみたいです。
実際にまだ使っていないので、なんともいえないですが、ソースを見た感じ
楽!!
依存をかんがえなくていいのですね!°˖✧◝(⁰▿⁰)◜✧˖°
僕自身意味を分かっていないのに使っているものが沢山あるんだなーと未熟さを痛感とともにまだまだ勉強しなければいけないことが沢山。
でも楽しいお勉強は飽きなくていいですよね。
僕は本を読んだり、何もしないで見てるだけだと覚えれないので、
実際にソースを下記ながら少しずつ切り替えていきたいなと思います。
まだまだわかないことだらけ。。。。(´;ω;`)
日本には沢山の素晴らしい開発者がいらっしゃいますし、そういった方々の情報提供は
未熟な僕にとって本当にありがたい。
精進致します。
当記事の参考・引用サイト:http://notnil-creative.com/blog/archives/1688
コンクリートファイブジャパン株式会社代表取締役 菱川拓郎 が運営するブログです。
お世話になりました。