wordpress 的搜尋 (search) 技巧

搜尋特定的category

直接限制前台搜尋只查某個 category

functions.php 加:

PHP
function my_search_only_in_category($query) {
    if (!is_admin() && $query->is_main_query() && $query->is_search()) {
        $query->set('cat', 12); // 只搜尋 category ID = 12
    }
}
add_action('pre_get_posts', 'my_search_only_in_category');

這樣前台搜尋結果就只會出現在 分類 ID 12 裡的文章。

只在某個 category 與其子分類中搜尋

cat 通常會包含該分類底下文章;若想更明確控制,也可以先抓子分類 ID 再指定:

PHP
function my_search_only_in_category_tree($query) {
    if (!is_admin() && $query->is_main_query() && $query->is_search()) {
        $parent_cat_id = 12;

        $child_ids = get_terms([
            'taxonomy'   => 'category',
            'hide_empty' => false,
            'child_of'   => $parent_cat_id,
            'fields'     => 'ids',
        ]);

        $cat_ids = array_merge([$parent_cat_id], $child_ids);

        $query->set('category__in', $cat_ids);
    }
}
add_action('pre_get_posts', 'my_search_only_in_category_tree');

這樣會限定在:

  • 主分類
  • 子分類
  • 孫分類

內搜尋。

讓使用者從搜尋表單指定 category

image 2

如果不是想「全站搜尋都固定只查某分類」,而是想做成搜尋表單帶 category,可以這樣:

PHP
//搜尋表單
<form role="search" method="get" action="<?php echo esc_url(home_url('/')); ?>">
    <input type="search" name="s" placeholder="搜尋文章">
    <input type="hidden" name="cat" value="12">
    <button type="submit">搜尋</button>
</form>

這樣送出後就只查 category 12。

指定分類 slug,再轉成 ID

若比較習慣用 slug:

PHP
function my_search_only_in_specific_category($query) {
    if (!is_admin() && $query->is_main_query() && $query->is_search()) {
        $category = get_category_by_slug('business-supplies');

        if ($category) {
            $query->set('cat', $category->term_id);
        }
    }
}
add_action('pre_get_posts', 'my_search_only_in_specific_category');

如果搜尋的是 自訂文章類型

那還要補:

PHP
$query->set('post_type', 'post');
或是
$query->set('post_type', ['post']);

不然搜尋結果可能混到 page 或其他 post type。

指定多個分類 slug

指定多個分類 slug 最乾脆的方式是先把 slug 轉成 term ID,再塞進 category__in

PHP
function my_search_only_in_multiple_categories($query) {
    if (!is_admin() && $query->is_main_query() && $query->is_search()) {
        $slugs = ['business-supplies', 'office', 'stationery'];

        $categories = get_terms([
            'taxonomy'   => 'category',
            'hide_empty' => false,
            'slug'       => $slugs,
            'fields'     => 'ids',
        ]);

        if (!is_wp_error($categories) && !empty($categories)) {
            $query->set('category__in', $categories);
        }
    }
}
add_action('pre_get_posts', 'my_search_only_in_multiple_categories');

包含這些分類底下的子分類、孫分類

那就要把每個 slug 對應的分類,再往下抓全部子孫分類 ID:

PHP
function my_search_only_in_multiple_category_trees($query) {
    if (!is_admin() && $query->is_main_query() && $query->is_search()) {
        $slugs = ['business-supplies', 'office', 'stationery'];

        $parent_ids = get_terms([
            'taxonomy'   => 'category',
            'hide_empty' => false,
            'slug'       => $slugs,
            'fields'     => 'ids',
        ]);

        if (is_wp_error($parent_ids) || empty($parent_ids)) {
            return;
        }

        $all_cat_ids = $parent_ids;

        foreach ($parent_ids as $parent_id) {
            $child_ids = get_terms([
                'taxonomy'   => 'category',
                'hide_empty' => false,
                'child_of'   => $parent_id,
                'fields'     => 'ids',
            ]);

            if (!is_wp_error($child_ids) && !empty($child_ids)) {
                $all_cat_ids = array_merge($all_cat_ids, $child_ids);
            }
        }

        $all_cat_ids = array_values(array_unique($all_cat_ids));

        $query->set('category__in', $all_cat_ids);
    }
}
add_action('pre_get_posts', 'my_search_only_in_multiple_category_trees');

URL 傳入多個 slug

例如網址長這樣:

PHP
?s=abc&cats=business-supplies,office,stationery

可以這樣寫:

PHP
function my_search_only_in_multiple_categories_from_url($query) {
    if (!is_admin() && $query->is_main_query() && $query->is_search()) {
        if (!empty($_GET['cats'])) {
            $slugs = array_map('sanitize_title', explode(',', wp_unslash($_GET['cats'])));

            $categories = get_terms([
                'taxonomy'   => 'category',
                'hide_empty' => false,
                'slug'       => $slugs,
                'fields'     => 'ids',
            ]);

            if (!is_wp_error($categories) && !empty($categories)) {
                $query->set('category__in', $categories);
            }
        }
    }
}
add_action('pre_get_posts', 'my_search_only_in_multiple_categories_from_url');

搜尋表單傳送到URL範例

如果要搭配表單

PHP
<form role="search" method="get" action="<?php echo esc_url(home_url('/')); ?>">
    <input type="search" name="s" placeholder="搜尋文章">
    <input type="hidden" name="cats" value="business-supplies,office,stationery">
    <button type="submit">搜尋</button>
</form>

該選哪一種

如果要的是:

  • 整個網站搜尋都固定只搜某分類
    pre_get_posts
  • 某個搜尋框只搜某分類
    用表單 hidden cat
  • 只搜主分類加全部子孫分類
    category__in + get_terms()

設定 search 的結果的 Pagination

functions.phppre_get_posts 設定就可以。

PHP
function my_search_posts_per_page($query) {
    if (!is_admin() && $query->is_main_query() && $query->is_search()) {
        $query->set('posts_per_page', 8);
    }
}
add_action('pre_get_posts', 'my_search_posts_per_page');

如果同時還要限制搜尋只查特定多個分類 slug,可以合併成這樣:

PHP
function my_search_filter($query) {
    if (!is_admin() && $query->is_main_query() && $query->is_search()) {
        $query->set('posts_per_page', 8);

        $slugs = ['business-supplies', 'office', 'stationery'];

        $category_ids = get_terms([
            'taxonomy'   => 'category',
            'hide_empty' => false,
            'slug'       => $slugs,
            'fields'     => 'ids',
        ]);

        if (!is_wp_error($category_ids) && !empty($category_ids)) {
            $query->set('category__in', $category_ids);
        }
    }
}
add_action('pre_get_posts', 'my_search_filter');

如果 search.php 有分頁,記得用主查詢的分頁輸出,不要另外 new WP_Query,不然又很容易出現 /page/2/404 pagination error 錯誤。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *


內容索引