私は読みます @ nacin'sあなたはQuery - を知らない 昨日、ちょっと質問しているうさぎの穴を送りました。昨日の前に、私は(間違って) query_posts()
を私のすべての問い合わせの必要性のために使っていました。今、私は WP_Query()
を使うことについて少し賢いですが、それでもまだいくつかの灰色の領域があります。
私が確実に知っていると思うこと:
ページ上の任意の場所(サイドバー、フッター、任意の種類の「関連記事」など)で追加ループを作成している場合は、 WP_Query()
を使用します。私は何の問題もなく単一のページでそれを繰り返し使用することができます。 (右?)。
確実にわからないこと
pre_get_posts
と WP_Query()
の組み合わせはいつですか。今はすべてに pre_get_posts
を使うべきですか?if have_posts : while have_posts : the_post
部分を削除して自分の WP_Query()
を書くのですか?それとも、functions.phpファイルで pre_get_posts
を使用して出力を変更しますか?tl; dr
これから導きたいtl; drの規則は次のとおりです。
query_posts
もう使用しないWP_Query()
を使用してください。知恵をありがとう
テリー
pS:私は見て読んだことがあります: あなたはいつWP_Queryとquery_posts()とget_posts()を使うべきですか? これは別の次元を追加します - get_posts
。しかし、 pre_get_posts
はまったく扱いません。
あなたが言うのは正しいです:
query_posts
をもう使わない
pre_get_posts
は any queryを変更するためのフィルタです。最もよく使われるのは、「メインクエリー」だけを変更することです。
add_action('pre_get_posts','wpse50761_alter_query');
function wpse50761_alter_query($query){
if( $query->is_main_query() ){
//Do something to main query
}
}
(私はまたis_admin()
がfalseを返すことを確認します - これは冗長かもしれませんが)。主なクエリはテンプレートに次のように表示されます。
if( have_posts() ):
while( have_posts() ): the_post();
//The loop
endwhile;
endif;
このループを編集する必要があると感じたことがある場合はpre_get_posts
を使用してください。つまり、query_posts()
を使用したい場合は、代わりにpre_get_posts
を使用してください。
主なクエリは WP_Query object
の重要なインスタンスです。 WordPressはそれを使用してどのテンプレートを使用するかなどを決定します。たとえば、urlに渡される引数(たとえばページ付け)はすべてWP_Query
オブジェクトのそのインスタンスに送られます。
二次的なループ(サイドバーや「関連記事」リストなど)では、WP_Query
オブジェクトの独自のインスタンスを作成します。例えば。
$my_secondary_loop = new WP_Query(...);
if( $my_secondary_loop->have_posts() ):
while( $my_secondary_loop->have_posts() ): $my_secondary_loop->the_post();
//The secondary loop
endwhile;
endif;
wp_reset_postdata();
wp_reset_postdata();
に注意してください - これは二次ループが '現在の投稿'を識別するグローバル$post
変数をオーバーライドするためです。これは本質的に私達がいる$post
にリセットします。
これは基本的にWP_Query
オブジェクトの独立したインスタンスのラッパーです。これはpostオブジェクトの配列を返します。上記のループで使用されているメソッドはもう使用できません。これは「ループ」ではなく、単にポストオブジェクトの配列です。
<ul>
<?php
global $post;
$args = array( 'numberposts' => 5, 'offset'=> 1, 'category' => 1 );
$myposts = get_posts( $args );
foreach( $myposts as $post ) : setup_postdata($post); ?>
<li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php endforeach; wp_reset_postdata(); ?>
</ul>
pre_get_posts
を使用してください。テンプレートページの二次ループには、別のWP_Query
オブジェクト(方法2)を使用します。pre_get_posts
を使用してください。ループには2つの異なるコンテキストがあります。
query_posts()
の問題は、それが主ループになろうとしていて惨めに失敗するのが二次ループであるということです。したがって、それが存在することを忘れてください。
query_posts()
を使わない$query->is_main_query()
チェックでpre_get_posts
フィルターを使うrequest
フィルタを使用してください(少し粗すぎるので上記のほうが良いです)。ほぼ互換性のあるnew WP_Query
またはget_posts()
を使用してください(後者は前者の薄いラッパーです)。
wp_reset_query()
を使用した場合、またはグローバル$wp_query
と直接混同した場合は、query_posts()
を使用してください。そうする必要はほとんどありません。
wp_reset_postdata()
またはthe_post()
を使用しているか、グローバル$post
と混同していて、投稿関連のものの初期状態を復元する必要がある場合は、setup_postdata()
を使用してください。
query_posts($query)
を使用するための正当なシナリオがあります。例えば:
ページ上の投稿またはカスタム投稿タイプの投稿の一覧を表示する(ページテンプレートを使用)
これらの記事のページネーションを機能させたい
では、なぜアーカイブテンプレートを使用せずにページに表示したいのでしょうか。
管理者(あなたの顧客?)にとってより直感的です - 彼らは 'Pages'にページを見ることができます
それをメニューに追加するのがより良いです(ページなしで、彼らは直接URLを追加しなければならないでしょう)
追加のコンテンツ(テキスト、サムネイルの投稿、またはカスタムメタコンテンツ)をテンプレートに表示する場合は、ページから簡単に取得できます(そして顧客にとっても意味があります)。アーカイブテンプレートを使用したかどうかを確認するには、追加のコンテンツをハードコードするか、テーマやプラグインオプションなどを使用する必要があります(これにより、顧客にとって直観的にわかりにくくなります)。
これが簡単なサンプルコードです(これはあなたのページテンプレートにあります - 例えばpage-page-of-posts.php):
/**
* Template Name: Page of Posts
*/
while(have_posts()) { // original main loop - page content
the_post();
the_title(); // title of the page
the_content(); // content of the page
// etc...
}
// now we display list of our custom-post-type posts
// first obtain pagination parametres
$paged = 1;
if(get_query_var('paged')) {
$paged = get_query_var('paged');
} elseif(get_query_var('page')) {
$paged = get_query_var('page');
}
// query posts and replace the main query (page) with this one (so the pagination works)
query_posts(array('post_type' => 'my_post_type', 'post_status' => 'publish', 'paged' => $paged));
// pagination
next_posts_link();
previous_posts_link();
// loop
while(have_posts()) {
the_post();
the_title(); // your custom-post-type post's title
the_content(); // // your custom-post-type post's content
}
wp_reset_query(); // sets the main query (global $wp_query) to the original page query (it obtains it from global $wp_the_query variable) and resets the post data
// So, now we can display the page-related content again (if we wish so)
while(have_posts()) { // original main loop - page content
the_post();
the_title(); // title of the page
the_content(); // content of the page
// etc...
}
さて、完全に明確にするために、ここでもquery_posts()
を使わずに代わりにWP_Query
を使うことができます。
// ...
global $wp_query;
$wp_query = new WP_Query(array('your query vars here')); // sets the new custom query as a main query
// your custom-post-type loop here
wp_reset_query();
// ...
しかし、そのようなNiceという小さな機能が利用可能になったときに、なぜそうするのでしょうか。
Functions.phpからWordPressクエリを修正します。
//unfortunately, "IS_PAGE" condition doesn't work in pre_get_posts (it's WORDPRESS behaviour)
//so you can use `add_filter('posts_where', ....);` OR modify "PAGE" query directly into template file
add_action( 'pre_get_posts', 'myFunction' );
function myFunction($query) {
if ( ! is_admin() && $query->is_main_query() ) {
if ( $query->is_category ) {
$query->set( 'post_type', array( 'post', 'page', 'my_postType' ) );
add_filter( 'posts_where' , 'MyFilterFunction_1' ) && $GLOBALS['call_ok']=1;
}
}
}
function MyFilterFunction_1($where) {
return (empty($GLOBALS['call_ok']) || !($GLOBALS['call_ok']=false) ? $where : $where . " AND ({$GLOBALS['wpdb']->posts}.post_name NOT LIKE 'Journal%')";
}
WordPressは時間の経過とともに進化し、現在(5年後)いくつかの点で異なっているため、受け入れられた回答に対するいくつかの改善点を概説するだけです:
pre_get_posts
は、クエリを変更するためのフィルターです。最もよく使用されるのは、「メインクエリ」のみを変更する場合です。
実際にはアクションフックです。フィルタではなく、クエリに影響します。
メインクエリは、テンプレートに次のように表示されます。
if( have_posts() ):
while( have_posts() ): the_post();
//The loop
endwhile;
endif;
実際、これも事実ではありません。関数have_posts
は、メインクエリに関連しないonlyglobal $wp_query
オブジェクトを繰り返します。 global $wp_query;
は、セカンダリクエリでも変更できます。
function have_posts() {
global $wp_query;
return $wp_query->have_posts();
}
get_posts()
これは本質的に、WP_Queryオブジェクトの個別のインスタンスのラッパーです。
実際、最近ではWP_Query
はクラスであるため、クラスのインスタンスがあります。
結論:@StephenHarrisが書いた時点では、これはすべて真実である可能性が最も高かったが、時間が経つにつれてWordPressの内容は変更された。