Wann sollten wir WP_query (), query_posts () und pre_get_posts verwenden?

Ich habe @ nacin’s gelesen Du weißt nicht, Abfrage gestern und wurde nach unten ein bisschen ein Frage Kaninchen Loch gesendet. query_posts() benutzte ich (fälschlicherweise) query_posts() für alle meine query_posts() . Jetzt bin ich ein bisschen weiser bei der Verwendung von WP_Query() , habe aber immer noch einige Graubereiche.

Was ich glaube, weiß ich sicher:

Wenn ich irgendwo auf einer Seite zusätzliche Schleifen mache – in der Seitenleiste, in einer Fußzeile, irgendeiner Art von “verwandten Posts” usw. – möchte ich WP_Query() . Ich kann das wiederholt auf einer einzigen Seite ohne Schaden verwenden. (Recht?).

Was ich nicht sicher weiß

  1. Wann verwende ich @nacins pre_get_posts vs. WP_Query() ? Soll ich jetzt pre_get_posts für alles verwenden?
  2. Wenn ich die Schleife in einer Template-Seite ändern möchte – sagen wir mal, ich möchte eine Taxonomie-Archivseite ändern – entferne ich die if have_posts : while have_posts : the_post part und schreibe meine eigene WP_Query() ? Oder pre_get_posts ich die Ausgabe mit pre_get_posts in meiner functions.php Datei?

tl; dr

Die Tl; dr-Regeln, die ich daraus ziehen möchte, sind:

  1. query_posts nie mehr query_posts
  2. Wenn Sie mehrere Abfragen auf einer einzelnen Seite WP_Query() , verwenden Sie WP_Query()
  3. Wenn Sie eine Schleife ändern, tun Sie dies __________________.

Danke für jede Weisheit

Terry

ps: Ich habe gesehen und gelesen: Wann sollten Sie WP_Query vs query_posts () vs get_posts () verwenden? Das fügt eine andere Dimension hinzu – get_posts . Aber behandelt pre_get_posts überhaupt nicht.

Solutions Collecting From Web of "Wann sollten wir WP_query (), query_posts () und pre_get_posts verwenden?"

Du hast recht zu sagen:

query_posts nie mehr query_posts

pre_get_posts

pre_get_posts ist ein Filter zum Ändern einer Abfrage. Es wird meistens verwendet, um nur die ‘Hauptabfrage’ zu ändern:

 add_action('pre_get_posts','wpse50761_alter_query'); function wpse50761_alter_query($query){ if( $query->is_main_query() ){ //Do something to main query } } 

(Ich würde auch überprüfen, dass is_admin() false zurückgibt – obwohl dies redundant sein kann.). Die Hauptabfrage erscheint in Ihren Vorlagen als:

 if( have_posts() ): while( have_posts() ): the_post(); //The loop endwhile; endif; 

Wenn Sie diese Schleife bearbeiten pre_get_posts verwenden Sie pre_get_posts . Wenn Sie versucht sind, query_posts() verwenden, verwenden pre_get_posts stattdessen pre_get_posts .

WP_Query

Die Hauptabfrage ist eine wichtige Instanz eines WP_Query object . WordPress verwendet es, um beispielsweise zu entscheiden, welche Vorlage zu verwenden ist, und alle in die URL übergebenen Argumente (z. B. Paginierung) werden alle in diese Instanz des WP_Query Objekts geleitet.

Bei sekundären Schleifen (z. B. in Seitenleisten oder Listen mit verwandten Posts) sollten Sie eine eigene separate Instanz des WP_Query Objekts WP_Query . Z.B

 $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(); 

Hinweis wp_reset_postdata(); – Dies liegt daran, dass die sekundäre Schleife die globale Variable $post überschreibt, die den ‘aktuellen Post’ identifiziert. Dies setzt das im Wesentlichen auf den $post , auf dem wir uns befinden.

get_posts ()

Dies ist im Wesentlichen ein Wrapper für eine separate Instanz eines WP_Query Objekts. Dies gibt ein Array von Post-Objekten zurück. Die in der obigen Schleife verwendeten Methoden stehen Ihnen nicht mehr zur Verfügung. Dies ist kein ‘Loop’, einfach ein Array von Post-Objekten.

 
    < ?php global $post; $args = array( 'numberposts' => 5, 'offset'=> 1, 'category' => 1 ); $myposts = get_posts( $args ); foreach( $myposts as $post ) : setup_postdata($post); ?>
  • < ?php the_title(); ?>
  • < ?php endforeach; wp_reset_postdata(); ?>

Als Antwort auf deine Fragen

  1. Verwenden Sie pre_get_posts , um Ihre pre_get_posts zu ändern. Verwenden Sie ein separates WP_Query Objekt (Methode 2) für sekundäre Schleifen in den Vorlagenseiten.
  2. Wenn Sie die Abfrage der Hauptschleife ändern möchten, verwenden Sie pre_get_posts .

Es gibt zwei verschiedene Kontexte für Schleifen:

  • Hauptschleife , die auf der Basis einer URL-Anfrage stattfindet und vor dem Laden der Vorlagen verarbeitet wird
  • Sekundärschleifen , die auf andere Art und Weise auftreten, die aus Vorlagendateien oder anderweitig aufgerufen werden

Problem mit query_posts() ist, dass es eine sekundäre Schleife ist, die versucht, die Hauptschleife zu sein und kläglich versagt. Also vergiss es.

Um Hauptschleife zu ändern

  • Verwenden query_posts() nicht query_posts()
  • Verwenden Sie den pre_get_posts Filter mit $query->is_main_query()
  • alternativ request (etwas zu grob, so ist oben besser)

Um die sekundäre Schleife auszuführen

Verwenden Sie new WP_Query oder get_posts() die ziemlich austauschbar sind (letzteres ist ein dünner Wrapper für Former).

Aufräumen

Verwenden Sie wp_reset_query() wenn Sie query_posts() oder direkt mit dem globalen $wp_query – Sie werden es also fast nie brauchen.

Verwenden Sie wp_reset_postdata() wenn Sie the_post() oder setup_postdata() oder mit dem globalen $post the_post() setup_postdata() und den Anfangszustand von Post-verwandten Dingen wiederherstellen müssen.

Es gibt legitime Szenarien für die Verwendung von query_posts($query) , zum Beispiel:

  1. Sie möchten eine Liste von Posts oder Posts mit benutzerdefinierten Posts auf einer Seite anzeigen (mithilfe einer Seitenvorlage).

  2. Sie möchten die Paginierung dieser Posts arbeiten lassen

Warum möchten Sie es jetzt auf einer Seite anzeigen, anstatt eine Archivvorlage zu verwenden?

  1. Es ist intuitiver für einen Administrator (Ihr Kunde?) – Sie können die Seite in den ‘Seiten’ sehen

  2. Es ist besser, sie zu Menüs hinzuzufügen (ohne die Seite müssten sie die URL direkt hinzufügen)

  3. Wenn Sie zusätzlichen Inhalt (Text, Post-Thumbnail oder einen benutzerdefinierten Metainhalt) in der Vorlage anzeigen möchten, können Sie ihn einfach von der Seite abrufen (und das ist auch für den Kunden sinnvoller). Wenn Sie eine Archivvorlage verwenden, müssen Sie entweder den zusätzlichen Inhalt fest codieren oder beispielsweise Themen- / Plugin-Optionen verwenden (was den Kunden weniger intuitiv macht).

Hier ist ein vereinfachter Beispielcode (der sich auf Ihrer Seitenvorlage befindet – zB 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... } 

Nun, um ganz klar zu sein, könnten wir auch hier die Verwendung von query_posts() vermeiden und stattdessen WP_Query verwenden – so:

 // ... 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(); // ... 

Aber warum sollten wir das tun, wenn wir so eine nette kleine function dafür haben?

Ich ändere die WordPress-Abfrage von functions.php:

 //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%')"; } 

Nur um einige Verbesserungen zu der akzeptierten Antwort zu skizzieren, seit sich WordPress im Laufe der Zeit entwickelt hat und einige Dinge jetzt anders sind (fünf Jahre später):

pre_get_posts ist ein Filter zum Ändern einer Abfrage. Es wird meistens verwendet, um nur die ‘Hauptabfrage’ zu ändern:

Eigentlich ist ein Aktionshaken. Kein Filter, und jede Abfrage wird beeinflusst.

Die Hauptabfrage erscheint in Ihren Vorlagen als:

 if( have_posts() ): while( have_posts() ): the_post(); //The loop endwhile; endif; 

Eigentlich ist das auch nicht wahr. Die function have_posts iteriert das global $wp_query Objekt, das sich nicht nur auf die Hauptabfrage bezieht. global $wp_query; kann auch mit den sekundären Abfragen geändert werden.

 function have_posts() { global $wp_query; return $wp_query->have_posts(); } 

get_posts ()

Dies ist im Wesentlichen ein Wrapper für eine separate Instanz eines WP_Query-Objekts.

Eigentlich ist WP_Query heutzutage eine class, also haben wir eine Instanz einer class.


Zum Schluss: Zu der Zeit, als @StephenHarris am wahrscheinlichsten schrieb, war das alles wahr, aber im Laufe der Zeit wurden die Dinge in WordPress verändert.