使用具有多个元查询的orderby自定义元时的WP_Query问题

时间:2014-12-17 05:37:49

标签: wordpress wp-query

我相信这是使用这种高级查询在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 ...

0 个答案:

没有答案
相关问题