Repost from wordpress.stackexchange:
I run a blog site with posts by authors, and I implemented a search that would return results if the search was like an author’s name or the search term was contained in a story. I was functioning and properly returned authors who matched the search, but now the search returns every user every single time.
I suspect it has something to do with WP_User_query since
since that function was updated in 4.2, but I have no idea how I would change it to be compatible.
Here is the search code:
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 );
EDIT:
The relevant sql in array form:
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%' ) ) )
I’m not quite sure why this sql no longer works in the latest update. It seems to be properly formatted, but it still returns all authors.
It seems like I was right (see comment to question): I had the possibility to test the query before and after the update, and it changed:
So with this line in your code
you’re changing the first
AND
found in the query with anOR
, but as you can see now it targets the wrong one.In fact now the condition is
WHERE 1=1 OR ...
, that is like sayingALWAYS
. 🙂So as I said earlier in the comment you need to target the right
AND
, but be careful that order can change again.Update
Unfortunately there’s no ultimate way to do this because is not native (let’s hope it’ll be added soon), so you need to rely on changing the right
AND
.Maybe find a way that works for both the queries (old and new), and to do that you need to change filter hook: use
pre_user_query
: