Kiedy używać WP_query (), query_posts () i pre_get_posts

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

  1. Kiedy czy używam @nacin „s pre_get_posts a WP_Query() ? Czy powinienem teraz używać pre_get_posts do wszystkiego?
  2. 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łasne WP_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ąć:

  1. Nigdy nie używaj query_posts już teraz
  2. W przypadku uruchamiania wielu zapytań na jednej stronie użyj WP_Query()
  3. 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

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

  1. Użyj pre_get_posts, aby zmienić główne zapytanie. Użyj oddzielnego obiektu WP_Query (metoda 2) dla dodatkowych pętli na stronach szablonów.
  2. 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:

  1. Chcesz wyświetlić listę postów lub postów o niestandardowym typie postów na stronie (używając szablonu strony)

  2. Chcesz, aby działała paginacja tych postów

Dlaczego teraz miałbyś chcieć wyświetlić go na stronie zamiast używać szablonu archiwum?

  1. Jest to bardziej intuicyjne dla administrator (Twój klient?) – widzi stronę w „Stronach”

  2. Lepiej jest dodać ją do menu (bez strony mieliby aby dodać adres URL bezpośrednio)

  3. 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. i WP_Query zawsze był klasą, instancją klasy = obiekt.
  • Dzięki, @Milo, poprawna z jakiegoś powodu. Miałem w głowie nadmiernie uproszczony model.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *