Wanneer gebruik ik WP_query (), query_posts () en pre_get_posts

Ik las @nacin “s Je kent geen Query gisteren en werd een beetje een vragend konijnenhol gestuurd. Voor gisteren gebruikte ik (ten onrechte) query_posts() voor al mijn vragen. Nu “ben ik een beetje wijzer over het gebruik van WP_Query() , maar ik heb nog steeds enkele grijze gebieden.

Wat ik denk dat ik zeker weet:

Als ik extra loopt overal op een pagina – in de zijbalk, in een voettekst, elk soort “gerelateerde berichten”, enz. – Ik wil . Ik kan dat zonder enige schade herhaaldelijk op een enkele pagina gebruiken. (Rechtsaf?).

Wat ik niet zeker weet

  1. Wanneer gebruik ik @nacin “s pre_get_posts vs. WP_Query() ? Moet ik nu voor alles pre_get_posts gebruiken?
  2. Als ik de lus in een sjabloonpagina wil wijzigen – laten we zeggen dat ik een taxonomie-archiefpagina wil wijzigen – verwijder ik het if have_posts : while have_posts : the_post -gedeelte en schrijf ik mijn bezit WP_Query() ? Of pas ik de uitvoer aan met pre_get_posts in mijn functions.php-bestand?

tl; dr

De tl; dr-regels Ik “zou hieruit willen putten zijn:

  1. Gebruik nooit query_posts meer
  2. Wanneer u meerdere zoekopdrachten op één pagina uitvoert, gebruikt u WP_Query()
  3. Doe dit bij het aanpassen van een loop __________________.

Bedankt voor alle wijsheid

Terry

ps: ik heb gezien en gelezen: Wanneer moet u WP_Query vs query_posts () vs get_posts () gebruiken? Wat een andere dimensie toevoegt – get_posts . Maar heeft helemaal niets te maken met pre_get_posts .

Reacties

Antwoord

Je hebt gelijk als je zegt:

Gebruik query_posts nooit meer

pre_get_posts

pre_get_posts is een filter voor het wijzigen van elk zoekopdracht. Het wordt meestal gebruikt om alleen de “hoofdquery” te wijzigen:

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

(ik zou ook controleren of is_admin() geeft false terug – hoewel dit overbodig kan zijn.). De hoofdvraag verschijnt in uw sjablonen als:

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

Als u ooit de behoefte voelt om deze lus te bewerken, gebruik dan pre_get_posts. dwz als u in de verleiding komt om query_posts() te gebruiken – gebruik in plaats daarvan pre_get_posts.

WP_Query

De belangrijkste zoekopdracht is een belangrijke instantie van een WP_Query object . WordPress gebruikt het om te beslissen welke sjabloon moet worden gebruikt, en alle argumenten die aan de url worden doorgegeven (bijvoorbeeld paginering) worden allemaal naar die instantie van het WP_Query -object gestuurd.

Voor secundaire loops (bijv. in zijbalken, of “gerelateerde berichten” lijsten) wil je “je eigen aparte instantie van het WP_Query object maken. Bijv.

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

Opmerking wp_reset_postdata(); – dit komt omdat de secundaire lus de globale $post variabele die de “huidige post” identificeert. Dit reset deze in wezen naar de $post waar we op zijn.

get_posts ()

Dit is in wezen een wrapper voor een afzonderlijke instantie van een WP_Query -object. Dit retourneert een reeks post-objecten. De methoden die in de bovenstaande lus worden gebruikt, zijn niet langer beschikbaar voor jou. Dit isn ” ta “Loop”, gewoon een array van post-objecten.

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

In antwoord op uw vragen

  1. Gebruik pre_get_posts om uw hoofdzoekopdracht te wijzigen. Gebruik een apart WP_Query -object (methode 2) voor secundaire lussen in de sjabloonpaginas.
  2. Als je de zoekopdracht van de hoofdlus wilt wijzigen, gebruik dan pre_get_posts.

