Hvornår skal jeg bruge WP_query (), query_posts () og pre_get_posts

Jeg læser @nacin “s Du kender ikke Forespørgsel i går og blev sendt ned lidt af et forespørgsel om kaninhul. Før i går brugte jeg (fejlagtigt) query_posts() til alle mine forespørgselsbehov. Nu er jeg “lidt klogere med at bruge WP_Query() , men har stadig nogle grå områder.

Hvad jeg tror jeg ved med sikkerhed:

Hvis jeg laver ekstra sløjfer hvor som helst på en side – i sidepanelet, i en sidefod, enhver form for “relaterede indlæg” osv. – Jeg vil bruge WP_Query() . Jeg kan bruge det gentagne gange på en enkelt side uden skade. (ret?).

Hvad jeg ikke ved med sikkerhed

  1. Hvornår bruger jeg @nacin “s pre_get_posts vs. WP_Query() ? Skal jeg bruge pre_get_posts til alt nu?
  2. Når jeg vil ændre sløjfen på en skabelonside – lad os sige, at jeg vil ændre en taksonomiarkivside – fjerner jeg if have_posts : while have_posts : the_post -delen og skriver min ejer WP_Query() ? Eller ændrer jeg output ved hjælp af pre_get_posts i min functions.php-fil?

tl; dr

Tl; dr-reglerne Jeg vil gerne trække fra dette er:

  1. Brug aldrig query_posts længere
  2. Når du kører flere forespørgsler på en enkelt side, skal du bruge WP_Query()
  3. Når du ændrer en løkke, skal du gøre dette __________________.

Tak for enhver visdom

Terry

ps: Jeg har set og læst: Hvornår skal du bruge WP_Query vs query_posts () vs get_posts ()? Hvilket tilføjer en anden dimension – get_posts . Men beskæftiger sig ikke med pre_get_posts overhovedet .

Kommentarer

Svar

Du har ret i at sige:

Brug aldrig query_posts længere

pre_get_posts

pre_get_posts er et filter til ændring af ethvert forespørgsel. Det bruges oftest kun til at ændre “hovedforespørgslen”:

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å kontrollere, at is_admin() returnerer falsk – selvom dette kan være overflødigt.). Hovedforespørgslen vises i dine skabeloner som:

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

Hvis du nogensinde har brug for at redigere denne loop – brug pre_get_posts. dvs. hvis du er fristet til at bruge query_posts() – brug pre_get_posts i stedet.

WP_Query

Hovedforespørgslen er en vigtig forekomst af en WP_Query object . WordPress bruger den til at beslutte, hvilken skabelon der skal bruges, for eksempel, og eventuelle argumenter, der sendes til urlen (f.eks. Pagination), kanaliseres alle til den forekomst af WP_Query -objektet.

For sekundære sløjfer (f.eks. i sidelinjer eller “relaterede indlæg” -lister) vil du “oprette din egen separate forekomst af 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(); 

Bemærk wp_reset_postdata(); – dette skyldes, at den sekundære sløjfe tilsidesætter den globale $post variabel, der identificerer det “aktuelle indlæg”. Dette nulstiller i det væsentlige det til $post vi er på.

get_posts ()

Dette er i det væsentlige en indpakning til en separat forekomst af et WP_Query -objekt. Dette returnerer en række postobjekter. Metoderne i løkken ovenfor er ikke længere tilgængelige for dig. Dette er ikke ” ta “Loop”, simpelthen en matrix med post-objekt.

<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å dine spørgsmål

  1. Brug pre_get_posts til at ændre din hovedforespørgsel. Brug et separat WP_Query -objekt (metode 2) til sekundære sløjfer i skabelonsiderne.
  2. Hvis du vil ændre forespørgslen i hovedsløjfen, skal du bruge pre_get_posts.

Kommentarer

  • Så er der noget scenarie, når man går direkte til get_posts () snarere end WP_Query?
  • @drtanz – ja. Sig for eksempel, at du ikke har brug for ‘, eller at klæbrige indlæg øverst – i disse tilfælde er get_posts() mere effektiv.
  • Men ville ‘ ikke tilføje en ekstra forespørgsel, hvor vi bare kunne ændre pre_get_posts for at ændre hovedforespørgslen?
  • @drtanz – du ville ikke ‘ bruger ikke get_posts() til hovedforespørgslen – det er til sekundære forespørgsler.
  • @StephenHarris Right =) Hvis du bruger next_post () på objektet i stedet for at bruge_post, du ‘ t trin på den globale forespørgsel og don ‘ t skal huske at brug wp_reset_postdata bagefter.

Svar

Der er to forskellige sammenhænge for sløjfer:

  • hoved loop, der sker baseret på URL-anmodning og behandles inden skabeloner indlæses
  • sekundær

sløjfer, der sker på nogen anden måde, kaldet fra skabelonfiler eller på anden måde

Problem med query_posts() er, at det er sekundær sløjfe, der prøver at være hovedløber og mislykkes. Så glem det eksisterer.

For at ændre hovedsløjfe

  • brug ikke query_posts()
  • brug pre_get_posts filter med $query->is_main_query() check
  • skiftevis brug request filter ( lidt for groft, så ovenfor er bedre)

At køre sekundær sløjfe

Brug new WP_Query eller get_posts() som er stort set udskiftelige (sidstnævnte er tynd indpakning til tidligere).

