如何基于post__in和p数组让查询结果重复显示指定文章?
保留post__in中的重复文章结果
这个需求确实有点反常规(毕竟大部分人都在想办法去重😂),不过核心问题在于WordPress的WP_Query默认会利用数据库的IN子句查询post__in,而数据库的IN本身只会返回唯一的ID结果,不管你在数组里写多少次重复值。要绕过这个限制,我们可以通过修改查询语句的方式,让数据库返回重复的行,而且不用额外遍历数组。
解决方案:使用posts_clauses过滤器修改SQL查询
我们可以通过WordPress的posts_clauses钩子,把原来的IN查询改成JOIN一个包含重复ID的临时数据集,这样每个重复的ID都会对应一条查询结果,同时还能保留你传入数组的顺序。
具体代码实现
首先添加过滤器函数:
add_filter('posts_clauses', 'preserve_duplicate_posts_in_query', 10, 2); function preserve_duplicate_posts_in_query($clauses, $query) { // 只处理包含post__in参数的主查询(可根据需求调整范围) if (!$query->is_main_query() || empty($query->query_vars['post__in'])) { return $clauses; } $post_ids = $query->query_vars['post__in']; // 如果数组没有重复值,直接返回原查询 if (count($post_ids) === count(array_unique($post_ids))) { return $clauses; } // 生成带排序序号的临时数据集(保证结果顺序和传入数组一致) $temp_table_rows = []; $sort_order = 0; foreach ($post_ids as $id) { $sort_order++; $temp_table_rows[] = "(SELECT " . (int)$id . " AS post_id, {$sort_order} AS sort_order)"; } $temp_table = implode(' UNION ALL ', $temp_table_rows); // 修改FROM子句,JOIN临时表 $clauses['from'] = "{$clauses['from']} JOIN ({$temp_table}) AS ordered_posts ON wp_posts.ID = ordered_posts.post_id"; // 移除原查询中的ID IN条件 $clauses['where'] = preg_replace('/\bAND?\s+ID\s+IN\s*\([^)]+\)/i', '', $clauses['where']); // 按照临时表的序号排序,保持传入数组的顺序 $clauses['orderby'] = "ordered_posts.sort_order ASC"; // 确保不添加DISTINCT去重 $clauses['distinct'] = ''; return $clauses; }
然后正常使用WP_Query即可:
// 传入包含重复ID的数组 $args = [ 'post_type' => 'post', 'post__in' => [123, 456, 123, 789], // 这里有重复的123 'posts_per_page' => -1, // 显示所有匹配结果 ]; $query = new WP_Query($args); // 循环输出结果,你会看到123对应的文章出现两次 if ($query->have_posts()) { while ($query->have_posts()) { $query->the_post(); echo get_the_title() . '<br>'; } wp_reset_postdata(); }
为什么这个方法高效?
- 只需要一次数据库查询就能得到包含重复值的结果集,不需要额外遍历数组去逐个获取文章;
- 利用数据库的JOIN操作,性能上比PHP层面循环
get_post()要高很多,尤其是当数组较大时; - 完美保留了你传入数组的顺序,不需要额外处理排序。
内容的提问来源于stack exchange,提问作者user137681
相关产品推荐
相关产品推荐