Reacties

  • Is er dus een scenario waarin men rechtstreeks naar get_posts () zou gaan in plaats van naar WP_Query?
  • @drtanz – ja. Stel dat u ‘ geen paginering of vastgezette berichten bovenaan nodig hebt – in deze gevallen is get_posts() efficiënter.
  • Maar zou ‘ niet een extra zoekopdracht toevoegen waar we pre_get_posts gewoon zouden kunnen wijzigen om de hoofdvraag te wijzigen?
  • @drtanz – je zou ‘ t gebruik get_posts() voor de hoofdzoekopdracht – het is voor secundaire zoekopdrachten.
  • @StephenHarris Right =) Als je next_post () op het object in plaats van the_post te gebruiken, ‘ stap niet op de globale zoekopdracht en ‘ niet te onthouden gebruik wp_reset_postdata daarna.

Answer

Er zijn twee verschillende contexten voor loops:

  • main loop die plaatsvindt op basis van URL-verzoek en wordt verwerkt voordat sjablonen worden geladen
  • secundair

loops die op een andere manier plaatsvinden, aangeroepen vanuit sjabloonbestanden of anderszins

Probleem met query_posts() is dat het de secundaire lus is die de hoofdlus probeert te zijn en jammerlijk faalt. Dus vergeet dat het bestaat.

Om de hoofdlus te wijzigen

  • gebruik query_posts()
  • gebruik pre_get_posts filter met $query->is_main_query() check
  • gebruik afwisselend request filter ( een beetje te ruw, dus hierboven is beter)

Om secundaire lus uit te voeren

Gebruik new WP_Query of get_posts() die vrijwel uitwisselbaar zijn (de laatste is een dunne wikkel voor de eerste).

Opruimen

Gebruik wp_reset_query() als je query_posts() hebt gebruikt of hebt geknoeid met global $wp_query rechtstreeks – dus je zult het bijna nooit nodig hebben.

Gebruik wp_reset_postdata() als je the_post() of setup_postdata() hebt gebruikt of hebt geknoeid met global $post en moeten de oorspronkelijke toestand van postgerelateerde zaken herstellen.

Opmerkingen

  • Betekende zelden wp_reset_postdata()

Antwoord r

Er zijn legitieme scenarios voor het gebruik van query_posts($query), bijvoorbeeld:

  1. U wilt een lijst met posts of aangepaste posts van het posttype op een pagina weergeven (met behulp van een paginasjabloon)

  2. U wilt ervoor zorgen dat de paginering van die posts werkt

Waarom zou je het nu op een pagina willen weergeven in plaats van een archiefsjabloon te gebruiken?

  1. Het is intuïtiever voor een beheerder (uw klant?) – ze kunnen de pagina zien in de “Paginas”.

  2. Het is beter om deze toe te voegen aan menus (zonder de pagina zouden ze om de URL rechtstreeks toe te voegen)

  3. Als u extra inhoud (tekst, miniatuur van een bericht of aangepaste meta-inhoud) op de sjabloon wilt weergeven, kunt u deze gemakkelijk ophalen uit de pagina (en het is allemaal ook logischer voor de klant). Kijk of je een archiefsjabloon hebt gebruikt, je “moet ofwel de aanvullende inhoud hardcoderen of bijvoorbeeld thema- / plug-in-opties gebruiken (waardoor het minder intuïtief is voor de klant).

Hier “is een vereenvoudigde voorbeeldcode (die op uw paginasjabloon zou staan – bijv. 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... }  

Voor alle duidelijkheid: we zouden query_posts() hier ook kunnen vermijden en WP_Query in plaats daarvan – zoals zo:

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

Maar waarom zouden we dat doen als we er zon leuke kleine functie voor beschikbaar hebben?

