问题描述
我认为问题本质上与 sql 查询结构有关,我不是专家….
我需要通过 2 个参数搜索帖子 (自定义帖子类型):
-
pd_city
-
pd_country
请注意,meta_query 关系是’OR’,所以如果上述两个之一都是有一些结果。
第三键 (is_sponsored) 用于排序帖子! “is_sponsored” 值等于 1 的帖子可以是 1 或 0,而顶部应列出。
所以这里是 WordPress 的事情:
$sfp_query_args = array(
'sfp_complex_search' => 'yeap',
'tax_query' => array( array( 'taxonomy' => 'sfp_post_category', 'terms' => $term_id ) ),
//'meta_key' => 'is_sponsored',
'post_type' => 'sfpposts',
'post_status' => 'publish',
'showposts' => (int)$per_page,
'paged' => $paged,
'meta_query' => array( 'relation' => 'OR',
array( 'key' => 'pd_city', 'value' => $sfp_search_meta, 'compare' => 'LIKE' ),
array( 'key' => 'pd_country', 'value' => $sfp_search_meta, 'compare' => 'LIKE' ),
array( 'key' => 'is_sponsored' )
)
);
$sfp_search = new WP_Query( $sfp_query_args );
我也需要用”posts_orderby” 过滤结果,以获得那些赞助到顶部:
add_filter( 'posts_orderby', 'sfp_modify_search' );
function sfp_modify_search( $orderby ) {
if( !is_admin() && is_page( $this->options[ 'sfp_page_entries_search' ] ) ) {
global $wpdb;
$orderby = " CASE WHEN mt2.meta_value = 0 THEN 1 END, $wpdb->posts.post_date DESC ";
}
return $orderby;
}
真正的问题依赖于这个查询,返回来自”sfp_post_category” 的所有 POSTS,不仅是匹配”pd_city” 或”pd_country” 的所有 POSTS,因为所有 POSTS 都有”is_sponsored” 元键 (并且值设置为 1 或 0) 。再次:”is_sponsored” 需要排序!
当 var_dump
var_dump( $sfp_search->request );
… WordPress 的 sql 看起来像这样:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id)
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id IN (77) )
AND wp_posts.post_type = 'sfpposts'
AND (wp_posts.post_status = 'publish')
AND ( (wp_postmeta.meta_key = 'pd_city'
AND CAST(wp_postmeta.meta_value AS CHAR)
LIKE '%something%')
OR (mt1.meta_key = 'pd_country'
AND CAST(mt1.meta_value AS CHAR)
LIKE '%something%')
OR mt2.meta_key = 'is_sponsored' )
GROUP BY wp_posts.ID
ORDER BY CASE WHEN mt2.meta_value = 0 THEN 1 END, wp_posts.post_date DESC
LIMIT 0, 10
如何从结果中删除与”pd_city” 或”pd_country” 不匹配的所有帖子?
最佳解决方案
罪魁祸首
这个问题的罪魁祸首是不支持不同和/或嵌套关系的元查询 – 顺便说一下,这也使我以前坚持不了。在最近有一个搜索场景的情况下。
您想要做的只是无法通过 WP_Query
以及一个循环单独完成。如您所知,无论是将排序键放在 meta_query
数组中还是将其作为一般查询参数,都不会有所作为。如果您将元查询关系设置为 OR
,并在查询 args 的任何位置指定 meta_key
,而不设置附带的 meta_value
参数,查询将始终至少返回设置该 meta_key 的所有帖子。为方便起见,为了完整性:当使用具有!=
的单个 meta_query 作为 meta_compare
的值时,查询将返回所有结果,而 meta_key
设置不等于给定的 meta_value
– 它不会返回任何没有使用 meta_key
的帖子。元查询失败的另一点。
解决方案 1
我看到两个选项。一方面,您可以从查询中省略 is_sponsored
元密钥,省略分页,获取正确的帖子,并使用 WP_Query
的第二个实例进行排序,并通过 post__in
参数传递过滤的帖子 ID:
$sfp_search_args = array(
'sfp_complex_search' => 'yeap',
'tax_query' => array( array( 'taxonomy' => 'sfp_post_category', 'terms' => $term_id ) ),
'post_type' => 'sfpposts',
'post_status' => 'publish',
'meta_query' => array(
'relation' => 'OR',
array( 'key' => 'pd_city', 'value' => $sfp_search_meta, 'compare' => 'LIKE' ),
array( 'key' => 'pd_country', 'value' => $sfp_search_meta, 'compare' => 'LIKE' )
)
);
$sfp_search = new WP_Query( $sfp_search_args );
$post_ids = array();
while ( $sfp_search->have_posts() ) : $sfp_search->next_post();
$post_ids[] = $sfp_search->post->ID;
endwhile;
$sfp_ordered_args(
'post__in' => $post_ids,
// note that 'showposts' is deprected
'posts_per_page' => (int)$per_page,
'paged' => $paged,
'meta_key' => 'is_sponsored',
'order' => 'DESC',
'orderby' => 'meta_value_num date'
);
$sfp_ordered = new WP_Query( $sfp_ordered_args );
while ( $sfp_ordered->have_posts() ) : $sfp_ordered->next_post();
// display posts
endwhile;
请注意,WP_Query
的 $orderby
参数将采用由空格分隔的多个值。您的搜索修改可能比必要更复杂。
解决方案 2
由于我喜欢你的想法 var_dumping 查询对象的 request
属性,让我开始一个快速的,并且,未经测试 – 备注的建议:
如果您通过将 OR mt2.meta_key = 'is_sponsored'
的逻辑运算符更改为 AND
稍微修改给定的 SQL,并相应地移动给定的 SQL,则可以使用 $wpdb
来拉动帖子:
$sfp_post_ids = $wpdb->get_col(
"
SELECT wp_posts.ID
FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id)
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id = $term_id )
AND wp_posts.post_type = 'sfpposts'
AND (wp_posts.post_status = 'publish')
AND ( (wp_postmeta.meta_key = 'pd_city'
AND CAST(wp_postmeta.meta_value AS CHAR)
LIKE '%$sfp_search_meta%')
OR (mt1.meta_key = 'pd_country'
AND CAST(mt1.meta_value AS CHAR)
LIKE '%$sfp_search_meta%') )
AND mt2.meta_key = 'is_sponsored'
GROUP BY wp_posts.ID
ORDER BY CASE WHEN mt2.meta_value = 0 THEN 1 END, wp_posts.post_date DESC
"
);
此时,您还有两个选择:使用简单的 foreach
对 $sfp_post_ids
阵列进行迭代,并在该循环中单独使用 get_post()
提取后置数据,或者,如果您想要 WP_Query
的优点 – 分页,模板标签等 – 将 $sfp_post_ids
进给到 post__in
参数,如解决方案 1 所示。
参考文献
注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。