1

I'm building an advanced User search using WP_User_Query but experiencing some unusual behaviour. I'm trying to search with a term that I know exists in the user_nicename and user_email fields but fails to return when I include meta_query in the $args.

Using the simple query below, when searching the users table data, WordPress returns everything as expected because the term exists in the user_nicename and user_email.

$args = array (
    'fields' => ['ID'],
    'count_total' => true,
    'order' => 'ASC',   
    'orderby' => 'display_name',
    'search' => '*'.esc_attr( $search_term ).'*',
);
$wp_user_query = new WP_User_Query($args);

Then however, when I introduce a meta_query into the search to check against the user meta, the query fails to return any results at all - even though it's matching data previously using the simple statement. The meta_query makes the $args look like so:

$args = array (
    'fields' => ['ID'],
    'count_total' => true,
    'order' => 'ASC',   
    'orderby' => 'display_name',
    'search' => '*'.esc_attr( $search_term ).'*',
    'meta_query' => array(
        'relation' => 'OR',
        array(
            'key'     => 'first_name',
            'value'   => $search_term,
            'compare' => 'LIKE'
        ),
        array(
            'key'     => 'last_name',
            'value'   => $search_term,
            'compare' => 'LIKE'
        ),
        array(
            'key' => 'description',
            'value' => $search_term ,
            'compare' => 'LIKE'
        )
    )
);
$wp_user_query = new WP_User_Query($args);

I'm determining which columns to search from the users table by implementing the following filter:

function inc_columns( $search_columns, $search, $this ) {
    $search_columns[] = 'user_email';
    $search_columns[] = 'user_nicename';
    $search_columns[] = 'display_name';

    return $search_columns;
}
add_filter('user_search_columns', 'inc_columns', 10, 3);

Any light that can be shed on why this is would be great.

1
  • I should've mentioned - the search term I know doesn't appear in any of the fields referenced in the meta_query, however, I'd still expect the user to be returned because of it matching other criteria
    – estin92
    Dec 8, 2016 at 11:44

1 Answer 1

3

Combining a meta query with a search for a keyword will return posts which match both the search query and the result of the meta query (even if you're using relation => OR in the meta query).

This answer covers a way to achieve your expected outcome for posts, which – you need to modify the query before it fetches the result. That will need to be modified to be used with a WP User Query however. I've made an attempt at a solution that searches for the search term in the user_nicename, user_email and your meta fields - untested, so might need tweaking.

add_action( 'pre_user_query', 'user_meta_OR_search');
function user_meta_OR_search($q){
    if ($search = $q->get('_meta_or_search')){
        add_filter( 'get_meta_sql', function( $sql ) use ( $search ){
            global $wpdb;

            // Only run once:
            static $nr = 0; 
            if( 0 != $nr++ ) return $sql;

            // Modify WHERE part:
            $where = sprintf(
                " AND ( %s OR %s OR %s ) ",
                $wpdb->prepare( "{$wpdb->users}.user_nicename like '%%%s%%'", $search),
                $wpdb->prepare( "{$wpdb->users}.user_email like '%%%s%%'", $search),
                mb_substr( $sql['where'], 5, mb_strlen( $sql['where'] ) )
            );

            $sql['where'] = $where;

            return $sql;
        });
    }
}

// Then, where you do the searching:
$search_term = "test";

$args = array(
    'fields' => ['ID'],
    'count_total' => true,
    'order' => 'ASC',   
    'orderby' => 'display_name',
    '_meta_or_search' => '*'.esc_attr( $search_term ).'*',
    "meta_query" => array(
        'relation' => 'OR',
        array(
            'key'     => 'first_name',
            'value'   => $search_term,
            'compare' => 'LIKE'
        ),
        array(
            'key'     => 'last_name',
            'value'   => $search_term,
            'compare' => 'LIKE'
              ),
        array(
            'key' => 'description',
            'value' => $search_term ,
            'compare' => 'LIKE'
        )
    )
);

$the_query = new WP_User_Query($args);

Another solution is to use two queries – one which does a general search using s and one searching using meta_query:

$args1 = array (
    'fields' => ['ID'],
    'count_total' => true,
    'order' => 'ASC',   
    'orderby' => 'display_name',
    'search' => '*'.esc_attr( $search_term ).'*'
);

$wp_user_query1 = new WP_User_Query($args1);
$args2 = array (
    'fields' => ['ID'],
    'count_total' => true,
    'order' => 'ASC',   
    'orderby' => 'display_name',
    'meta_query' => array(
        'relation' => 'OR',
        array(
            'key'     => 'first_name',
            'value'   => $search_term,
            'compare' => 'LIKE'
        ),
        array(
            'key'     => 'last_name',
            'value'   => $search_term,
            'compare' => 'LIKE'
        ),
        array(
            'key' => 'description',
            'value' => $search_term ,
            'compare' => 'LIKE'
        )
    )
);
$wp_user_query2 = new WP_User_Query($args2);

$result = new WP_User_Query();
$result->results = array_unique( array_merge( $wp_user_query1->results, $wp_user_query2->results ), SORT_REGULAR );
$result->post_count = count( $result->results );

This will merge the results of the two queries into a third query containing the final search results. I haven't tested this, so it might need some tweaking!

5
  • Thanks, @Emil. Was hoping to avoid running two separate queries and combining the results because of the volume of users on the website and the impact that may/will have on performance. Will try to find a way of achieving the outcome using the link you provided! Cheers :)
    – estin92
    Dec 8, 2016 at 14:02
  • Yeah, that could be a problem. The link I provided replaces the s variable and instead searches directly in the post title, so if you know what fields you want to search in, it shouldn't be too hard to modify the code. I'll give it a go for you as well and edit my answer!
    – Emil
    Dec 8, 2016 at 14:07
  • The updated answer might be helpful!
    – Emil
    Dec 8, 2016 at 14:19
  • Thanks, @Emil. Looks perfect and all makes sense! I'll have a play around with it and let you know what happens. Thanks for your help, appreciate it!
    – estin92
    Dec 8, 2016 at 16:40
  • No problem! If it turns out to have helped you a lot, feel free to mark the answer as accepted by clicking the checkmark ✔ next to it. :)
    – Emil
    Dec 9, 2016 at 8:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.