iT邦幫忙

2023 iThome 鐵人賽

DAY 21
0
WordPress

從 0 到 100:WordPress 開發者的實戰手冊系列 第 21

Day 21 - 利用 WP_Query 類別來自定內容查詢

  • 分享至 

  • xImage
  •  

在昨天的介紹的客製化網路路由一文提到,當網站伺服器收到請求,將此請求傳遞給 WordPress 解析完網址之後,會將生成 SQL 查詢語句,向 MySQL 資料庫查詢,接著取得資料後並生成內容輸出到網頁上。

生成內容流程圖
圖:生成內容流程圖

而今天要介紹的主角就是 WP_Query 類別,它 WordPress 核心中,負責生成 SQL 查詢語句的組件。

WP_Query 實例化過程
圖:WP_Query 實例化過程

它的實例化是在 wp-settings.php 檔案中,大約 516 行位置,並將此實例放在全域變數 $wp_the_query$wp_query 中。

以主要鉤點的生命週期來說,位於 sanitize_comment_cookiessetup_theme 之間。因此我們除了可以在佈景主題中直接使用 $wp_query 這個全域變數,在 setup_theme 之後的鉤點也可以使用。

使用時機

適合使用 WP_Query 的情境有兩種。

(1) 判斷請求頁面

要找出 WordPress目前正在處理的是哪一種請求,非常簡單,因為 WP_Query 類別中的 $is_ 屬性就是設計來存放這個資訊的,並在這裡使用條件標籤來互動。對外掛的開發者來說非常有用。

屬性

以下是部分屬性的例子:

  • $is_single:如果當前請求是查看單一文章頁面,此屬性為 true。
  • $is_page:如果當前是一個靜態頁面的請求,此屬性為 true。
  • $is_archive:如果當前請求是一個彙整頁面,例如分類、標籤、作者等存檔頁面,此屬性為 true。

條件標籤函式

條件標籤指的是 WordPress 提供的一套函式,這些函數可以用來檢查當前請求的各種條件,並基於這些條件執行不同的程式邏輯。條件標籤和 WP_Query 實例的 $is_ 屬性直接相關,並提供了一個更簡潔、更方便的方式來進行檢查。

以下是部分條件標籤函式的例子:

  • is_single():檢查當前是否為單一文章頁面。
  • is_page():檢查當前是否為一個靜態頁面。
  • is_archive():檢查當前是否為一個彙整頁面。

(2) The Loop (迴圈)

The Loop 用在佈景主題的範本檔案中,WP_Query 提供了許多的方法來完成 The Loop 內的常見功能,例如:

if ( $the_query->have_posts() ) {
    while ( $the_query->have_posts() ) {
        $the_query->the_post();
        // 在這之後使用內容輸出的相關函式
    }
}

先使用 have_posts 方法來判斷是否有文章資料,如果有,就開始一個 while 迴圈,同樣使用 have_posts 作為條件,當所有文章在迴圈中被處理過(即指針移動到了最後一個文章之後的位置), have_posts 會返回 false,結束 while 迴圈。

在每次迴圈中,呼叫 the_post 方法,它會設定全域變數 $post 讓其它依賴這個全域變數的函式可以使用。

WP_Query

參數

建構子的參位為陣列,根據查詢種類的不同有不一樣的條件,按此查詢

屬性

通用類

名稱 說明
$query 傳遞給 $wp_query 物件的查詢字符串。
$query_vars 包含解析的 $query 的關聯陣列,查詢變數及其相對應的值的陣列。
$queried_object 如果請求是分類、作者或頁面,此屬性保存其相關資訊。
$queried_object_id 如果請求是分類、作者或頁面,此屬性保存相應的 ID。
$posts 從資料庫取得的文章。
$post_count 正在顯示的文章數量。
$found_posts 符合當前查詢參數的文章總數。
$max_num_pages 總頁數。 是 $found_posts / $posts_per_page 的結果。
$current_post (在 The Loop 期間可用) 目前正在顯示的文章的索引。
$post (在 The Loop 期間可用) 目前正在顯示的文章。

