Czytam @nacin „s Nie znasz zapytania wczoraj i zostałeś wysłany w dół jako pytająca królicza nora. Przed wczoraj (niesłusznie) używałem query_posts()
do wszystkich moich potrzeb związanych z zapytaniami. Teraz jestem trochę mądrzejszy, jeśli chodzi o używanie WP_Query()
, ale nadal mam pewne szare obszary.
Co myślę, że wiem na pewno:
Jeśli robię dodatkowe pętle w dowolnym miejscu strony – na pasku bocznym, w stopce, we wszelkiego rodzaju „powiązanych postach” itp. – chcę używać WP_Query()
. Mogę tego używać wielokrotnie na jednej stronie bez szkody. (dobrze?).
Czego nie wiem na pewno
- Kiedy czy używam @nacin „s
pre_get_posts
aWP_Query()
? Czy powinienem teraz używaćpre_get_posts
do wszystkiego? - Kiedy chcę zmodyfikować pętlę na stronie szablonu – powiedzmy, że chcę zmodyfikować stronę archiwum taksonomii – czy mam usunąć część
if have_posts : while have_posts : the_post
i napisać własneWP_Query()
? Czy mogę zmodyfikować dane wyjściowe za pomocąpre_get_posts
w moim pliku functions.php?
tl; dr
Zasady tl; dr Chciałbym z tego wyciągnąć:
- Nigdy nie używaj
query_posts
już teraz - W przypadku uruchamiania wielu zapytań na jednej stronie użyj
WP_Query()
- Podczas modyfikowania pętli zrób to __________________.
Dziękuję za wszelką mądrość
Terry
ps: Widziałem i czytałem: Kiedy należy używać WP_Query vs query_posts () vs get_posts ()? Co dodaje kolejny wymiar – get_posts
. Ale w ogóle nie radzi sobie z pre_get_posts
.
Komentarze
- Możliwy duplikat Kiedy należy używać WP_Query vs query_posts () vs get_posts ( )?
- @saltcod, teraz jest inaczej, WordPress ewoluował, dodałem kilka komentarzy w porównaniu z zaakceptowaną odpowiedzią tutaj .
Odpowiedź
Masz rację, mówiąc:
Nigdy więcej nie używaj
query_posts
pre_get_posts
pre_get_posts
to filtr służący do zmiany dowolnego zapytanie. Najczęściej jest używane do zmiany tylko „głównego zapytania”:
add_action("pre_get_posts","wpse50761_alter_query"); function wpse50761_alter_query($query){ if( $query->is_main_query() ){ //Do something to main query } }
(Chciałbym też sprawdzić, czy is_admin()
zwraca false – chociaż może to być zbędne). Główne zapytanie pojawia się w szablonach jako:
if( have_posts() ): while( have_posts() ): the_post(); //The loop endwhile; endif;
Jeśli kiedykolwiek poczujesz potrzebę edycji tej pętli – użyj pre_get_posts
. tj. jeśli masz ochotę użyć query_posts()
– użyj zamiast tego pre_get_posts
.
WP_Query
Główne zapytanie jest ważnym wystąpieniem WP_Query object
. WordPress używa go, aby na przykład zdecydować, którego szablonu użyć, a wszelkie argumenty przekazane do adresu URL (np. Paginacja) są kierowane do tej instancji obiektu WP_Query
.
W przypadku pętli pomocniczych (np. w paskach bocznych lub listach „powiązanych postów”) będziesz chciał utworzyć własną oddzielną instancję obiektu WP_Query
. Np.
$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();
Uwaga wp_reset_postdata();
– dzieje się tak, ponieważ wtórna pętla zastąpi globalne $post
, która identyfikuje „bieżący post”. To zasadniczo resetuje ją do $post
, na którym jesteśmy.
get_posts ()
Zasadniczo jest to opakowanie dla oddzielnej instancji obiektu WP_Query
. Zwraca tablicę obiektów wiadomości. Metody użyte w powyższej pętli nie są już dostępne. To nie jest ” ta „Pętla”, po prostu tablica obiektów wiadomości.
<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>
W odpowiedzi na Twoje pytania
- Użyj
pre_get_posts
, aby zmienić główne zapytanie. Użyj oddzielnego obiektuWP_Query
(metoda 2) dla dodatkowych pętli na stronach szablonów. - Jeśli chcesz zmienić zapytanie głównej pętli, użyj
pre_get_posts
.
Komentarze
- Czy jest więc jakiś scenariusz, w którym można by przejść bezpośrednio do get_posts () zamiast WP_Query?
- @drtanz – tak. Załóżmy na przykład, że nie ' nie potrzebujesz paginacji ani przyklejonych postów na górze – w tych przypadkach
get_posts()
jest bardziej wydajne. - Ale czy nie ' nie dodałoby dodatkowego zapytania, w którym moglibyśmy po prostu zmodyfikować pre_get_posts, aby zmodyfikować główne zapytanie?
- @drtanz – nie ' nie używaj
get_posts()
do głównego zapytania – to do dodatkowych zapytań. - @StephenHarris Right =) Jeśli używasz next_post () na obiekcie zamiast używać the_post, nie ' nie wkracza na globalne zapytanie i nie ' nie musisz pamiętać o następnie użyj wp_reset_postdata.
Odpowiedź
Istnieją dwa różne konteksty pętli:
- główna pętla, która dzieje się na podstawie żądania adresu URL i jest przetwarzana przed załadowaniem szablonów
- drugorzędne
pętle, które występują w jakikolwiek inny sposób, wywoływane z plików szablonów lub w inny sposób
Problem z query_posts()
jest to, że jest to pętla wtórna, która stara się być główną i kończy się niepowodzeniem. Zapomnij więc, że istnieje.
Aby zmodyfikować główną pętlę
- nie używaj
query_posts()
- użyj
pre_get_posts
filtruj z$query->is_main_query()
sprawdź - naprzemiennie użyj filtra
request
( trochę za szorstka, więc powyższe jest lepsze)
Aby uruchomić pętlę wtórną
Użyj new WP_Query
lub get_posts()
, które są prawie wymienne (drugie jest cienkim opakowaniem dla pierwszego).
Do czyszczenia
Użyj wp_reset_query()
jeśli użyłeś query_posts()
lub pomieszałeś z globalnym $wp_query
bezpośrednio – więc prawie nigdy nie będziesz musiał.
Użyj wp_reset_postdata()
, jeśli używasz the_post()
lub setup_postdata()
lub pomieszałeś z globalnym $post
i trzeba przywrócić początkowy stan rzeczy związanych z postem.
Komentarze
- Rarst oznaczał
wp_reset_postdata()
Answe r
Istnieją uzasadnione scenariusze użycia query_posts($query)
, na przykład:
-
Chcesz wyświetlić listę postów lub postów o niestandardowym typie postów na stronie (używając szablonu strony)
-
Chcesz, aby działała paginacja tych postów
Dlaczego teraz miałbyś chcieć wyświetlić go na stronie zamiast używać szablonu archiwum?
-
Jest to bardziej intuicyjne dla administrator (Twój klient?) – widzi stronę w „Stronach”
-
Lepiej jest dodać ją do menu (bez strony mieliby aby dodać adres URL bezpośrednio)
-
Jeśli chcesz wyświetlić w szablonie dodatkową zawartość (tekst, miniaturę posta lub dowolną niestandardową zawartość meta), możesz łatwo pobrać ją z strona (i to wszystko ma też większy sens dla klienta). Sprawdź, czy użyłeś szablonu archiwum, „musiałbyś albo zakodować na stałe dodatkową zawartość, albo użyć na przykład opcji motywu / wtyczki (co czyni ją mniej intuicyjną dla klienta).
Oto „uproszczony przykładowy kod (który byłby w szablonie Twojej strony – np. 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... }
Teraz, aby mieć całkowitą jasność, moglibyśmy uniknąć używania tutaj również query_posts()
i użyć WP_Query
zamiast tego – tak:
// ... 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(); // ...
Ale po co mielibyśmy to robić, skoro mamy do dyspozycji tak fajną, małą funkcję?
Komentarze
- Brian, dzięki za to. ' starałem się zmusić pre_get_posts do pracy na stronie w DOKŁADNIE opisanym przez Ciebie scenariuszu: klient musi dodać niestandardowe pola / zawartość do strony archiwum, więc ” strona ” musi zostać utworzona; klient musi zobaczyć coś do dodania do menu nawigacyjnego, ponieważ dodanie niestandardowego łącza powoduje ich uniknięcie; itd. +1 ode mnie!
- Można to również zrobić za pomocą ” pre_get_posts „. Zrobiłem to, aby mieć ” statyczną stronę główną ” z listą moich niestandardowych typów postów w niestandardowej kolejności i z niestandardowym filtrem. Ta strona jest również podzielona na strony. Sprawdź to pytanie, aby zobaczyć, jak to działa: wordpress.stackexchange.com / questions / 30851 / … Krótko mówiąc, nadal nie ma bardziej uzasadnionego scenariusza korzystania z query_posts;)
- Ponieważ ” Należy zauważyć, że użycie tej opcji do zastąpienia głównego zapytania na stronie może wydłużyć czas ładowania strony, w najgorszym przypadku ponad dwukrotnie lub więcej wymaganej pracy. Chociaż ta funkcja jest łatwa w użyciu, jest również podatna na zamieszanie i późniejsze problemy. ” Źródło codex.wordpress.org/Function_Reference/ query_posts
- Ta odpowiedź jest wszelkiego rodzaju błędna. Możesz utworzyć ” stronę ” w WP z tym samym adresem URL, co typ posta niestandardowego. Np. Jeśli twój CPT to Banany, możesz otrzymać stronę o nazwie Banany z tym samym adresem URL. Następnie ' d otrzymujesz siteurl.com/bananas. Jeśli masz archive-bananas.php w folderze z motywami, użyje on szablonu i ” zastąpi ” tę stronę . Jak stwierdzono w jednym z pozostałych komentarzy, użycie tej ” metody ” powoduje dwukrotne obciążenie WP, dlatego NIE powinno być nigdy używane.
Odpowiedź
Modyfikuję zapytanie WordPress 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%")"; }
Komentarze
- chciałbym zobaczyć ten przykład, ale gdzie klauzula znajduje się w niestandardowej meta.
Odpowiedź
Tylko po to, aby przedstawić kilka ulepszeń w zaakceptowanej odpowiedzi, ponieważ WordPress ewoluował w czasie i niektóre rzeczy są teraz inne (pięć lat później) :
pre_get_posts
to filtr służący do zmiany dowolnego zapytania. Najczęściej jest używany do zmiany tylko „głównego zapytania”:
Właściwie jest to hak akcji. Nie jest filtrem i wpłynie na każde zapytanie.
Główne zapytanie pojawia się w Twoich szablonach jako:
if( have_posts() ): while( have_posts() ): the_post(); //The loop endwhile; endif;
Właściwie to też nie jest prawdą. Funkcja have_posts
iteruje obiekt global $wp_query
, który nie jest powiązany tylko z głównym zapytaniem. global $wp_query;
można również zmienić za pomocą dodatkowych zapytań.
function have_posts() { global $wp_query; return $wp_query->have_posts(); }
get_posts ()
Zasadniczo jest to opakowanie dla oddzielnej instancji obiektu WP_Query.
Obecnie WP_Query
jest klasą, więc mamy instancję klasy.
Podsumowując: w tym czasie @StephenHarris pisał najprawdopodobniej wszystko to prawda, ale z biegiem czasu wiele rzeczy w WordPressie uległo zmianie.
Komentarze
- Technicznie rzecz biorąc, ' s wszystkie filtry pod maską, działania to tylko prosty filtr. Ale masz rację, to ' jest działaniem, które przekazuje argument przez odwołanie, co różni się tym od prostszych działań.
- zwraca tablicę obiektów wiadomości, a nie obiekt
WP_Query
, więc jest to rzeczywiście poprawne. iWP_Query
zawsze był klasą, instancją klasy = obiekt. - Dzięki, @Milo, poprawna z jakiegoś powodu. Miałem w głowie nadmiernie uproszczony model.