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ß
pre_get_posts
vs. WP_Query()
? Soll ich pre_get_posts
jetzt für alles verwenden?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:
query_posts
mehrWP_Query()
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
.
Sie haben Recht zu sagen:
Nie mehr
query_posts
verwenden
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
.
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.
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>
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.pre_get_posts
.Es gibt zwei verschiedene Kontexte für Schleifen:
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.
query_posts()
pre_get_posts
filter mit $query->is_main_query()
checkrequest
filter verwenden (etwas zu grob, also besser oben)Verwenden Sie new WP_Query
oder get_posts()
, die ziemlich austauschbar sind (letzteres ist ein dünner Wrapper für erstere).
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.
Es gibt legitime Szenarien für die Verwendung von query_posts($query)
, zum Beispiel:
Sie möchten eine Liste von Posts oder benutzerdefinierten Posts auf einer Seite anzeigen (mithilfe einer Seitenvorlage).
Sie möchten, dass die Paginierung dieser Posts funktioniert
Warum sollten Sie es nun auf einer Seite anzeigen, anstatt eine Archivvorlage zu verwenden?
Für einen Administrator (Ihren Kunden?) Ist es intuitiver - er kann die Seite unter "Seiten" sehen.
Es ist besser, es zu Menüs hinzuzufügen (ohne die Seite müssten sie die URL direkt hinzufügen)
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?
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 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.