如何通过WordPress钩子合并两类搜索查询结果?
WordPress搜索功能优化:实现OR条件匹配及分页修复
需求
需要实现搜索结果满足以下任一条件:
- 文章标题(
post_title)匹配搜索关键词 - 文章所属自定义分类法
color的ACF重复字段synonimes中的synonim文本字段匹配搜索关键词
当前问题
- 最初用
pre_get_posts钩子只能实现AND条件,不符合OR需求 - 改为自定义查询获取匹配文章后合并到主查询,分页时自定义匹配的结果会丢失
用户当前代码
function filter_tax($query){ if (!is_admin() && $query->is_main_query() && $query->is_search()) { $args_new_query = array( 'post_type' => MAIN_POST, 'posts_per_page' => 12, 'post_parent' => 0, ); $new_query = new WP_Query($args_new_query); $search_keyword = sanitize_text_field(get_search_query()); $matching_posts = array(); if ($new_query->have_posts()) { $taxonomy_name = 'color'; while ($new_query->have_posts()) : $new_query->the_post(); $post_id = get_the_ID(); $terms = wp_get_post_terms($post_id, $taxonomy_name); foreach ($terms as $term) { $synonim_values = get_field('synonimes', $taxonomy_name . '_' . $term->term_id); if (is_array($synonim_values)) { foreach ($synonim_values as $syn) { if (strpos($syn['synonim'], $search_keyword) !== false) { $matching_posts[] = get_post($post_id); break 2; } } } } endwhile; wp_reset_postdata(); } if (!empty($matching_posts)) { /*$query->set('post__in', wp_list_pluck($matching_posts, 'ID'));*/ $query->posts = array_merge([], $matching_posts); } } }
问题根源
- 自定义查询
$new_query仅获取12条文章,无法覆盖所有可能匹配的内容,分页时其他页的匹配文章根本没被检索 - 直接替换
$query->posts会破坏主查询的分页计算逻辑,WordPress分页依赖found_posts、max_num_pages等参数,直接替换文章数组不会更新这些参数
解决方案
方案一:修改SQL WHERE子句(推荐,性能最优)
通过posts_where钩子直接修改主查询的SQL,实现OR条件匹配,完全兼容原生分页逻辑:
function custom_search_where_clause($where, $query) { if (!is_admin() && $query->is_main_query() && $query->is_search()) { global $wpdb; $search_term = sanitize_text_field(get_search_query()); $like_term = '%' . $wpdb->esc_like($search_term) . '%'; // 保留原生的post_title匹配条件 $original_where = $where; // 新增匹配color分类法ACF重复字段的条件 $taxonomy = 'color'; $meta_key_prefix = 'synonimes_'; // ACF重复字段的前缀 // ACF重复字段存储格式为:synonimes_0_synonim、synonimes_1_synonim... $additional_where = " OR EXISTS ( SELECT 1 FROM {$wpdb->term_relationships} tr JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id JOIN {$wpdb->termmeta} tm ON tt.term_id = tm.term_id WHERE tr.object_id = {$wpdb->posts}.ID AND tt.taxonomy = '{$taxonomy}' AND tm.meta_key LIKE '{$meta_key_prefix}%_synonim' AND tm.meta_value LIKE '{$like_term}' )"; $where = $original_where . $additional_where; } return $where; } add_filter('posts_where', 'custom_search_where_clause', 10, 2);
优势:
- 直接复用主查询,无需额外循环查询,性能更优
- 完全适配WordPress原生分页逻辑,分页自动生效
- 覆盖所有可能匹配的文章,不会遗漏
方案二:修正自定义查询合并逻辑
如果坚持用自定义查询的方式,需要修正代码以支持分页:
function filter_tax($query){ if (!is_admin() && $query->is_main_query() && $query->is_search()) { $search_keyword = sanitize_text_field(get_search_query()); $matching_post_ids = array(); // 1. 获取原生搜索匹配post_title的文章ID $original_post_ids = wp_list_pluck($query->posts, 'ID'); $matching_post_ids = array_merge($matching_post_ids, $original_post_ids); // 2. 从数据库直接查询匹配color分类法ACF字段的文章ID global $wpdb; $taxonomy = 'color'; $like_term = '%' . $wpdb->esc_like($search_keyword) . '%'; $synonym_post_ids = $wpdb->get_col($wpdb->prepare(" SELECT DISTINCT tr.object_id FROM {$wpdb->term_relationships} tr JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id JOIN {$wpdb->termmeta} tm ON tt.term_id = tm.term_id WHERE tt.taxonomy = %s AND tm.meta_key LIKE %s AND tm.meta_value LIKE %s ", $taxonomy, 'synonimes_%_synonim', $like_term)); // 合并并去重 $matching_post_ids = array_merge($matching_post_ids, $synonym_post_ids); $matching_post_ids = array_unique($matching_post_ids); if (!empty($matching_post_ids)) { // 设置主查询的文章ID列表 $query->set('post__in', $matching_post_ids); // 重置排序为相关性排序(避免post__in默认按ID排序) $query->set('orderby', 'relevance'); $query->set('order', 'DESC'); // 更新分页参数,确保分页计算正确 $total_posts = count($matching_post_ids); $query->found_posts = $total_posts; $query->max_num_pages = ceil($total_posts / $query->get('posts_per_page')); } } } add_action('pre_get_posts', 'filter_tax');
修正点:
- 用数据库查询替代循环所有文章,提升性能
- 合并原生搜索结果和自定义匹配结果并去重
- 使用
post__in设置主查询参数,而非直接替换文章数组 - 更新
found_posts和max_num_pages参数,保证分页逻辑正常
内容的提问来源于stack exchange,提问作者Ivan_OFF
相关产品推荐
相关产品推荐

