Kdy použít WP_query (), query_posts () a pre_get_posts

Přečetl jsem @nacin „s Včera neznáte dotaz a byl odeslán trochu dotazovací králičí nory. Před včerejškem jsem (špatně) používal query_posts() pro všechny své potřeby dotazování. Teď jsem trochu moudřejší, když používám WP_Query() , ale stále mám nějaké šedé oblasti.

Co si myslím, že vím jistě:

Pokud udělám další smyčky kdekoli na stránce – v postranním panelu, v zápatí, jakýkoli druh „souvisejících příspěvků“ atd. – chci používat WP_Query() . Mohu to použít opakovaně na jedné stránce bez jakékoli újmy. (že jo?).

Co nevím jistě

  1. Kdy používám @nacin „s pre_get_posts vs. WP_Query() ? Mám nyní používat pre_get_posts pro všechno?
  2. Když chci upravit smyčku na stránce šablony – řekněme, že chci upravit stránku archivu taxonomie – odstraním část if have_posts : while have_posts : the_post a napíšu vlastní WP_Query() ? Nebo upravím výstup pomocí pre_get_posts v mém souboru functions.php?

tl; dr

Pravidla tl; dr Z toho bych chtěl čerpat:

  1. Nikdy nepoužívejte query_posts
  2. Při spouštění více dotazů na jedné stránce použijte WP_Query()
  3. Při úpravě smyčky proveďte toto __________________.

Děkuji za jakoukoli moudrost

Terry

ps: Viděl jsem a četl: Kdy byste měli použít WP_Query vs query_posts () vs get_posts ()? Který přidává další dimenzi – get_posts . Ale vůbec se nezabývá pre_get_posts .

Komentáře

Odpověď

Máte pravdu, když řeknete:

Už nikdy nepoužívejte query_posts

pre_get_posts

pre_get_posts je filtr pro změnu libovolného dotaz. Nejčastěji se používá ke změně pouze „hlavního dotazu“:

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

(zkontroloval bych také, že is_admin() vrací false – i když to může být nadbytečné.). Hlavní dotaz se ve vašich šablonách objeví jako:

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

Pokud někdy budete potřebovat tuto smyčku upravit – použijte pre_get_posts. tj. pokud vás láká použít query_posts() – použijte místo toho pre_get_posts.

WP_Query

Hlavní dotaz je důležitou instancí WP_Query object . WordPress ji používá například k rozhodnutí, kterou šablonu použít, a všechny argumenty předané do adresy URL (např. Stránkování) jsou všechny směrovány do této instance objektu WP_Query.

Pro sekundární smyčky (např. v postranních pruzích nebo v seznamech „souvisejících příspěvků“) budete chtít vytvořit vlastní samostatnou instanci objektu WP_Query. Například

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

Upozornění wp_reset_postdata(); – je to proto, že sekundární smyčka přepíše globální $post, která identifikuje „aktuální příspěvek“. Tím se v podstatě resetuje na $post, ve kterém se nacházíme.

get_posts ()

Jedná se v podstatě o obálku pro samostatnou instanci objektu WP_Query. Tím se vrací pole poštovních objektů. Metody použité ve výše uvedené smyčce vám již nejsou k dispozici. Toto není “ Ta „Loop“, simply a array of post object.

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

V reakci na vaše dotazy

  1. Pomocí pre_get_posts upravte svůj hlavní dotaz. Pro sekundární smyčky na stránkách šablon použijte samostatný WP_Query objekt (metoda 2).
  2. Chcete-li změnit dotaz hlavní smyčky, použijte pre_get_posts.

Komentáře

  • Existuje tedy nějaký scénář, kdy by se dalo jít rovnou na get_posts () a ne na WP_Query?
  • @drtanz – ano. Řekněme například, že ‚ nepotřebujete stránkování nebo lepkavé příspěvky nahoře – v těchto případech je get_posts() efektivnější.
  • Ale nechtěli byste ‚ přidat další dotaz, kde bychom mohli upravit pre_get_posts a upravit tak hlavní dotaz?
  • @drtanz – ne ‚ nepoužívá get_posts() pro hlavní dotaz – pro sekundární dotazy.
  • @StephenHarris Right =) Pokud používáte next_post () na objektu namísto použití the_post, nemusíte ‚ t krok na globální dotaz a nemusíte ‚ pamatovat poté použijte wp_reset_postdata.

Odpovědět

Pro smyčky existují dva různé kontexty:

  • hlavní smyčka, která se děje na základě požadavku na adresu URL a je zpracována před načtením šablon
  • sekundární

smyčky, které se vyskytují jakýmkoli jiným způsobem, volány ze souborů šablon nebo jinak

Problém s query_posts() je to, že je to sekundární smyčka, která se snaží být hlavní a nešťastně selže. Zapomeňte tedy, že existuje.

Chcete-li upravit hlavní smyčku

  • nepoužívejte query_posts()
  • použít pre_get_posts filtr s $query->is_main_query() kontrolou
  • střídavě použijte request filtr ( trochu příliš hrubý, takže výše je lepší)

Spuštění sekundární smyčky

Použijte new WP_Query nebo get_posts() které jsou do značné míry zaměnitelné (druhý je tenký obal pro první).

Vyčištění

Použijte wp_reset_query() pokud jste použili query_posts() nebo si spletli s globálním $wp_query přímo – takže téměř nikdy nebudete muset.