可直接使用公開的屬性,例如 $queries = $wp_query->query_vars

狀態類

名稱 說明
$is_single 是否是單一文章的請求。
$is_page 是否是頁面的請求。
$is_archive 是否是任何類型的存檔頁面的請求。
$is_preview 是否是文章預覽的請求。
$is_date 是否是日期存檔的請求。
$is_year 是否是年存檔的請求。
$is_month 是否是月存檔的請求。
$is_time 是否是時間存檔的請求。
$is_author 是否是作者存檔的請求。
$is_category 是否是分類存檔的請求。
$is_tag 是否是標籤存檔的請求。
$is_tax 是否是自訂分類法存檔的請求。
$is_search 是否是搜索結果的請求。
$is_feed 是否是訂閱源的請求。
$is_comment_feed 是否是評論訂閱源的請求。
$is_trackback 是否是跟踪回溯的請求。
$is_home 是否是首頁的請求。
$is_404 是否是404錯誤頁面的請求。
$is_comments_popup 是否是評論彈出窗口的請求。
$is_admin 是否是管理區的請求。
$is_attachment 是否是附件頁面的請求。
$is_singular 是否是單一文章、頁面或附件的請求。
$is_robots 是否是針對 robots.txt 檔案的請求。
$is_posts_page 是否是文章列表頁面的請求。
$is_paged 是否是分頁的請求。

狀態類的屬性對應了狀態標籤函式,例如 $is_single 對應到 is_single()

方法

通用方法

連結 說明
fill_query_vars 填充不存在於參數內的查詢變數。
generate_cache_key 產生快取鍵。
generate_postdata 產生文章資料。
get 檢索查詢變數的值。
get_posts 根據查詢變數檢索一系列的文章。
get_queried_object 檢索當前查詢的對象。
get_queried_object_id 檢索當前查詢對象的 ID。
get_search_stopwords 檢索解析搜尋詞語時使用的停用詞。
have_comments 判斷是否還有更多的迴響可用。
have_posts 判斷在迴圈中是否還有更多的文章可用。
init 初始化物件屬性並設定預設值。
init_query_flags 重置查詢標誌為 false
next_comment 迭代當前迴響索引並返回 WP_Comment 對象。
next_post 設定下一篇文章並迭代當前文章索引。
parse_order 解析 order 查詢變量並根據需要將其轉換為 ASCDESC
parse_orderby 將給定的 orderby 別名(如果允許的話)轉換為正確前綴的值。
parse_query 解析查詢字串並設定查詢類型布林值。
parse_query_vars 重新解析查詢變量。
parse_search 根據傳遞的搜尋字詞生成 WHERE 子句的 SQL。
parse_search_order 根據傳遞的搜尋全域生成 ORDER BY 條件的 SQL。
parse_search_terms 檢查字詞是否適合搜尋。
parse_tax_query 解析各種與分類相關的查詢變量。
query 通過解析查詢字串來設定 WordPress 查詢。
reset_postdata 在迴圈過一個嵌套查詢後,此函數將 $post 全域變數恢復為此查詢中的當前文章。
rewind_comments 倒回迴響,重置迴響索引和迴響到第一個指針。
rewind_posts 倒回文章並重置文章索引指針。
set 設定查詢變數的值。
set_404 設置404 屬性並保存查詢是否為 RSS Feed。
set_found_posts 為當前查詢設置找到的文章數量和頁面數(如果使用了限制子句)。
setup_postdata 設置全域文章資料。
the_comment 設置當前迴響。
the_post 設置當前文章。

狀態標籤方法

連結 說明
is_404 判斷查詢是否為404(無結果)。
is_archive 判斷查詢是否為現有的彙整頁面。
is_attachment 判斷查詢是否為現有的附件頁面。
is_author 判斷查詢是否為現有的作者彙整頁面。
is_category 判斷查詢是否為現有的分類彙整頁面。
is_comment_feed 判斷查詢是否為迴響訂閱。
is_date 判斷查詢是否為現有的日期彙整。
is_day 判斷查詢是否為現有的日彙整。
is_embed 判斷查詢是否為嵌入的文章。
is_favicon 判斷查詢是否為 favicon.ico 檔案。
is_feed 判斷查詢是否為訂閱。
is_front_page 判斷查詢是否為網站的首頁。
is_home 判斷查詢是否為部落格首頁。
is_main_query 判斷查詢是否為主查詢。
is_month 判斷查詢是否為現有的月份彙整。
is_page 判斷查詢是否為現有的單一頁面。
is_paged 判斷查詢是否為分頁結果且不是第一頁。
is_post_type_archive 判斷查詢是否為現有的文章類型彙整頁面。
is_preview 判斷查詢是否為文章或頁面預覽。
is_privacy_policy 判斷查詢是否為隱私政策頁面。
is_robots 判斷查詢是否為 robots.txt 檔案。
is_search 判斷查詢是否為搜尋。
is_single 判斷查詢是否為現有的單一文章。
is_singular 判斷查詢是否為現有的任何文章類型的單一文章(文章、附件、頁面、自定文章類型)。
is_tag 判斷查詢是否為現有的標籤彙整頁面。
is_tax 判斷查詢是否為現有的自定義分類彙整頁面。
is_time 判斷查詢是否為特定時間。
is_trackback 判斷查詢是否為 trackback 端點呼叫。
is_year 判斷查詢是否為現有的年份彙整。

WP_Query 類別中的這些方法又被包裝為全域的函式方便呼叫。

使用範例

$args = array(
    'post_type' => 'post',
    'posts_per_page' => 5
);
$the_query = new WP_Query( $args );

這段簡短的程式碼,正是 WP_Query 類別的基本應用。$args 為查詢的條件。以這個例子來說,文章類型為 post,每頁筆數為 5。以此條件實例化後的 $the_query 即可在佈景主題中使用。

鐵人賽相關文章程式範例
圖:鐵人賽相關文章程式範例

比較複雜一點的應用,例如要在文章頁面底下加上一個「鐵人賽相關文章」區塊,程式碼大概如上圖所示。

第 1 行:狀態標簽函式,判斷是否為單一文章頁面。
第 4 行至第 7 行:給 WP_Query 的查詢參數,找的是文章類型,顯示 5 筆。
第 9 行:實例化 WP_Query 類別。
第 14 行:更新文章所需的全域變數。
第 11 行至第 22 行:執行 The Loop,印出帶有文章連結的文章標題。

總結

WP_Query 類別主要用在佈景主題範本中,用於生成 SQL 查詢語句,並提供我們專門處理文章迴圈的方法,比較要注意的是 The Loop 的概念比較不直覺,它是採用在迴圈的區域內依次更新全域變數,接著依賴這些全域變數的函式才能正確輸出當前在迴圈中的文章,一開始如果不大習慣這樣的邏輯,多用幾次就習慣了。


課後思考:

WP_Query 類別提供了豐富的參數來查詢對應的資料表,但有些參數可能會產生不佳的 SQL 語句查詢,產生效能的問題,該如何避免這種情況發生?

前篇解答參考:

當發現 MySQL 的 binlog 長大的速度異常,或者 CPU 的負荷一直很高,就是一種警訊。使用像是 Query Monitor 這類的開發者工具,會將每一條 SQL 語句都列出來,當發現更新的對象為資料表 wp_optionsrewrite_rules 欄位,就必須清查網站上的外掛,搜尋 flush_rewrite_rules 關鍵字。


上一篇
Day 20 - 使用 Rewrite API 設計客制化網址路由
下一篇
Day 22 - 理解 WordPress 的資料庫操作類別 wpdb 的用法
系列文
從 0 到 100:WordPress 開發者的實戰手冊30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言