verwendet werden sollen Ich habe @nacin „s Sie kennen Query gestern nicht und wurden in ein fragendes Kaninchenloch geschickt. Vor gestern habe ich (fälschlicherweise) query_posts()
für alle meine Abfrageanforderungen verwendet. Jetzt bin ich etwas weiser bei der Verwendung von WP_Query()
, habe aber immer noch einige Grauzonen.
Was ich sicher zu wissen glaube:
Wenn ich zusätzlich mache Schleifen an einer beliebigen Stelle auf einer Seite – in der Seitenleiste, in einer Fußzeile, in „verwandten Posts“ usw. – Ich möchte . Ich kann das wiederholt auf einer einzelnen Seite verwenden, ohne Schaden zu nehmen. (richtig?).
Was ich nicht sicher weiß
- Wann verwende ich @nacin „s
pre_get_posts
vs.WP_Query()
? Sollte ich jetzt für allespre_get_posts
verwenden? - 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 meinen eigeneWP_Query()
? Oder ändere ich die Ausgabe mitpre_get_posts
in meiner Datei functions.php?
tl; dr
Die tl; dr-Regeln Daraus möchte ich Folgendes ziehen:
- Verwenden Sie niemals
query_posts
mehr - Wenn Sie mehrere Abfragen auf einer Seite ausführen, verwenden Sie
WP_Query()
- Wenn Sie eine Schleife ändern, gehen Sie folgendermaßen vor __________________.
Vielen Dank für Ihre Weisheit
Terry
ps: Ich habe gesehen und gelesen: Wann sollten Sie WP_Query vs query_posts () vs get_posts () verwenden? Dadurch wird eine weitere Dimension hinzugefügt – get_posts
. Aber pre_get_posts
wird überhaupt nicht behandelt .
Kommentare
- Mögliches Duplikat von Wann sollten Sie WP_Query vs query_posts () vs get_posts ( )?
- @saltcod, jetzt ist es anders, WordPress hat sich weiterentwickelt, ich habe einige Kommentare im Vergleich zu der akzeptierten Antwort hier hinzugefügt
Antwort
Sie haben Recht zu sagen:
Verwenden Sie niemals
query_posts
pre_get_posts
pre_get_posts
ist ein Filter zum Ändern von beliebiger Abfrage. 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 überprüfen, ob is_admin()
gibt false zurück – obwohl dies möglicherweise redundant ist.). Die Hauptabfrage wird in Ihren Vorlagen wie folgt angezeigt:
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
. 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 beispielsweise verwendet werden soll, und alle an die URL übergebenen Argumente (z. B. Paginierung) werden alle in diese Instanz des WP_Query
-Objekts geleitet.
Für sekundäre Schleifen (z. B. in Seitenleisten oder Listen „verwandter Beiträge“) möchten Sie eine eigene separate Instanz des WP_Query
-Objekts erstellen. ZB
$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 $post
Variable, die den „aktuellen Beitrag“ identifiziert. Dies setzt im Wesentlichen die $post
zurück, auf der 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 nicht “ ta „Loop“, einfach 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
- Verwenden Sie
pre_get_posts
, um Ihre Hauptabfrage zu ändern. Verwenden Sie ein separatesWP_Query
-Objekt (Methode 2) für sekundäre Schleifen auf den Vorlagenseiten. - Wenn Sie die Abfrage der Hauptschleife ändern möchten, verwenden Sie
pre_get_posts
.
Kommentare
- Gibt es also ein Szenario, in dem man direkt zu get_posts () und nicht zu WP_Query wechselt?
li> @drtanz – ja. Angenommen, Sie benötigen ‚ keine Paginierung oder klebrige Beiträge oben – in diesen Fällen ist get_posts()
effizienter.
get_posts()
für die Hauptabfrage – es ist für sekundäre Abfragen. Antwort
Es gibt zwei verschiedene Kontexte für Schleifen:
- main Schleife, die auf der Grundlage einer URL-Anforderung erfolgt und vor dem Laden von Vorlagen verarbeitet wird
- sekundär
Schleifen, die auf andere Weise auftreten, aus Vorlagendateien oder auf andere Weise aufgerufen werden
Problem mit query_posts()
ist, dass es eine sekundäre Schleife ist, die versucht, die Hauptschleife zu sein und kläglich versagt. Vergessen Sie also, dass es existiert.
Zum Ändern der Hauptschleife
- verwenden Sie nicht
query_posts()
-
pre_get_posts
Filter mit$query->is_main_query()
check - Verwenden Sie alternativ den Filter
request
( etwas zu rau, so dass oben besser ist)
Um eine 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 erstere).
Zum Bereinigen
Verwenden Sie wp_reset_query()
Wenn Sie query_posts()
verwendet oder mit globalem $wp_query
direkt herumgespielt haben, müssen Sie dies fast nie tun.
Verwenden Sie wp_reset_postdata()
, wenn Sie the_post()
oder setup_postdata()
verwendet oder mit globalem und müssen den Anfangszustand postbezogener Dinge wiederherstellen.
Kommentare
- Selten bedeutet
wp_reset_postdata()
Answe r
Es gibt legitime Szenarien für die Verwendung von query_posts($query)
, zum Beispiel:
-
Sie möchten eine Liste von Posts oder benutzerdefinierten Posts vom Typ Post 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?
-
Es ist intuitiver für ein Administrator (Ihr Kunde?) – er kann die Seite auf den „Seiten“ sehen
-
Es ist besser, sie zu Menüs hinzuzufügen (ohne die Seite hätten sie “ um die URL direkt hinzuzufügen)
-
Wenn Sie zusätzlichen Inhalt (Text, Miniaturansicht oder benutzerdefinierten Metainhalt) in der Vorlage anzeigen möchten, können Sie ihn einfach über die URL abrufen Seite (und alles macht auch für den Kunden mehr Sinn). Wenn Sie eine Archivvorlage verwendet haben, müssen Sie entweder den zusätzlichen Inhalt fest codieren oder beispielsweise Themen- / Plugin-Optionen verwenden (was für den Kunden weniger intuitiv ist).
Hier „ein vereinfachter Beispielcode (der sich auf Ihrer Seitenvorlage befindet – 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 die Verwendung von query_posts()
auch hier vermeiden und WP_Query
stattdessen – 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 eine so nette kleine Funktion dafür zur Verfügung haben?
Kommentare
- Brian, danke dafür. Ich ‚ habe Probleme damit, pre_get_posts auf einer Seite genau in dem von Ihnen beschriebenen Szenario zum Laufen zu bringen: Der Client muss benutzerdefinierte Felder / Inhalte zu einer Archivseite hinzufügen, die sonst eine Archivseite wäre “ Seite “ muss erstellt werden; Der Client muss etwas sehen, das dem Navigationsmenü hinzugefügt werden kann, da das Hinzufügen eines benutzerdefinierten Links ihnen entgeht. usw. +1 von mir!
- Dies kann auch mit “ pre_get_posts “ erfolgen. Ich habe das getan, um eine “ statische Startseite “ zu haben, die meine benutzerdefinierten Beitragstypen in einer benutzerdefinierten Reihenfolge und mit einem benutzerdefinierten Filter auflistet. Diese Seite ist ebenfalls paginiert. Schauen Sie sich diese Frage an, um zu sehen, wie es funktioniert: wordpress.stackexchange.com / question / 30851 / … Kurz gesagt, es gibt immer noch kein legitimeres Szenario für die Verwendung von query_posts;)
- Weil “ Es sollte beachtet werden, dass die Verwendung dieser Option zum Ersetzen der Hauptabfrage auf einer Seite die Ladezeiten von Seiten verlängern kann, im schlimmsten Fall mehr als das Verdoppeln des Arbeitsaufwands oder mehr. Die Funktion ist zwar einfach zu bedienen, neigt aber auch später zu Verwirrung und Problemen. “ Quelle codex.wordpress.org/Function_Reference/ query_posts
- Diese Antwort ist falsch. Sie können in WP eine “ Seite “ mit derselben URL wie der benutzerdefinierte Beitragstyp erstellen. Wenn Ihr CPT Bananen ist, können Sie eine Seite mit dem Namen Bananen mit derselben URL erhalten. Dann würden Sie ‚ mit siteurl.com/bananas enden. Solange Sie archive-bananas.php in Ihrem Themenordner haben, wird die Vorlage verwendet und “ überschreibt “ diese Seite . Wie in einem der anderen Kommentare angegeben, erzeugt die Verwendung dieser “ -Methode “ die doppelte Arbeitslast für WP und sollte daher niemals verwendet werden.
Antwort
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%")"; }
Kommentare
- würde dieses Beispiel gerne sehen, aber wo Klausel auf benutzerdefinierten Meta ist.
Antwort
Nur um einige Verbesserungen 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:
Ist tatsächlich ein Aktions-Hook. Kein Filter, und er wirkt sich auf jede Abfrage aus.
Die Hauptabfrage wird in Ihren Vorlagen wie folgt angezeigt:
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 nur mit der Hauptabfrage verknüpft ist. 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.
Heutzutage ist WP_Query
eine Klasse, also haben wir eine Instanz einer Klasse.
Fazit: Zu der Zeit, als @StephenHarris schrieb, war dies höchstwahrscheinlich der Fall, aber im Laufe der Zeit wurden die Dinge in WordPress geändert.
Kommentare
- Technisch gesehen ‚ s Alle Filter unter der Haube, Aktionen sind nur ein einfacher Filter. Aber Sie haben hier Recht, es ist ‚ eine Aktion, die ein Argument als Referenz übergibt, was sich von einfacheren Aktionen unterscheidet.
-
get_posts
gibt ein Array von Post-Objekten zurück, keinWP_Query
-Objekt, sodass dies in der Tat immer noch korrekt ist. undWP_Query
war schon immer eine Klasse, eine Instanz eines class = -Objekts. - Danke, @Milo, aus irgendeinem Grund hatte ich ein stark vereinfachtes Modell im Kopf.