Når skal jeg bruke WP_query (), query_posts () og pre_get_posts

Jeg leser @nacin «s Du vet ikke spørring i går og ble sendt ned litt av et spørrende kaninhull. Før i går brukte jeg (feilaktig) query_posts() for alle spørsmålene mine. Nå er jeg litt klokere med å bruke WP_Query() , men har fortsatt noen gråsoner.

Det jeg tror jeg vet helt sikkert:

Hvis jeg gjør ekstra sløyfer hvor som helst på en side – i sidefeltet, i bunnteksten, alle slags «relaterte innlegg» osv. – Jeg vil bruke WP_Query() . Jeg kan bruke det gjentatte ganger på en enkelt side uten skade. (Ikke sant?).

Det jeg ikke vet sikkert

  1. Når bruker jeg @nacin «s pre_get_posts mot WP_Query() ? Skal jeg bruke pre_get_posts for alt nå?
  2. Når jeg vil endre sløyfen på en malside – la oss si at jeg vil endre en taksonomiarkivside – fjerner jeg if have_posts : while have_posts : the_post delen og skriver min eier WP_Query() ? Eller endrer jeg utdataene ved hjelp av pre_get_posts i funksjonene.php-filen min?

tl; dr

Tl; dr styrer Jeg vil trekke fra dette er:

  1. Bruk aldri query_posts lenger
  2. Når du kjører flere spørsmål på en enkelt side, bruker du WP_Query()
  3. Når du endrer en sløyfe, gjør du dette __________________.

Takk for enhver visdom

Terry

ps: Jeg har sett og lest: Når skal du bruke WP_Query vs query_posts () vs get_posts ()? Som legger til en annen dimensjon – get_posts . Men takler ikke pre_get_posts i det hele tatt .

Kommentarer

Svar

Du har rett i å si:

Bruk aldri query_posts lenger

pre_get_posts

pre_get_posts er et filter for å endre alle spørring. Det brukes oftest bare for å endre «hovedforespørselen»:

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

(Jeg vil også sjekke at is_admin() returnerer false – selv om dette kan være overflødig.). Hovedforespørselen vises i malene dine som:

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

Hvis du noen gang føler at du trenger å redigere denne sløyfen – bruk pre_get_posts. dvs. hvis du er fristet til å bruke query_posts() – bruk pre_get_posts i stedet.

WP_Query

Hovedspørsmålet er en viktig forekomst av en WP_Query object . WordPress bruker den til å bestemme hvilken mal som skal brukes, for eksempel, og eventuelle argumenter som sendes til url (f.eks. Paginering) kanaliseres alle til den forekomsten av WP_Query -objektet.

For sekundære sløyfer (f.eks. i sidelinjer eller «relaterte innlegg» -lister) vil du «lage din egen separate forekomst av WP_Query -objektet. F.eks.

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

Legg merke til wp_reset_postdata(); – dette er fordi den sekundære sløyfen vil overstyre den globale $post variabel som identifiserer «nåværende innlegg». Dette tilbakestiller i hovedsak det til $post vi er på.

get_posts ()

Dette er egentlig en innpakning for en separat forekomst av et WP_Query -objekt. Dette returnerer en rekke postobjekter. Metodene som brukes i løkken ovenfor er ikke lenger tilgjengelige for deg. Dette er ikke » ta «Loop», bare en rekke innleggsobjekter.

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

Som svar på spørsmålene dine

  1. Bruk pre_get_posts for å endre hovedforespørselen. Bruk et eget WP_Query -objekt (metode 2) for sekundære sløyfer på malsidene.
  2. Hvis du vil endre spørringen til hovedsløyfen, bruk pre_get_posts.

Kommentarer

  • Så er det noe scenario når man går rett til get_posts () i stedet for WP_Query?
  • @drtanz – ja. Si for eksempel at du ikke trenger ‘ ikke trenger paginering, eller klissete innlegg øverst – i disse tilfellene er get_posts() mer effektiv.
  • Men ville ikke ‘ t som legger til et ekstra spørsmål der vi bare kunne endre pre_get_posts for å endre hovedspørringen?
  • @drtanz – du ville ikke ‘ bruker ikke get_posts() for hovedforespørselen – det er for sekundære spørsmål.
  • @StephenHarris Right =) Hvis du bruker neste_post () på objektet i stedet for å bruke_posten, trenger du ikke ‘ t trinn på den globale spørringen og ikke trenger ‘ å huske å bruk wp_reset_postdata etterpå.

Svar

Det er to forskjellige sammenhenger for løkker:

  • hoved sløyfe som skjer basert på URL-forespørsel og behandles før maler lastes inn
  • sekundær

sløyfer som skjer på annen måte, kalt fra malfiler eller på annen måte

Problem med query_posts() er at det er sekundær sløyfe som prøver å være hoved en og mislykkes stort. Dermed glem at den eksisterer.

For å endre hovedsløyfen

  • ikke bruk query_posts()
  • bruk pre_get_posts filter med $query->is_main_query() sjekk
  • bruk alternativt request filter ( litt for grov, så over er bedre)

Å kjøre sekundær sløyfe

Bruk new WP_Query eller get_posts() som er ganske utskiftbare (sistnevnte er tynn innpakning for tidligere).

For å rydde opp

Bruk wp_reset_query() hvis du brukte query_posts() eller rotet med global $wp_query direkte – så du trenger nesten aldri å gjøre det.

Bruk wp_reset_postdata() hvis du brukte the_post() eller setup_postdata() eller rotet med global $post og trenger å gjenopprette innledende tilstand for postrelaterte ting.

Kommentarer

  • Rarst mente wp_reset_postdata()

Answe r

Det er legitime scenarier for bruk av query_posts($query), for eksempel:

  1. Du vil vise en liste over innlegg eller egendefinerte innlegg av typen på en side (ved hjelp av en sidemal)

  2. Du vil gjøre paginering av disse innleggene til å fungere

Hvorfor vil du vise det på en side i stedet for å bruke en arkivmal?

  1. Det er mer intuitivt for en administrator (kunden din?) – de kan se siden i «Sider»

  2. Det er bedre å legge den til i menyene (uten siden har de for å legge til nettadressen direkte)

  3. Hvis du vil vise ekstra innhold (tekst, miniatyrbilde eller noe tilpasset metainnhold) på malen, kan du enkelt få det fra siden (og det hele gir mer mening for kunden også). Se om du brukte en arkivmal, at du enten trenger å kode inn tilleggsinnholdet eller bruke for eksempel alternativ for tema / plugin (noe som gjør det mindre intuitivt for kunden)

Her «er en forenklet eksempelkode (som vil være på sidemalen din – f.eks. Side-side-av-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... }  

Nå, for å være helt klar, kan vi unngå å bruke query_posts() også her og bruke WP_Query i stedet – slik:

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

Men hvorfor skulle vi gjøre det når vi har en så fin liten funksjon tilgjengelig for det?

Kommentarer

  • Brian, takk for det. Jeg ‘ har slitt med å få pre_get_posts til å jobbe på en side i NØYAKTIG scenariet du beskriver: klienten må legge til egendefinerte felt / innhold til det som ellers ville være en arkivside, så en » side » må opprettes; klienten må se noe å legge til i nav-menyen, ettersom å legge til en tilpasset lenke unnslipper dem; osv. +1 fra meg!
  • Det kan også gjøres ved hjelp av » pre_get_posts «. Jeg gjorde det for å ha en » statisk forside » som oppførte mine egendefinerte innleggstyper i en tilpasset rekkefølge og med et tilpasset filter. Denne siden er også paginert. Ta en titt på dette spørsmålet for å se hvordan det fungerer: wordpress.stackexchange.no / spørsmål / 30851 / … Så kort fortalt er det fortsatt ikke noe mer legitimt scenario for bruk av query_posts;)
  • Fordi » Det bør bemerkes at bruk av dette for å erstatte hovedforespørselen på en side kan øke sidelastningstidene, i verste fall mer enn å doble arbeidsmengden som trengs eller mer. Selv om den er enkel å bruke, er funksjonen også utsatt for forvirring og problemer senere. » Kilde codex.wordpress.org/Function_Reference/ query_posts
  • Dette svaret er alle slags galt. Du kan opprette en » Side » i WP med samme URL som den egendefinerte innleggstypen. F.eks. Hvis CPT er bananer, kan du få en side som heter bananer med samme URL. Så ender du ‘ med siteurl.com/bananas. Så lenge du har arkiv-bananas.php i temamappen din, vil den bruke malen og » overstyre » den siden i stedet . Som det fremgår av en av de andre kommentarene, skaper bruk av denne » -metoden » dobbelt arbeidsmengden for WP, og bør derfor aldri brukes.

Svar

Jeg endrer WordPress-spørring fra funksjoner.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%")"; } 

Kommentarer

  • vil være interessert i å se dette eksemplet, men hvor klausul er om tilpasset meta.

Svar

Bare for å skissere noen forbedringer av det aksepterte svaret siden WordPress utviklet seg over tid og noen ting er forskjellige nå (fem år senere) :

pre_get_posts er et filter for å endre ethvert spørsmål. Det brukes oftest til å endre bare «hovedspørringen»:

Egentlig er det en actionkrok. Ikke et filter, og det vil påvirke alle spørsmål.

Hovedspørsmålet vises i malene dine som:

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

Egentlig er dette heller ikke sant. Funksjonen have_posts gjentar global $wp_query objektet som ikke er relatert bare til hovedspørsmålet. global $wp_query; kan også endres med de sekundære spørsmålene.

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

get_posts ()

Dette er egentlig en innpakning for en separat forekomst av et WP_Query-objekt.

I dag er faktisk WP_Query en klasse, så vi har en forekomst av en klasse.


For å konkludere: På det tidspunktet skrev @StephenHarris mest sannsynlig at alt dette var sant, men over tid har ting på WordPress blitt endret.

Kommentarer

  • Teknisk sett ‘ s alle filtre under panseret, handlinger er bare et enkelt filter. Men du har rett her, det ‘ er en handling som sender et argument med referanse, og det er hvordan det skiller seg fra enklere handlinger.
  • get_posts returnerer en matrise med postobjekter, ikke et WP_Query -objekt, så det er faktisk fortsatt riktig. og WP_Query har alltid vært en klasse, forekomst av et class = objekt.
  • Takk, @Milo, rett av en eller annen grunn at jeg hadde forenklet modell i hodet.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *