I’ve been trying to run a search on user names by following the wordpress codex but it doesn’t seem to work…

The following query, which is copied directly from the codex, returns 0 results. However, If I remove the meta_query (or ‘search’ parameter, depending on if i search for username or first name) then it returns results. Is this a bug with WordPress?

Essentially, in spite of the codex and multiple over examples I’ve looked up explicitly stating that both ‘search’ and ‘meta_query’ can run together it doesn’t appear to be the case. Can anyone confirm this for me?

$meta_search="Ross";

$qArgs = array (
    'order' => 'ASC',
    'orderby' => 'display_name',
    'search' => '*'.esc_attr( $meta_search ).'*',
    'meta_query' => array(
        'relation' => 'OR',
        array(
            'key'     => 'first_name',
            'value'   => $meta_search,
            'compare' => 'LIKE'
        ),
        array(
            'key'     => 'last_name',
            'value'   => $meta_search,
            'compare' => 'LIKE'
        ),
        array(
            'key' => 'description',
            'value' => $meta_search ,
            'compare' => 'LIKE'
        )
    )
);

$find_users = new WP_User_Query($qArgs);

Solution:
As a result of the missing functionality here I’ve been forced to run 2 separate queries and merge them together. Far form ideal but in real time I cannot wait for a bug fix. So, for what its worth (which for the higher level devs out there will be minimal, but for intermediates will hopefully be useful) here’s my work around –

// ORIGINAL QUERY
$qArgs = array('role' => 'subscriber','posts_per_page' => -1);

// SIMPLE SEARCH
$search1Args = array('search' => '*'.esc_attr($meta_search).'*');    
// merge search with original query
$s1Args = array_merge($qArgs, $search1Args);
// go fetch
$find_users_1 = new WP_User_Query($s1Args);

// META QUERY
$search2Args = array(
    'meta_query' => array(
    'relation' => 'OR',
    array(
        'key'     => 'first_name',
        'value'   => $meta_search,
        'compare' => 'LIKE'
    ),
    array(
        'key'     => 'last_name',
        'value'   => $meta_search,
        'compare' => 'LIKE'
    )
    )
);
// merge search with original query
$s2Args = array_merge($qArgs, $search2Args);
// go fetch
$find_users_2 = new WP_User_Query($s2Args);

// MERGE QUERIES
$find_out_1 = $find_users_1->get_results();
$find_out_2 = $find_users_2->get_results();
$found_users = array_merge_recursive($find_out_1, $find_out_2); // rebuild the returned users

$find_count_1 = $find_users_1->total_users;
$find_count_2 = $find_users_2->total_users;
$find_count = ($find_count_1 + $find_count_2); // rebuild the user count

// RECOMPILE
$find_users = $find_users_1;
$find_users->results = $found_users;
$find_users->total_users = $find_count;

As a warning I haven’t considered pagination here and it would need considering if someone expected to use this on a site with a lot of users.

1 Answer
1

They seems to work together, but note the AND part between the search part and the meta query part, in the generated SQL query. I wonder if you expected OR instead?

Here are the generated SQL queries, for the two cases you mentioned:

Search + Meta Query:

SELECT DISTINCT SQL_CALC_FOUND_ROWS wp_users.* 
    FROM wp_users 
    INNER JOIN wp_usermeta 
        ON ( wp_users.ID = wp_usermeta.user_id ) 
    WHERE 1=1 
        AND 
        ( 
            (
                    wp_usermeta.meta_key = 'first_name' 
                AND CAST(wp_usermeta.meta_value AS CHAR) LIKE '%Ross%' 
            ) 
            OR 
            ( 
                    wp_usermeta.meta_key = 'last_name' 
                AND CAST(wp_usermeta.meta_value AS CHAR) LIKE '%Ross%' 
            ) 
            OR 
            (   
                    wp_usermeta.meta_key = 'description' 
                AND CAST(wp_usermeta.meta_value AS CHAR) LIKE '%Ross%'
            )
        ) 
        AND 
        (
               user_login LIKE '%Ross%' 
            OR user_nicename LIKE '%Ross%'
        ) 
    ORDER BY display_name ASC ;

Only Search:

SELECT SQL_CALC_FOUND_ROWS wp_users.* 
    FROM wp_users 
    WHERE 1=1 
        AND 
        (
               user_login LIKE '%Ross%' 
            OR user_nicename LIKE '%Ross%'
        ) 
    ORDER BY display_name ASC ;

Core check:

In the core we have the WP_User_Query::get_search_sql() method returning an AND part:

return ' AND (' . implode(' OR ', $searches) . ')';

and similarly in the WP_Meta_Query::get_sql_clauses() method, we have an AND part:

$sql['where'] = ' AND ' . $sql['where'];

Leave a Reply

Your email address will not be published. Required fields are marked *