我相信这是使用这种高级查询在wordpress中生成的SQL的错误。希望我错了,有人可以解决这个问题。
[TL:DR]当我删除orderby部分时,此高级查询按预期工作,否则无效(它返回所有帖子)。我已经在$ query->请求中包含了SQL输出,它显示了查询的不正确嵌套(除非我遗漏了什么!)。
背景 Wordpress 4.0.1,通过本地Vagrant框运行(使用Chassis for wp dev)。
我正在编写一个API可访问端点,以根据从前端传入的某些条件搜索自定义帖子类型“services”。最终目标是允许在两个不同的上下文中进行ajax搜索 - 一个用于公共,一个用于内部系统,仅显示一些仅由操作员发出的额外服务。
该系统的一部分是服务的基本地理定位,一些是本地的,另一些是国家的。无论表格中的“邮政编码”变量如何,国家服务都应显示在结果中,本地服务应仅显示邮政编码是否适合他们。我通过在每个服务的保存时间填充一个名为“ hidden_keyword_search ”的隐藏自定义字段来执行此操作,其中包含来自其他字段的大量位,例如标题,郊区,邮政编码和列表根据服务基础邮政编码的半径发布代码。保持搜索速度快,并且不需要在每次搜索时动态地进行地理定位,因此它变成了对邮政编码进行非常基本的关键字搜索。
当我想通过另一个自定义元字段“ display_ranking ”来订购这些结果时,问题就出现了。这或多或少用于将可信赖的可靠服务放在结果的顶部,它只是一个数字订单(ASC订单)。
我有两个服务要测试。一个是国家的,另一个是本地的,只提供一个邮政编码(不是4000个)。我发布到端点的查询来自内部上下文(因此没有添加“public”only子句。)
这是传递的$ service_search_params的内容:
$service_search_params['numposts'] = 10;
$service_search_params['context'] = 'ccv';
$service_search_params['postcode'] = '4000';
$service_search_params['category'] = null;
$service_search_params['keyword'] = null;
这是用于构建wp_query的PHP。
$args = array(
'posts_per_page' => $service_search_params['numposts'],
'post_type' => 'service',
'post_status' => 'publish',
/*
* If I comment out the below 3 lines regarding ordering by the custom field 'display ranking',
* then the postcode search works - but then I have to return all results, and manually
* order & slice the array afterwards. If I leave them in, it returns ALL services.
*/
'meta_key' => 'display_ranking',
'orderby' => 'meta_value_num',
'order' => 'ASC'
);
if ($service_search_params['category']) {
$args['tax_query'] = array(
array(
'taxonomy' => 'service_categories',
'field' => 'id',
'terms' => array(intval($service_search_params['category'])),
),
);
}
if ($service_search_params['keyword']) {
$args['meta_query']['relation'] = 'AND';
$args['meta_query'][] = array(
'key' => 'hidden_keyword_search',
'value' => $service_search_params['keyword'],
'compare' => 'LIKE'
);
}
//public restrictions
if ($service_search_params['context'] != 'ccv') {
$args['meta_query']['relation'] = 'AND';
//only show public results for any search outside the ccv context.
$args['meta_query'][] = array(
'key' => 'public',
'value' => true,
'compare' => '='
);
}
//MUST BE LAST.
if ($service_search_params['postcode']) {
//construct a sub meta query. either the postcode is in
//the search keywords, or the service is national or state.
$pcode_meta_query = array();
$pcode_meta_query[] = array(
'key' => 'hidden_keyword_search',
'value' => $service_search_params['postcode'],
'compare' => 'LIKE'
);
// or the service is state/national.
$pcode_meta_query[] = array(
'key' => 'service_area',
'value' => 'national',
'compare' => '='
);
$pcode_meta_query[] = array(
'key' => 'service_area',
'value' => 'state',
'compare' => '='
);
$pcode_meta_query['relation'] = 'OR';
if (isset($args['meta_query']['relation'])) {
$args['meta_query']['relation'] = 'AND'; //probably redundant, just make sure
$args['meta_query'][] = $pcode_meta_query;
} else {
//no other search vars, so make this the top one.
$args['meta_query'] = $pcode_meta_query;
}
}
$the_query = new WP_Query( $args );
基于此,当我传入4000的'邮政编码'时,它应该只返回一个服务 - 全国服务。相反,即使其他服务仅为“本地”且在任何地方都没有“4000”,它也会返回两个结果。当我注释掉orderby变量并且不做任何其他更改时,SQL会更改,并且它只会正确返回国家服务。
这是$ the_query->请求生成的SQL,如果我将orderby变量留在:
// ------ ORDERBY INCLUDED, ONLY 'postcode' (4000) SUPPLIED. RETURNS ALL SERVICES.
SELECT SQL_CALC_FOUND_ROWS sz_posts.ID
FROM sz_posts INNER JOIN sz_postmeta ON sz_posts.ID = sz_postmeta.post_id
INNER JOIN sz_postmeta AS mt1 ON (sz_posts.ID = mt1.post_id)
INNER JOIN sz_postmeta AS mt2 ON (sz_posts.ID = mt2.post_id)
INNER JOIN sz_postmeta AS mt3 ON (sz_posts.ID = mt3.post_id)
WHERE 1=1
AND sz_posts.post_type = 'service'
AND ( (sz_posts.post_status = 'publish') )
AND (
sz_postmeta.meta_key = 'display_ranking'
OR (mt1.meta_key = 'hidden_keyword_search'
AND CAST(mt1.meta_value AS CHAR) LIKE '%4000%')
OR (mt2.meta_key = 'service_area'
AND CAST(mt2.meta_value AS CHAR) = 'national')
OR (mt3.meta_key = 'service_area'
AND CAST(mt3.meta_value AS CHAR) = 'state')
)
GROUP BY sz_posts.ID ORDER BY sz_postmeta.meta_value+0 ASC LIMIT 0, 10
这是$ the_query->请求生成的SQL,如果我对orderby变量进行注释:
// ------ ORDERBY REMOVED, ONLY 'postcode' (4000) SUPPLIED. RETURNS CORRECT SUBSET OF SERVICES.
SELECT SQL_CALC_FOUND_ROWS sz_posts.ID
FROM sz_posts INNER JOIN sz_postmeta ON (sz_posts.ID = sz_postmeta.post_id)
INNER JOIN sz_postmeta AS mt1 ON (sz_posts.ID = mt1.post_id)
INNER JOIN sz_postmeta AS mt2 ON (sz_posts.ID = mt2.post_id)
WHERE 1=1
AND sz_posts.post_type = 'service'
AND ((sz_posts.post_status = 'publish'))
AND (
(sz_postmeta.meta_key = 'hidden_keyword_search' AND CAST(sz_postmeta.meta_value AS CHAR) LIKE '%4000%')
OR (mt1.meta_key = 'service_area' AND CAST(mt1.meta_value AS CHAR) = 'national')
OR (mt2.meta_key = 'service_area' AND CAST(mt2.meta_value AS CHAR) = 'state')
)
GROUP BY sz_posts.ID ORDER BY sz_posts.post_date DESC LIMIT 0, 10
解决方法: 目前我通过查询所有结果(所以post_per_page = -1)来解决这个问题,然后通过display_rank手动排序并返回所需结果数量的array_slice ...