Reacties

  • Brian, bedankt daarvoor. Ik ‘ heb moeite gehad om pre_get_posts op een pagina te laten werken in PRECIES het scenario dat u beschrijft: de klant moet aangepaste velden / inhoud toevoegen aan wat anders een archiefpagina zou zijn, dus een ” pagina ” moet worden aangemaakt; de klant moet iets zien om aan het navigatiemenu toe te voegen, omdat het toevoegen van een aangepaste link eraan ontsnapt; etc. +1 van mij!
  • Dat kan ook worden gedaan met ” pre_get_posts “. Ik deed dat om een ” statische voorpagina ” te hebben met mijn aangepaste berichttypen in een aangepaste volgorde en met een aangepast filter. Deze pagina is ook gepagineerd. Bekijk deze vraag om te zien hoe het werkt: wordpress.stackexchange.com / questions / 30851 / … Kortom, er is nog steeds geen legitiem scenario meer voor het gebruik van query_posts;)
  • Omdat ” Opgemerkt moet worden dat als u dit gebruikt om de hoofdzoekopdracht op een pagina te vervangen, de laadtijd van de pagina kan toenemen, in het ergste geval meer dan een verdubbeling van de hoeveelheid werk die nodig is of meer. Hoewel deze functie gemakkelijk te gebruiken is, is hij later ook vatbaar voor verwarring en problemen. ” Bron codex.wordpress.org/Function_Reference/ query_posts
  • Dit antwoord is helemaal verkeerd. Je kunt een ” Pagina ” in WP maken met dezelfde URL als het aangepaste berichttype. Bijv. Als uw CPT Bananen is, kunt u een pagina met de naam Bananen krijgen met dezelfde URL. Dan zou je ‘ eindigen op siteurl.com/bananas. Zolang u archive-bananas.php in uw themamap heeft, zal het de sjabloon gebruiken en ” overschrijven ” die pagina . Zoals vermeld in een van de andere commentaren, zorgt het gebruik van deze ” methode ” voor tweemaal zoveel werklast voor WP, dus het mag nooit worden gebruikt.

Answer

Ik pas de WordPress-query aan vanuit 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%")"; } 

Reacties

  • zou graag dit voorbeeld willen zien, maar de clausule staat op een aangepaste meta.

Answer

Om enkele verbeteringen aan het geaccepteerde antwoord te schetsen sinds WordPress in de loop van de tijd is geëvolueerd en sommige dingen nu anders zijn (vijf jaar later) :

pre_get_posts is een filter om elke zoekopdracht te wijzigen. Het wordt meestal gebruikt om alleen de “hoofdquery” te wijzigen:

Eigenlijk is het een actiehaak. Geen filter, en het is van invloed op elke zoekopdracht.

De hoofdvraag wordt in uw sjablonen weergegeven als:

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

Eigenlijk is dit ook niet waar. De functie have_posts herhaalt het global $wp_query -object dat niet alleen gerelateerd is aan de hoofdquery. global $wp_query; kan ook worden gewijzigd met de secundaire zoekopdrachten.

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

get_posts ()

Dit is in wezen een wrapper voor een aparte instantie van een WP_Query-object.

In feite is WP_Query tegenwoordig een klasse, dus we hebben een instantie van een klasse.


Tot slot: op dat moment schreef @StephenHarris waarschijnlijk dat dit allemaal waar was, maar in de loop van de tijd zijn er dingen in WordPress veranderd.

Reacties

  • Technisch gezien is het ‘ s alle filters onder de motorkap, acties zijn slechts een simpele filter. Maar je hebt hier gelijk, het ‘ is een actie die een argument doorgeeft door middel van verwijzing, en dat is hoe het verschilt van meer eenvoudige acties.
  • get_posts retourneert een array met post-objecten, niet een WP_Query -object, dus dat is inderdaad nog steeds correct. en WP_Query is altijd een klasse geweest, instantie van een class = object.
  • Bedankt, @Milo, correct om een of andere reden dat ik een te eenvoudig model in mijn hoofd had.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *