Dlaczego powinienem umieścić if (have_posts ()), czy while (have_posts ()) to za mało?

22

Mam pytanie dotyczące „pętli”.

<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<?php endwhile; else: ?>
<p><?php _e('Sorry, no posts matched your criteria.'); ?></p>
<?php endif; ?>

Kod pobrany ze strony Loop WordPress Codex .

Dlaczego powinienem umieścić ifczęść? Wygląda na to, że jeśli jest whilepętla, działa dobrze.

W jakim przypadku problem występuje, jeśli nie ma ifinstrukcji?

Edytować

Zaakceptowałem odpowiedź @ Chip. ale szczerze mówiąc, potrzebuję tylko ostatniej części.

Wiem teraz, co chciałem wiedzieć z mojego pytania.

ifinstrukcja jest dostępna tylko wtedy, gdy jest to konieczne, jeśli chcesz umieścić nagłówek lub stopkę, które powinny być zapisane tylko raz. jeśli nie używasz „opakowania”, wówczas ifinstrukcja nie jest konieczna.

żelazko i piasek
źródło
2
Głosowałem przed przeczytaniem treści, tytuł jest decydujący!
brasofilo
Doskonała (końcowa) edycja. Większość ludzi korzysta z if i jednocześnie bezpośrednio po sobie, nigdy nie używając innego. Prawdopodobnie z powodu kopiowania i wklejania.
Herbert Van-Vliet

Odpowiedzi:

29

Program ładujący szablony WordPress w wielu okolicznościach będzie zawierać odpowiedni plik szablonu kontekstowego, nawet jeśli zapytanie dla tego kontekstu nie zwróci żadnych postów. Na przykład:

  • Indeks głównych postów na blogu
  • Indeks archiwum kategorii (kategoria istnieje, ale nie ma wpisów)
  • Tag Archive Index (Tag istnieje, ale nie ma postów)
  • Indeks archiwum autorów (autor istnieje, ale nie ma postów)
  • Indeks wyników wyszukiwania

Dlatego w takich przypadkach odpowiedni plik szablonu zostanie załadowany, ale nie zostaną wydrukowane żadne posty, ponieważ zapytanie nie zwróci żadnych postów.

Przykłady weryfikacji koncepcji:

Dlatego w tych kontekstach przydatne jest, aby plik szablonu zawierał if ( have_posts() )warunek.

W innych kontekstach plik szablonu nigdy nie zostanie załadowany, jeśli zapytanie nie zwróci żadnych postów. Na przykład:

  • Pojedynczy post na blogu
  • Strona statyczna

W tych kontekstach if ( have_posts() )prawdopodobnie nie jest to konieczne.

Edytować

Rozumiem, że zapytanie jest wywoływane przez the_post (), prawda? A jeśli while (have_posts ()) istnieje, zapytanie nigdy nie występuje, jeśli nie ma posta.

Aby zrozumieć, co się dzieje, musisz spojrzeć na kolejność działań WordPress . Zaczynając od wp_loaded(i pomijając niektóre dla jasności):

  • wp_loaded
  • parse_request
  • send_headers
  • parse_query
  • pre_get_posts
  • wp
  • template_redirect
  • get_header
  • wp_head
  • the_post
  • wp_footer

Co się dzieje i w jakiej kolejności?

  • Wywoływane jest zapytanie:
    • parse_query
    • pre_get_posts
    • wp
  • Szablon jest wybrany:
    • template_redirect
  • Szablon jest ładowany / wysyłany. Szablon uruchamia następujące działania :
    • get_header
    • wp_head
    • the_post
    • dynamic_sidebar
    • get_footer
    • wp_footer

Tak więc, the_postzwolniony przez the_post(), dzieje się długo po przeanalizowaniu zapytania, pobraniu postów i załadowaniu szablonu.

Jestem bardzo wdzięczny za przekazanie wielu informacji, których nie znałem, ale nie o to prosiłem.

Och, ale wierzę, że dokładnie o to prosiłeś.

Prawdziwe pytanie brzmi: co to jest poprawny zwrot zapytania ? W przypadku kontekstów, takich jak indeks archiwum kategorii, zapytanie jest poprawne, a szablon kategorii jest ładowany, jeśli istnieje identyfikator kategorii, którego dotyczy zapytanie, nawet jeśli do tej kategorii nie przypisano żadnych postów .