Oprydning

Brug wp_reset_query() hvis du brugte query_posts() eller rodet med global $wp_query direkte – så du behøver næsten aldrig at gøre det.

Brug wp_reset_postdata() hvis du brugte the_post() eller setup_postdata() eller rodet med global $post og har brug for at gendanne indledende tilstand for postrelaterede ting.

Kommentarer

  • Rarst betød wp_reset_postdata()

Answe r

Der er legitime scenarier for brug af query_posts($query), for eksempel:

  1. Du vil vise en liste over indlæg eller tilpassede indlæg af typen på en side (ved hjælp af en sideskabelon)

  2. Du ønsker at få paginering af disse indlæg til at fungere

Hvorfor vil du nu vise det på en side i stedet for at bruge en arkivskabelon?

  1. Det er mere intuitivt for en administrator (din kunde?) – de kan se siden i “Siderne”

  2. Det er bedre at føje den til menuerne (uden siden havde de for at tilføje url direkte)

  3. Hvis du vil vise yderligere indhold (tekst, miniaturebillede eller et hvilket som helst brugerdefineret metaindhold) på skabelonen, kan du nemt få det fra side (og det hele giver også mere mening for kunden). Se om du har brugt en arkivskabelon, skal du enten kode det ekstra indhold eller bruge f.eks. Tema- / plugin-indstillinger (hvilket gør det mindre intuitivt for kunden)

Her “er en forenklet eksempelkode (som ville være på din sideskabelon – f.eks. Side-side-af-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... }  

For at være helt klar kunne vi undgå at bruge query_posts() også her og bruge WP_Query i stedet – som sådan:

// ... 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 gøre det, når vi har en så dejlig lille funktion tilgængelig til det?

Kommentarer

  • Brian, tak for det. Jeg ‘ har kæmpet for at få pre_get_posts til at arbejde på en side i PRÆCIS det scenarie, du beskriver: klienten skal tilføje brugerdefinerede felter / indhold til det, der ellers ville være en arkivside, så en ” side ” skal oprettes; klienten skal se noget at tilføje til nav-menuen, da tilføjelse af et brugerdefineret link undgår dem; osv. +1 fra mig!
  • Det kan også gøres ved hjælp af ” pre_get_posts “. Jeg gjorde det for at have en ” statisk forside ” med en liste over mine tilpassede posttyper i en brugerdefineret rækkefølge og med et brugerdefineret filter. Denne side er også pagineret. Tjek dette spørgsmål for at se, hvordan det fungerer: wordpress.stackexchange.com / spørgsmål / 30851 / … Så kort sagt er der stadig ikke mere legitimt scenarie for brug af query_posts;)
  • Fordi ” Det skal bemærkes, at brug af dette til at erstatte hovedforespørgslen på en side kan øge sidens indlæsningstid, i værste fald mere end en fordobling af det nødvendige arbejde eller mere. Selvom den er let at bruge, er funktionen også tilbøjelig til forvirring og problemer senere. ” Kilde codex.wordpress.org/Function_Reference/ query_posts
  • Dette svar er alt for forkert. Du kan oprette en ” Side ” i WP med samme URL som den tilpassede posttype. F.eks. Hvis din CPT er bananer, kan du få en side med navnet Bananer med den samme URL. Derefter ender du ‘ med siteurl.com/bananas. Så længe du har arkiv-bananas.php i din temamappe, bruger den skabelonen og ” tilsidesætter ” den side i stedet . Som anført i en af de andre kommentarer skaber brug af denne ” -metode ” dobbelt arbejdsbelastningen for WP, og bør derfor aldrig bruges.

Svar

Jeg ændrer WordPress-forespørgsel fra funktioner.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

  • ville være interesseret i at se dette eksempel, men hvor klausul er om brugerdefineret meta.

Svar

Bare for at skitsere nogle forbedringer af det accepterede svar, da WordPress udviklede sig med tiden, og nogle ting er forskellige nu (fem år senere) :

pre_get_posts er et filter til ændring af enhver forespørgsel. Det bruges oftest kun til at ændre “hovedforespørgslen”:

Det er faktisk en actionkrog. Ikke et filter, og det vil påvirke enhver forespørgsel.

Hovedforespørgslen vises i dine skabeloner som:

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

Dette er faktisk heller ikke sandt. Funktionen have_posts gentager global $wp_query objekt, der ikke er relateret kun til hovedforespørgslen. global $wp_query; kan også ændres med de sekundære forespørgsler.

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

get_posts ()

Dette er i det væsentlige en indpakning til en separat forekomst af et WP_Query-objekt.

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


Afslutningsvis: På det tidspunkt skrev @StephenHarris højst sandsynligt, at alt dette var sandt, men over tid er ting i WordPress blevet ændret.

Kommentarer

  • Teknisk set ‘ s alle filtre under emhætten, handlinger er bare et simpelt filter. Men du har ret her, det ‘ er en handling, der sender et argument som reference, og det adskiller sig fra mere enkle handlinger.
  • get_posts returnerer en matrix med postobjekter, ikke et WP_Query -objekt, så det er faktisk stadig korrekt. og WP_Query har altid været en klasse, eksempel på et class = objekt.
  • Tak, @Milo, ret af en eller anden grund, at jeg havde en forenklet model i mit hoved.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *