@nacin “s 昨日はクエリがわからないので、ちょっとしたクエリのうさぎの穴に送られました。昨日まで、私は(間違って) query_posts()
をすべてのクエリのニーズに使用していました。今では、 WP_Query()
の使用について少し賢明ですが、まだ灰色の領域がいくつかあります。
確かに知っていると思うこと:
追加のを作成している場合は、サイドバー、フッター、あらゆる種類の「関連する投稿」など、ページの任意の場所でループします。 。害を及ぼすことなく、1ページで繰り返し使用できます。 (正しい?)。
よくわからないこと
- いつ @nacin “s
pre_get_posts
aを使用しますか> vs.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
は絶対に使用しないでくださいもう - 1つのページで複数のクエリを実行する場合は、
WP_Query()
- ループを変更するときは、これを行ってください__________________。
を使用します
知恵をありがとう
テリー
ps:私は見たり読んだりしました: WP_Queryとquery_posts()とget_posts()をいつ使用する必要がありますか?これにより別のディメンションが追加されます— get_posts
。ただし、 pre_get_posts
はまったく処理しません。 。
コメント
- WP_Queryとquery_posts()とget_posts( )?
- @saltcod、今は違います、WordPressは進化しました、受け入れられた答えと比較していくつかのコメントを追加しましたここ 。
回答
次のように言ってください:
query_posts
はもう使用しないでください
pre_get_posts
pre_get_posts
は、任意のクエリ。これは、「メインクエリ」のみを変更するために最もよく使用されます:
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
メインクエリは、 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
にリセットされます。
get_posts()
これは基本的に、WP_Query
オブジェクトの個別のインスタンスのラッパーです。これにより、postオブジェクトの配列が返されます。上記のループで使用されたメソッドは使用できなくなりました。これは使用できません。」 ta「ループ」、単に投稿オブジェクトの配列。
<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)を使用します。 - メインループのクエリを変更する場合は、
。
コメント
- では、WP_Queryではなくget_posts()に直接アクセスするシナリオはありますか?
- @ drtanz-はい。たとえば、’ページ付けや上部のスティッキーポストは必要ないとします。このような場合、
get_posts()
の方が効率的です。 - しかし、’ pre_get_postsを変更してメインクエリを変更できるクエリを追加しませんか?
- @ drtanz-あなたは’メインクエリに
get_posts()
を使用しないでください-セカンダリクエリに使用します。 - @StephenHarris Right =)使用する場合the_postを使用する代わりに、オブジェクトでnext_post()を使用すると、’グローバルクエリを踏む必要がなく、’覚えておく必要がありません。後でwp_reset_postdataを使用します。
回答
ループには2つの異なるコンテキストがあります。
- main ループは、URLリクエストに基づいて発生し、テンプレートが読み込まれる前に処理されます
- セカンダリ
テンプレートファイルから呼び出されるなど、他の方法で発生するループ
query_posts()
の問題メインループになろうとして惨めに失敗するのはセカンダリループであるということです。したがって、存在することを忘れてください。
メインループを変更するには
-
query_posts()
- を使用しないでください
pre_get_posts
フィルターと$query->is_main_query()
チェック - 代わりに
request
フィルターを使用します(少し粗すぎるので上記の方が良いです)
セカンダリループを実行するには
new WP_Query
またははほとんど互換性があります(後者は前者の薄いラッパーです)。
クリーンアップするには
wp_reset_query()
を使用しますquery_posts()
を使用した場合、またはグローバル$wp_query
を直接使用した場合は、ほとんど必要ありません。
使用the_post()またはsetup_postdata()
を使用した場合、またはグローバル > そして事後関連のものの初期状態を復元する必要があります。
コメント
- ラーストは
wp_reset_postdata()
Answe r
query_posts($query)
を使用するための正当なシナリオがあります。例:
-
投稿のリストまたはカスタム投稿タイプの投稿を(ページテンプレートを使用して)ページに表示したい
-
これらの投稿のページ付けを機能させたい
アーカイブテンプレートを使用する代わりに、なぜページに表示したいのですか?
-
より直感的に管理者(あなたの顧客?)-「ページ」でページを見ることができます
-
メニューに追加するのに適しています(ページがない場合は、 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(); // ...
しかし、このような素敵な小さな関数を使用できるのに、なぜそうするのでしょうか?
コメント
- ブライアン、ありがとう。私は’あなたが説明したまさにそのシナリオでpre_get_postsをページ上で機能させるのに苦労してきました:クライアントはカスタムフィールド/コンテンツをアーカイブページになるものに追加する必要があるので、 “ページ”を作成する必要があります。カスタムリンクを追加するとエスケープされるため、クライアントはナビゲーションメニューに追加するものを確認する必要があります。など。私から+1!
- これは、” pre_get_posts “を使用して行うこともできます。 “静的フロントページ”に、カスタム投稿タイプをカスタムオーダーでカスタムフィルター付きで一覧表示するためにこれを行いました。このページもページ付けされています。この質問をチェックして、どのように機能するかを確認してください: wordpress.stackexchange。com / questions / 30851 / … つまり、query_postsを使用するための正当なシナリオはまだありません;)
- “これを使用してページのメインクエリを置き換えると、ページの読み込み時間が長くなる可能性があり、最悪の場合、必要な作業量が2倍以上になることに注意してください。この関数は使いやすいものですが、後で混乱や問題が発生する可能性もあります。”ソース codex.wordpress.org/Function_Reference/ query_posts
- この答えはあらゆる種類の間違いです。カスタム投稿タイプと同じURLを使用して、WPで”ページ”を作成できます。たとえば、CPTがBananasの場合、同じURLでBananasという名前のページを取得できます。次に、’はsiteurl.com/bananasになります。テーマフォルダにarchive-bananas.phpがある限り、テンプレートが使用され、代わりにそのページが”オーバーライドされます” 。他のコメントの1つで述べられているように、この”メソッド”を使用すると、WPのワークロードが2倍になるため、使用しないでください。
回答
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%")"; }
コメント
- この例を見たいと思いますが、where句はカスタムメタにあります。
回答
WordPressは時間の経過とともに進化し、現在(5年後)はいくつかの点が異なっているため、受け入れられた回答の改善点の概要を説明します。 :
pre_get_posts
は、クエリを変更するためのフィルターです。ほとんどの場合、「メインクエリ」のみを変更するために使用されます。
実際にはアクションフックです。フィルタではなく、すべてのクエリに影響します。
メインクエリはテンプレートに次のように表示されます:
if( have_posts() ): while( have_posts() ): the_post(); //The loop endwhile; endif;
実際、これも当てはまりません。関数have_posts
は、メインクエリにのみ関連付けられていないglobal $wp_query
オブジェクトを繰り返し処理します。 global $wp_query;
はセカンダリクエリでも変更できます。
function have_posts() { global $wp_query; return $wp_query->have_posts(); }
get_posts()
これは基本的に、WP_Queryオブジェクトの個別のインスタンスのラッパーです。
実際、現在WP_Query
はクラスであるため、クラスのインスタンスがあります。
結論:@StephenHarrisが書いた時点では、おそらくこれはすべて真実でしたが、時間の経過とともにWordPressの状況は変化しました。
コメント
- 技術的には、’ s内部のすべてのフィルター、アクションは単なるフィルターです。ただし、ここでは正しいです。’は、参照によって引数を渡すアクションです。これが、より単純なアクションとの違いです。
-
get_posts
は、WP_Query
オブジェクトではなく、投稿オブジェクトの配列を返すため、それでも正しいです。WP_Query
は常にクラスであり、class = objectのインスタンスです。 - ありがとう、@ Milo、なんらかの理由でモデルを単純化しすぎていました。