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ě
- Kdy používám @nacin „s
pre_get_posts
vs.WP_Query()
? Mám nyní používatpre_get_posts
pro všechno? - 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:
- Nikdy nepoužívejte
query_posts
už - Při spouštění více dotazů na jedné stránce použijte
WP_Query()
- 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
- Možný duplikát Kdy byste měli použít WP_Query vs query_posts () vs get_posts ( )?
- @saltcod, nyní je to jiné, WordPress se vyvinul, přidal jsem několik komentářů ve srovnání s přijatou odpovědí zde .
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
- 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). - 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:
-
Chcete na stránce zobrazit seznam příspěvků nebo příspěvků vlastního typu (pomocí šablony stránky)
-
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?
-
Je to intuitivnější pro správce (váš zákazník?) – může stránku zobrazit v části „Stránky“
-
Je lepší ji přidat do nabídek (bez stránky by ji měli přidat adresu URL přímo)
-
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ů, nikoliWP_Query
objektu, takže je to stále správné. aWP_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.