問題描述

我有一個關於”the loop” 的問題。

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

程式碼取自 The Loop WordPress Codex page

為什麼要把 if 放在一起?好像是有 while 迴圈,工作正常。

在沒有 if 語句的情況下會發生什麼情況?

Edit

我接受了 @ Chip 的回答。但老實說,我只需要最後一部分。

我現在知道我想知道的問題。

if statement is only when necessary, if you want to put a header or footer that should be write only once. if you don’t use the “wrapper”, then if statement is not necessary.

最佳解決方案

WordPress 模板載入程式將在許多情況下包含適當的上下文模板檔案,即使該上下文的查詢不返回任何帖子。例如:

  • 主要部落格文章索引

  • 類別歸檔索引 (類別存在,但沒有帖子)

  • 標籤存檔索引 (標籤存在,但沒有帖子)

  • 作者存檔索引 (作者存在,但沒有帖子)

  • 搜尋結果索引

因此,在這些情況下,將載入適當的模板檔案,但不會輸出任何帖子,因為查詢不返回帖子。

Proof-of-concept 示例:

因此,在這些上下文中,模板檔案包含 if ( have_posts() )條件有用。

在其他上下文中,如果查詢不返回任何帖子,模板檔案將永遠不會被載入。例如:

  • 單個博文

  • 靜態頁面

在這些情況下,if ( have_posts() )可能是不必要的。

Edit

I understand the query is invoked by the_post(), right? And if while(have_posts()) exist, the query is never occurs if there is no post.

要了解發生了什麼,you have to look at the order of WordPress actions 。從 wp_loaded 開始 (為了清楚起見,省略一些):

  • wp_loaded

  • parse_request

  • send_headers

  • parse_query

  • pre_get_posts

  • wp

  • template_redirect

  • get_header

  • wp_head

  • the_post

  • wp_footer

那麼,發生了什麼,以什麼順序呢?

  • 查詢被呼叫:

    • parse_query

    • pre_get_posts

    • wp

  • 選擇模板:

    • template_redirect

  • 模板載入/輸出。模板觸發了以下操作:

    • get_header

    • wp_head

    • the_post

    • dynamic_sidebar

    • get_footer

    • wp_footer

因此,the_post()觸發的 the_post 會在查詢被解析後發生很長時間,並且將模板載入。

I’m very grateful that you give a lot of information that I didn’t know, but this is not what I asked.

哦,但我相信這正是你所問的。

真正的問題是:什麼是有效的查詢返回?對於諸如類別歸檔索引的上下文,查詢是有效的,並且如果查詢的類別 ID 存在,則載入類別模板,即使沒有分配給該類別的帖子。

為什麼?因為正在解析的查詢是 (IIRC)&cat={ID} – 即使沒有分配給該類別的帖子也是一個有效的查詢,因此在解析時不會導致 404 。

在這種情況下,您會收到一個有效的查詢,並載入了一個模板檔案,但沒有釋出任何帖子。因此,if ( have_posts() ),其實是相關的。再次,這裡有一個例子:category 存在,但沒有分配任何帖子。載入類別模板檔案,if ( have_posts() )返回 false

對於包含一個 post 變數 (&p={ID}) 的查詢 (例如單個部落格文章和靜態頁面),這並不適用,因為該帖子實際上不存在,並且在解析時,該查詢將不會返回一個有效的物件。

編輯 2

If I rightly understand if there is no if(have_posts()) in a category template and the category have no post, then it return 404.php, even though it should be return category-sample.php without post. Is that right?

不記得:模板是在 template_redirect 中選擇的。所以如果查詢是否有效,那麼載入相應的模板檔案。如果查詢無效,則載入 404 模板。

所以,一旦模板被載入 – 例如類別模板 – 一旦迴圈輸出,模板不會更改。

再看一下行動的順序:

  • parse_query

  • pre_get_posts

  • wp

  • template_redirect – 在這裡選擇並載入模板。這是不退貨的模板點。此後,模板無法更改。

  • the_post – postdata 設定在這裡,作為迴圈呼叫的一部分。這在模板中被呼叫,並且模板不會根據查詢物件中的可用資料進行更改

最終編輯

And I’am claiming that while checks existence of posts, why should I run the same test twice. That is my question from first point I’ve been asking only about that.

而且,我終於明白了:一直以來,你的問題與 WordPress 或 WordPress Loop 無關。您正在詢問將任意 PHP while 迴圈包含在 if 條件中,以檢查相同的條件。

這個問題超出了 WPSE 的範圍,但我將簡要解釋一下:

if 條件是一個二進位制評估:它是 truefalse,並且該條件內發生的內容將被執行一次。

while 條件是一個迴圈:基於某種計數器,它在一些離散時間段內保持為真; 並且該條件內發生的事情將被執行多次 – 每次計數器迭代一次。

所以,假設你想輸出一個無序列表的東西,如果事情的列表被填充。如果您使用 while 迴圈,並省略 if 包裝器,則您的標記如下所示:

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

如果 list_of_things()為空,則渲染的輸出為:

<ul>
</ul>

其中留下不必要的 (和無效的) 標記。

但是,如果新增 if 條件包裝器,您可以這樣做:

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

如果 list_of_things()為空,則不會輸出任何標記。

這只是一個例子。 if 條件包裝器有很多用途,if 條件包裝器與 while 迴圈完全不同。

次佳解決方案

改進晶片的答案真的是不可能的,只是為了減少追逐:

如果您想在沒有帖子時顯示不同的東西,請使用 if 部件。這在例如日期或類別歸檔頁面上特別有用。如果有人瀏覽到沒有帖子的頁面,很高興有一個訊息說出來,而不是根本沒有出現,因為迴圈永遠都不會被執行。

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;

參考文獻

注:本文內容整合自 google/baidu/bing 翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:gxnotes#qq.com(#替換為 @) 。