由wp 4.2更新破坏的搜索功能

时间:2015-04-25 22:40:19

标签: php wordpress wp-query

从wordpress.stackexchange重新发布:

我运行一个博客网站,其中包含作者的帖子,如果搜索类似于作者姓名或搜索词包含在故事中,我实施的搜索会返回结果。我正在运作并且正确地返回了与搜索匹配的作者,但现在搜索每次都返回每个用户。

我怀疑它与WP_User_query since有关,因为该功能在4.2中已更新,但我不知道如何将其更改为兼容。

以下是搜索代码:

add_filter('user_search_columns', 'user_search_columns_bd' , 10, 3);

function user_search_columns_bd($search_columns, $search, $this){
    if(!in_array('display_name', $search_columns)){
        $search_columns[] = 'display_name';
    }
    return $search_columns;
}

add_filter( 'get_meta_sql', 'user_meta_filter', 10, 6 );

function user_meta_filter( $sql, $queries, $type, $primary_table, $primary_id_column, $context ){
    if ( $type !== 'user' ){
        return $sql;
    }

    if ( ! isset( $context->query_vars['meta_query']['replace_and'] ) || $context->query_vars['meta_query']['replace_and'] !== true ){
        return $sql;
    }

    $sql['where'] = preg_replace('/AND/', 'OR', $sql['where'], 1);
    return $sql;
}   


$args = array(
'search'         => $s,
'search_columns' => array( 'user_login', 'user_email'),
'meta_query' => array(
    'relation' => 'OR',
    'replace_and' => true, 
    array(
        'key'     => 'first_name',
        'value'   => $s,
        'compare' => 'LIKE'
    ),
    array(
        'key'     => 'last_name',
        'value'   => $s,
        'compare' => 'LIKE'
    )
)
);

// The Query
$user_query = new WP_User_Query( $args ); 

编辑:

数组形式的相关sql:

Array ( [join] => INNER JOIN wp_usermeta ON ( wp_users.ID = wp_usermeta.user_id ) [where] => OR ( ( wp_usermeta.meta_key = 'first_name' AND CAST(wp_usermeta.meta_value AS CHAR) LIKE '%Search%' ) OR ( wp_usermeta.meta_key = 'last_name' AND CAST(wp_usermeta.meta_value AS CHAR) LIKE '%Search%' ) ) )

我不太确定为什么这个sql在最新更新中不再有效。它似乎格式正确,但它仍然会返回所有作者。

1 个答案:

答案 0 :(得分:1)

看起来我是对的(请参阅评论评论):我有可能在更新之前和之后测试查询,并且它已更改:

# BEFORE
SELECT DISTINCT SQL_CALC_FOUND_ROWS wp_users.* FROM wp_users INNER JOIN wp_usermeta ON ( wp_users.ID = wp_usermeta.user_id )  INNER JOIN wp_usermeta AS mt1 ON ( wp_users.ID = mt1.user_id ) WHERE 1=1 AND (user_login LIKE 'test' OR user_email LIKE 'test' OR display_name LIKE 'test') OR ( 
  ( 
    ( 
      ( wp_usermeta.meta_key = 'first_name' AND CAST(wp_usermeta.meta_value AS CHAR) LIKE '%test%' ) 
      OR 
      ( wp_usermeta.meta_key = 'last_name' AND CAST(wp_usermeta.meta_value AS CHAR) LIKE '%test%' )
    ) 
    AND 
    mt1.meta_key = 'wp_6_capabilities'
  )
) ORDER BY user_login ASC 


# AFTER
SELECT DISTINCT SQL_CALC_FOUND_ROWS wp_users.* FROM wp_users INNER JOIN wp_usermeta ON ( wp_users.ID = wp_usermeta.user_id )  INNER JOIN wp_usermeta AS mt1 ON ( wp_users.ID = mt1.user_id ) WHERE 1=1 OR ( 
  ( 
    ( 
      ( wp_usermeta.meta_key = 'first_name' AND CAST(wp_usermeta.meta_value AS CHAR) LIKE '%test%' ) 
      OR 
      ( wp_usermeta.meta_key = 'last_name' AND CAST(wp_usermeta.meta_value AS CHAR) LIKE '%test%' )
    ) 
    AND 
    mt1.meta_key = 'wp_6_capabilities'
  )
) AND (user_login LIKE 'test' OR user_email LIKE 'test' OR display_name LIKE 'test') ORDER BY user_login ASC

所以在你的代码中使用这一行

$sql['where'] = preg_replace('/AND/', 'OR', $sql['where'], 1);

您正在使用AND更改查询中找到的第一个OR,但正如您现在所看到的那样,它定位的是错误的。{/ p>

事实上现在条件是WHERE 1=1 OR ...,就像说ALWAYS。 :)

正如我之前在评论中所说,您需要定位正确的AND,但请注意,订单可能会再次发生变化。

<强>更新

不幸的是,没有最终的方法可以做到这一点,因为它不是原生的(我们希望它很快会被添加),所以你需要依靠改变正确的AND

也许找到一种适用于查询(旧版和新版)的方法,为此你需要更改过滤器钩子:使用pre_user_query

add_action('pre_user_query', 'my_custom_users_search');
function my_custom_users_search( $args ) {
    if( isset( $args->query_vars['meta_query']['replace_and'] ) && $args->query_vars['meta_query']['replace_and'] )
        $args->query_where = str_replace(') AND (', ') OR (', $args->query_where);
}