Czemu? Ponieważ analizowane zapytanie to (IIRC) &cat={ID}- co jest poprawnym zapytaniem, nawet jeśli do tej kategorii nie przypisano żadnych postów , a zatem nie daje wyniku 404 podczas analizy.

W takim przypadku otrzymasz prawidłowe zapytanie i załadowany plik szablonu, ale nie ma wpisów . Tak więc if ( have_posts() ), jest w rzeczywistości istotne. Ponownie, oto przykład: kategoria istnieje, ale nie ma przypisanych wpisów. Plik szablonu kategorii jest ładowany z if ( have_posts() )powrotemfalse .

Nie dotyczy to zapytań zawierających zmienną wpisu ( &p={ID}), takich jak pojedyncze posty na blogu i strony statyczne, ponieważ post faktycznie nie istnieje, a po przeanalizowaniu zapytanie nie zwróci prawidłowego obiektu.

Edytuj 2

Jeśli słusznie rozumiem, czy w szablonie kategorii nie ma opcji if (have_posts ()), a kategoria nie ma postu, wówczas zwraca 404.php, nawet jeśli powinien to być zwrot kategorii-sample.php bez postu. Czy to prawda?

Nie. Pamiętaj: szablon jest wybierany o godzinie template_redirect. Jeśli więc zapytanie jest prawidłowe, ładowany jest odpowiedni plik szablonu. Jeśli zapytanie nie jest poprawne, szablon 404 jest ładowany.

Tak więc po załadowaniu szablonu - np. Szablonu kategorii - po wygenerowaniu pętli szablon się nie zmienia .

Spójrz ponownie na kolejność działań:

  • parse_query
  • pre_get_posts
  • wp
  • template_redirect- szablon jest wybierany i ładowany tutaj. Jest to szablon bez powrotu . Szablon nie może się zmienić po tym punkcie.
  • ...
  • the_post- tutaj ustawia się postdata, jako część wywołania pętli. Nazywa się to wewnątrz szablonu , a szablon nie zmienia się w zależności od dostępnych danych w obiekcie zapytania

Ostateczna edycja

I twierdzę, że chociaż sprawdzam istnienie postów, dlaczego powinienem dwukrotnie uruchomić ten sam test. To jest moje pytanie od pierwszego pytania, które tylko o to pytałem.

I w końcu rozumiem: przez cały czas twoje pytanie nie miało nic wspólnego z WordPress lub WordPress Loop . Pytasz o zawinięcie dowolnej dowolnej whilepętli PHP w ifwarunek, który sprawdza ten sam warunek.

To pytanie jest poza zakresem WPSE, ale krótko wyjaśnię:

ifUwarunkowane jest ocena binarna: to albo truealbo false, i to, co dzieje się wewnątrz tej warunkowym jest wykonywany raz .

whileUzależnione jest pętla : pozostaje prawdziwe dla pewnego okresu dyskretnych, oparte na pewnego rodzaju przeciwjony; a to, co dzieje się wewnątrz tego warunku, jest wykonywane kilka razy - raz dla każdej iteracji licznika.

Powiedzmy, że chcesz wypisać nieuporządkowaną listę rzeczy, jeśli lista rzeczy jest zapełniona. Jeśli użyjesz whilepętli i pominiesz ifopakowanie, twój znacznik wyglądałby następująco:

<ul>
<?php while ( list_of_things() ) : ?>
    <li><?php the_list_item(); ?></li>
<?php endwhile; ?>
</ul>

A jeśli list_of_things()byłby pusty, renderowany wynik byłby:

<ul>
</ul>

Który pozostawia niepotrzebne (i nieprawidłowe) znaczniki.

Ale jeśli dodasz ifopakowanie warunkowe, możesz to zrobić:

<?php if ( list_of_things() ) : ?>
    <ul>
    <?php while ( list_of_things() ) : ?>
        <li><?php the_list_item(); ?></li>
    <?php endwhile; ?>
    </ul>
<?php endif; ?>

A jeśli list_of_things()byłby pusty, w ogóle nie byłyby generowane żadne znaczniki.

To tylko jeden przykład. Istnieje wiele zastosowań tego ifopakowania warunkowego, a ifopakowanie warunkowe służy do zupełnie innych celów niż whilepętla.

Chip Bennett
źródło
2
W moich pojedynczych szablonach postów / stron od dłuższego czasu używam tylko the_post();dlatego, że również nie whilejest konieczne. +1 za kompletność informacji.
gmazzap
@GM Być może usunięcie tego if( have_posts() )oświadczenia ma sens (właśnie tego próbuję się dowiedzieć), ale nie używaj go tylko the_post()na pojedynczych stronach!
Sunyatasattva,
@ChipBennett Wszystko uznać, myślisz, że jest to bezpieczne, aby usunąć if( have_post() )stan przed pełnej pętli w kontekście single-*.phpi page-*.phpplików szablonu?
Sunyatasattva,
1
„Bezpieczny” naprawdę nie ma w tym kontekście definitywnego znaczenia.
Chip Bennett,
10

Naprawdę niemożliwe jest poprawienie odpowiedzi Chipa, ale po prostu przejdź do sedna:

Użyj tej ifczęści, jeśli chcesz, aby pojawiało się coś innego, gdy nie ma żadnych postów . Jest to szczególnie przydatne na przykład na stronie archiwum daty lub kategorii. Jeśli ktoś przejdzie do strony, na której nie ma żadnych postów, miło jest mieć taki komunikat, a nie tylko nic się nie wyświetla, ponieważ pętla nigdy nie zostanie wykonana.

if ( have_posts() ):
  // Yep, we have posts, so let's loop through them.
  while ( have_posts() ) : the_post();
  // do your loop
  endwhile;
else :
  // No, we don't have any posts, so maybe we display a nice message
  echo "<p class='no-posts'>" . __( "Sorry, there are no posts at this time." ) . "</p>";
endif;
Tom Auger
źródło
I to wszystko, co musisz wiedzieć.
Herbert Van-Vliet
0

Mogą istnieć pewne uwagi, które nie zostały dotychczas uwzględnione w odpowiedziach. Nie zaleca się pomijania instrukcji if.

Instrukcja if jest powszechnie używana do:

  • wyprowadza coś w rodzaju no posts foundwskazania, że ​​dana kategoria nie ma przypisanych artykułów.
  • aby zdecydować, czy otaczający HTML (jak ul) powinien być generowany przed i po artykułach.

Co się stanie, jeśli zostanie dodany nowy hak?

Innym możliwym problemem nieużywania instrukcji if jest to, że jeśli zespół wordpress kiedykolwiek zdecyduje się dodać nowy hak, który uruchamia się przy pierwszym $wp_query->have_posts()wywołaniu, uruchomi się w niewłaściwym czasie. A jeśli spowoduje to nieoczekiwane zachowanie, to twoja wina będzie polegać na nieprzestrzeganiu specyfikacji.

Inni deweloperzy oczekują określonej struktury dla pętli wordpress

Podejrzewam, że inni programiści oczekują całej pętli wordpress. Więc może to zły pomysł, aby szukali instrukcji if, której nie ma.

RMo
źródło
-1

Widzę to jako podstawowe pytanie teorii struktury kontroli. Zamknięty blok w pętli while nie jest wykonywany nawet raz, jeśli warunek (have_posts ()) za pierwszym razem oceni jako fałszywy.

Tak więc celem if ( have_posts() )pętli WordPress jest wykonanie funkcji have_posts () tylko raz, zanim warunek while zostanie oceniony. Jeśli have_posts()nie ma żadnych skutków ubocznych, to if ( have_posts() )jest całkowicie bezcelowe. Jeśli have_posts()ma skutki uboczne, możesz uprościć w następujący sposób:

<?php have_posts(); ?>
<?php while ( have_posts() ) : the_post(); ?>
<?php endwhile; else: ?>
<p><?php _e('Sorry, no posts matched your criteria.'); ?></p>
<?php endif; ?>
Schparky
źródło
3
Uproszczenie to jest nieprawidłowe PHP, masz instrukcję else, która nie ma dołączonej instrukcji if. W najlepszym razie trudno to odczytać
Tom J Nowell
1
ifJest tam ze względu na elsepo niej. Nie ma innego powodu. Jeśli nie ma żadnych postów, wyświetlenie miłej wiadomości „brak postów” jest lepsze niż nic.
Otto