it-swarm.com.de

Wann ist WP_query (), query_posts () und pre_get_posts zu verwenden?

Ich habe gestern @ nacinsSie kennen Query nicht gelesen und wurde ein bisschen von einem fragenden Kaninchenbau heruntergeschickt. Vor gestern habe ich (zu Unrecht) query_posts() für alle meine Abfrageanforderungen verwendet. Jetzt bin ich ein bisschen weiser im Umgang mit WP_Query() , habe aber immer noch einige graue Bereiche.

Was ich zu wissen glaube:

Wenn ich zusätzliche Schleifen auf einer Seite mache - in der Seitenleiste, in einer Fußzeile, in "verwandten Beiträgen" usw. - möchte ich WP_Query() verwenden. Ich kann das wiederholt auf einer einzelnen Seite ohne Schaden verwenden. (Recht?).

Was ich nicht sicher weiß

  1. Wann verwende ich @ nacinspre_get_posts vs. WP_Query() ? Soll ich pre_get_posts jetzt für alles verwenden?
  2. Wenn ich die Schleife in einer Vorlagenseite ändern möchte - sagen wir, ich möchte eine Taxonomie-Archivseite ändern - entferne ich den Teil if have_posts : while have_posts : the_post und schreibe mein eigenes WP_Query() ? Oder ändere ich die Ausgabe mit pre_get_posts in meiner functions.php Datei?

tl; dr

Die Regeln, die ich hieraus ziehen möchte, sind:

  1. Verwenden Sie niemals query_posts mehr
  2. Wenn Sie mehrere Abfragen auf einer Seite ausführen, verwenden Sie WP_Query()
  3. Gehen Sie beim Ändern einer Schleife folgendermaßen vor: __________________.

Danke für jede Weisheit

Terry

pS: Ich habe gesehen und gelesen: Wann sollten Sie WP_Query vs query_posts () vs get_posts () verwenden? Womit eine weitere Dimension hinzugefügt wird - get_posts . Aber es geht überhaupt nicht um pre_get_posts .

155
saltcod

Sie haben Recht zu sagen:

Nie mehr query_posts verwenden

pre_get_posts

pre_get_posts ist ein Filter zum Ändern von any query. Es wird am häufigsten 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 prüfen, ob 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 jemals das Bedürfnis haben, diese Schleife zu bearbeiten, verwenden Sie pre_get_posts. d. h., wenn Sie versucht sind, query_posts() zu verwenden, verwenden Sie stattdessen pre_get_posts.

WP_Query

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

Für sekundäre Schleifen (z. B. in Seitenleisten oder Listen mit verwandten Posts) möchten Sie eine eigene Instanz des Objekts WP_Query erstellen. 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();

Beachten Sie wp_reset_postdata(); - dies liegt daran, dass die sekundäre Schleife die globale $post-Variable überschreibt, die den 'aktuellen Beitrag' identifiziert. Dies setzt im Wesentlichen das auf den $post zurück, 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 keine 'Schleife', sondern nur ein Array von Post-Objekten.

<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>

Als Antwort auf Ihre Fragen

  1. Verwenden Sie pre_get_posts, um Ihre Hauptabfrage 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.
142
Stephen Harris

Es gibt zwei verschiedene Kontexte für Schleifen:

  • main - Schleife, die auf der Grundlage einer URL-Anforderung ausgeführt wird und verarbeitet wird, bevor Vorlagen geladen werden
  • sekundäre Schleifen, die auf andere Weise auftreten und aus Vorlagendateien oder auf andere Weise aufgerufen werden

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

Hauptschleife ändern

  • benutze nicht query_posts()
  • benutze pre_get_posts filter mit $query->is_main_query() check
  • alternativ request filter verwenden (etwas zu grob, also besser oben)

Sekundäre Schleife ausführen

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

Aufräumen

Verwenden Sie wp_reset_query(), wenn Sie query_posts() verwendet haben oder direkt mit globalem $wp_query in Konflikt geraten sind.

Verwenden Sie "wp_reset_postdata()", wenn Sie "the_post()" oder "setup_postdata()" verwendet haben oder mit dem globalen "$post" in Unordnung geraten sind und den anfänglichen Zustand von nachträglichen Dingen wiederherstellen müssen.

55
Rarst

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

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

  2. Sie möchten, dass die Paginierung dieser Posts funktioniert

Warum sollten Sie es nun auf einer Seite anzeigen, anstatt eine Archivvorlage zu verwenden?

  1. Für einen Administrator (Ihren Kunden?) Ist es intuitiver - er kann die Seite unter "Seiten" sehen.

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

  3. Wenn Sie zusätzlichen Inhalt (Text, Miniaturansicht des Beitrags oder benutzerdefinierten Metainhalt) in der Vorlage anzeigen möchten, können Sie ihn problemlos von der Seite abrufen (und dies 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-/Plug-in-Optionen verwenden (was die Benutzerfreundlichkeit für den Kunden beeinträchtigt).

Hier ist ein vereinfachter Beispielcode (der sich auf Ihrer Seitenvorlage befinden würde - z. B. 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...
}

Um ganz klar zu sein, könnten wir query_posts() auch hier vermeiden und stattdessen WP_Query verwenden - wie folgt:

// ...

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 Funktion zur Verfügung haben?

23
Lukas Pecinka

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%')"; 
}
8
T.Todua

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

pre_get_posts ist ein Filter zum Ändern von Abfragen. Es wird am häufigsten verwendet, um nur die 'Hauptabfrage' zu ändern:

Eigentlich ist das ein Aktionshaken. Kein Filter, und es wirkt sich auf jede Abfrage aus.

Die Hauptabfrage erscheint in Ihren Vorlagen als:

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

Eigentlich stimmt das auch nicht. Die Funktion have_posts iteriert das global $wp_query-Objekt, das nicht mit der Hauptabfrage only zusammenhängt. 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.

Tatsächlich ist WP_Query heutzutage eine Klasse, also haben wir eine Instanz einer Klasse.


Fazit: Zu der Zeit, als @StephenHarris schrieb, war dies höchstwahrscheinlich alles wahr, aber im Laufe der Zeit wurden die Dinge in WordPress geändert.

6
prosti