WP_query()、query_posts()、pre_get_postsを使用する場合

@nacin “s 昨日はクエリがわからないので、ちょっとしたクエリのうさぎの穴に送られました。昨日まで、私は(間違って) query_posts() をすべてのクエリのニーズに使用していました。今では、 WP_Query() の使用について少し賢明ですが、まだ灰色の領域がいくつかあります。

確かに知っていると思うこと:

追加のを作成している場合は、サイドバー、フッター、あらゆる種類の「関連する投稿」など、ページの任意の場所でループします。 。害を及ぼすことなく、1ページで繰り返し使用できます。 (正しい?)。

よくわからないこと

  1. いつ @nacin “s pre_get_posts aを使用しますか> vs. WP_Query() ?今、すべてに pre_get_posts を使用する必要がありますか?
  2. テンプレートページのループを変更したい場合(たとえば、分類法のアーカイブページを変更したい場合)、if have_posts : while have_posts : the_postの部分を削除して、自分の WP_Query() ?または、functions.phpファイルで pre_get_posts を使用して出力を変更しますか?

tl; dr

tl; drルールこれから引き出したいのは次のとおりです。

  1. query_posts は絶対に使用しないでくださいもう
  2. 1つのページで複数のクエリを実行する場合は、 WP_Query()
  3. を使用します

  4. ループを変更するときは、これを行ってください__________________。

知恵をありがとう

テリー

ps:私は見たり読んだりしました: WP_Queryとquery_posts()とget_posts()をいつ使用する必要がありますか?これにより別のディメンションが追加されます— get_posts 。ただし、 pre_get_posts はまったく処理しません。 。

コメント

回答

次のように言ってください:

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> 

質問への回答

  1. pre_get_postsを使用して、メインクエリを変更します。テンプレートページのセカンダリループには、別のWP_Queryオブジェクト(メソッド2)を使用します。
  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)を使用するための正当なシナリオがあります。例:

  1. 投稿のリストまたはカスタム投稿タイプの投稿を(ページテンプレートを使用して)ページに表示したい

  2. これらの投稿のページ付けを機能させたい

アーカイブテンプレートを使用する代わりに、なぜページに表示したいのですか?

  1. より直感的に管理者(あなたの顧客?)-「ページ」でページを見ることができます

  2. メニューに追加するのに適しています(ページがない場合は、 URLを直接追加するには)

  3. テンプレートに追加のコンテンツ(テキスト、投稿のサムネイル、またはカスタムメタコンテンツ)を表示する場合は、から簡単に取得できます。ページ(そしてそれはすべて顧客にとってもより理にかなっています)。アーカイブテンプレートを使用したかどうかを確認するには、追加のコンテンツをハードコーディングするか、たとえばテーマ/プラグインオプションを使用する必要があります(これにより、顧客にとって直感的ではなくなります)

ここに「簡略化されたサンプルコード(ページテンプレートにあります-例: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、なんらかの理由でモデルを単純化しすぎていました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です