在昨天的介紹的客製化網路路由一文提到,當網站伺服器收到請求,將此請求傳遞給 WordPress 解析完網址之後,會將生成 SQL 查詢語句,向 MySQL 資料庫查詢,接著取得資料後並生成內容輸出到網頁上。
圖:生成內容流程圖
而今天要介紹的主角就是 WP_Query
類別,它 WordPress 核心中,負責生成 SQL 查詢語句的組件。
圖:WP_Query 實例化過程
它的實例化是在 wp-settings.php 檔案中,大約 516 行位置,並將此實例放在全域變數 $wp_the_query
和 $wp_query
中。
以主要鉤點的生命週期來說,位於 sanitize_comment_cookies
和 setup_theme
之間。因此我們除了可以在佈景主題中直接使用 $wp_query
這個全域變數,在 setup_theme 之後的鉤點也可以使用。
適合使用 WP_Query 的情境有兩種。
要找出 WordPress目前正在處理的是哪一種請求,非常簡單,因為 WP_Query 類別中的 $is_
屬性就是設計來存放這個資訊的,並在這裡使用條件標籤來互動。對外掛的開發者來說非常有用。
以下是部分屬性的例子:
$is_single
:如果當前請求是查看單一文章頁面,此屬性為 true。$is_page
:如果當前是一個靜態頁面的請求,此屬性為 true。$is_archive
:如果當前請求是一個彙整頁面,例如分類、標籤、作者等存檔頁面,此屬性為 true。條件標籤指的是 WordPress 提供的一套函式,這些函數可以用來檢查當前請求的各種條件,並基於這些條件執行不同的程式邏輯。條件標籤和 WP_Query 實例的 $is_
屬性直接相關,並提供了一個更簡潔、更方便的方式來進行檢查。
以下是部分條件標籤函式的例子:
is_single()
:檢查當前是否為單一文章頁面。is_page()
:檢查當前是否為一個靜態頁面。is_archive()
:檢查當前是否為一個彙整頁面。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
讓其它依賴這個全域變數的函式可以使用。
建構子的參位為陣列,根據查詢種類的不同有不一樣的條件,按此查詢。
名稱 | 說明 |
---|---|
$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 查詢變量並根據需要將其轉換為 ASC 或 DESC 。 |
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_options
的rewrite_rules
欄位,就必須清查網站上的外掛,搜尋flush_rewrite_rules
關鍵字。