Použijte wp_reset_postdata() pokud jste použili the_post() nebo setup_postdata() nebo jste se dostali do globálního $post a je třeba obnovit počáteční stav věcí souvisejících s příspěvkem.

Komentáře

  • Rarst znamenalo wp_reset_postdata()

Answe r

Existují legitimní scénáře použití query_posts($query), například:

  1. Chcete na stránce zobrazit seznam příspěvků nebo příspěvků vlastního typu (pomocí šablony stránky)

  2. Chcete, aby stránkování těchto příspěvků fungovalo

Proč byste jej chtěli zobrazit na stránce namísto použití archivní šablony?

  1. Je to intuitivnější pro správce (váš zákazník?) – může stránku zobrazit v části „Stránky“

  2. Je lepší ji přidat do nabídek (bez stránky by ji měli přidat adresu URL přímo)

  3. Pokud chcete na šabloně zobrazit další obsah (text, miniaturu příspěvku nebo jakýkoli vlastní meta obsah), můžete jej snadno získat z stránka (a vše má větší smysl i pro zákazníka). Zjistíte-li, zda jste použili šablonu archivu, musíte buď dodatečně naprogramovat další obsah, nebo použít například možnosti motivu / pluginu (což pro zákazníka činí méně intuitivní)

Zde je zjednodušený ukázkový kód (který by byl ve vaší šabloně stránky – např. 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... }  

Abychom byli zcela jasní, mohli bychom se vyhnout použití query_posts() i zde a použít WP_Query místo toho – například:

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

Proč bychom to ale dělali, když máme k dispozici takovou pěknou malou funkci?

Komentáře

  • Briane, díky za to. ‚ Snažil jsem se přimět pre_get_posts pracovat na stránce PRESNĚ podle scénáře, který popisujete: klient musí přidat vlastní pole / obsah na to, co by jinak byla stránka archivu, takže “ stránku “ je třeba vytvořit; klient potřebuje vidět něco, co by měl přidat do navigačního menu, protože přidání vlastního odkazu jim uniká; atd. +1 ode mě!
  • To lze provést také pomocí “ pre_get_posts „. Udělal jsem to proto, abych měl “ statickou titulní stránku “ s výpisem mých vlastních typů příspěvků ve vlastním pořadí a s vlastním filtrem. Tato stránka je také stránkována. Podívejte se na tuto otázku a podívejte se, jak to funguje: wordpress.stackexchange.com / questions / 30851 / … Stručně řečeno, stále neexistuje legitimnější scénář pro použití query_posts;)
  • Protože “ Je třeba poznamenat, že jeho použití k nahrazení hlavního dotazu na stránce může prodloužit dobu načítání stránky, v nejhorších scénářích více než zdvojnásobení množství potřebné práce nebo více. I když je tato funkce snadno použitelná, je také náchylná k nejasnostem a problémům. “ Zdroj codex.wordpress.org/Function_Reference/ query_posts
  • TATO odpověď je nejrůznější. Ve službě WP můžete vytvořit “ stránku “ se stejnou adresou URL jako typ vlastního příspěvku. Například pokud je váš CPT Banány, můžete získat stránku s názvem Banány se stejnou adresou URL. Pak ‚ skončíte s siteurl.com/bananas. Pokud máte ve složce s motivy archive-bananas.php, použije místo toho šablonu a “ přepíše “ tuto stránku. . Jak je uvedeno v jednom z dalších komentářů, použitím této “ metody “ se vytvoří dvojnásobné pracovní vytížení pro WP, proto by se NEMĚLO nikdy používat.

Odpověď

Upravuji WordPress dotaz z 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%")"; } 

Komentáře

  • by měl zájem vidět tento příklad, ale kde je klauzule na vlastní meta.

Odpověď

Jen nastíním některá vylepšení přijaté odpovědi, protože WordPress se postupem času vyvíjel a některé věci se nyní liší (o pět let později) :

pre_get_posts je filtr pro změnu jakéhokoli dotazu. Nejčastěji se používá ke změně pouze „hlavního dotazu“:

Ve skutečnosti jde o akční háček. Nejde o filtr a ovlivní jakýkoli dotaz.

Hlavní dotaz se ve vašich šablonách objeví jako:

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

Ve skutečnosti to také není pravda. Funkce have_posts iteruje global $wp_query objekt, který nesouvisí pouze s hlavním dotazem. global $wp_query; lze změnit i pomocí sekundárních dotazů.

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

get_posts ()

Toto je v podstatě obal pro samostatnou instanci objektu WP_Query.

Ve skutečnosti je dnes WP_Query třída, takže máme instanci třídy.


Na závěr: @StephenHarris v té době s největší pravděpodobností psal, že to byla pravda, ale postupem času se věci ve WordPressu změnily.

Komentáře

  • Technicky je to ‚ s všechny filtry pod kapotou, akce jsou jen jednoduchým filtrem. Ale tady máte pravdu, je to ‚ akce, která předá argument odkazem, čímž se liší od jednodušších akcí.
  • get_posts vrací pole příspěvkových objektů, nikoli WP_Query objektu, takže je to stále správné. a WP_Query vždy byla třída, instance objektu class = object.
  • Díky, @Milo, z nějakého důvodu jsem měl v hlavě zjednodušený model.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *