讓 WooCommerce 搜尋也能搜尋商品分類!混在一起做撒尿牛丸

明明有商品卻找不到對應的廣義模糊名稱
在 WooCommerce 的預設設定中,使用者於前台搜尋框輸入關鍵字時,系統只會比對產品名稱(post_title),若產品名稱與分類名稱無關,可能導致搜尋不到對應的商品。這對於產品分類架構清楚的電商網站來說,是一個明顯的使用者體驗痛點。
為了解決這個問題,我們可以透過 WordPress 的 posts_clauses
過濾器,修改 SQL 查詢語法,讓搜尋結果同時比對 product_cat
的分類名稱。以下會逐步解析這段程式碼的設計邏輯:
在開發的路上難免會碰到很多問題,而問題有大有小,我們端看要怎樣去看待這個問題,可以用替代方案,也可以直接略過,更可以...直球對決!
原生 WP 搜尋查詢功能並不支援分類名稱搜尋
問題的發生是這樣的,針對 WooCommerce 電商網站設定搜尋商品時,預設是搜尋 title 也就是商品名稱,但是我們往往有個迷思,就是當使用者需要比較廣範圍模糊搜尋該商品的種類時,過去都是依賴商品的分類連結去找到,或者某一些類似 AJAX Search 的功能可以辦到,但今天若要做成上圖這樣的方式,列出一個大家都在找的熱門關鍵字讓使用者更為方便的方式時,就顯得有點尷尬,會發生下圖這種情況:
範例程式碼
add_filter( 'posts_clauses', 'shp_search_include_product_cat_name', 10, 2 );
function shp_search_include_product_cat_name( $clauses, $wp_query ) {
if (
! is_admin()
&& $wp_query->is_main_query()
&& $wp_query->is_search()
&& $wp_query->get( 'post_type' ) === 'product'
) {
global $wpdb;
$term = $wpdb->esc_like( $wp_query->get( 's' ) );
$like = "'%{$term}%'";
$clauses['join'] .= "
LEFT JOIN {$wpdb->term_relationships} AS tr
ON ({$wpdb->posts}.ID = tr.object_id)
LEFT JOIN {$wpdb->term_taxonomy} AS tt
ON (tr.term_taxonomy_id = tt.term_taxonomy_id AND tt.taxonomy = 'product_cat')
LEFT JOIN {$wpdb->terms} AS t
ON (tt.term_id = t.term_id)
";
$clauses['where'] = preg_replace(
"/\(\s*{$wpdb->posts}\.post_title\s+LIKE\s*('[^']+')\s*\)/",
"(
{$wpdb->posts}.post_title LIKE \$1
OR t.name LIKE \$1
)",
$clauses['where']
);
$clauses['distinct'] = 'DISTINCT';
}
return $clauses;
}
解釋重點:
- 條件判斷
確保僅在前台、主查詢、搜尋頁面、搜尋產品時套用此功能,避免後台或非搜尋時誤觸。 - 關鍵字安全處理
使用 $wpdb->esc_like() 處理搜尋字串,避免 SQL 注入風險。 - 關聯資料表 JOIN
JOIN 三個 WordPress taxonomy 相關資料表,取得每個商品的分類名稱。 - 擴充 WHERE 條件
原本只搜尋 post_title,現在額外加上 t.name(分類名稱)來進行模糊比對。 - 使用 DISTINCT
解決商品同時屬於多個分類時的重複結果問題。
成功範例
上述為按下搜尋功能下方的「紙紮房屋」這顆預設好的按鈕讓使用者加速搜尋到想找的,別懷疑,你分類有列出來,但很多使用者甚至不知道分類在哪打開切換之類的。
這樣修改後,也不會影響原生地搜尋商品名稱,等於說把你的 WooCommerce 搜尋功能給增強了,而且只用一段簡單的 Snippet 就可達成。