Search WordPress Users by Name

If you run a WordPress site with a large list of users and have ever needed to search for a specific user (from the Users > All Users admin page) there’s a good chance no users were found. The problem is that the default query only searches by nicename (username) and email address. However, if you need to search by first name, last name, or a custom user meta field, the default search query is all but useless. Thankfully, the Improved user search in backend plugin fixes this shortcoming, but unfortunately this plugin is outdated and won’t work if you’re running PHP 5.5 and WordPress 3.9 or higher.

So, I’ve gone ahead and created my own user query filter to fix the problem, and included some additional functionality to improve the usefulness of the user search.

<?php

/**
* user_search_by_multiple_parameters
* 
* Modifies the wp_user_query to allow for User searching (within the WordPress dashboard > Users > All Users) by:
*	first_name
*	last_name
*	nickname
*	any other custom meta_key added to user profiles (manually or through something like Advanced Custom Fields)
*
* @param    object  $wp_user_query  a WordPress query object
*
* @return   object	$wp_user_query  a modified version of the WordPress query object parameter
*/
function user_search_by_multiple_parameters($wp_user_query) {
    if (false === strpos($wp_user_query->query_where, '@') && !empty($_GET["s"])) {
        global $wpdb;

        $user_ids = array();
        $user_ids_per_term = array();

		// Usermeta fields to search
		$usermeta_keys = array('first_name', 'last_name', 'nickname');

		$query_string_meta = "";
		$search_terms = $_GET["s"];
		$search_terms_array = explode(' ', $search_terms);
		
		// Search users for each search term (word) individually
		foreach ($search_terms_array as $search_term) {
			// reset ids per loop
			$user_ids_per_term = array();
			
			// add all custom fields into the query
			if (!empty($usermeta_keys)) {
				$query_string_meta = "meta_key='" . implode("' OR meta_key='", $wpdb->escape($usermeta_keys)) . "'";
			}

			// Query usermeta table
            $usermeta_results = $wpdb->get_results($wpdb->prepare("SELECT DISTINCT user_id FROM $wpdb->usermeta WHERE (" . $query_string_meta . ") AND LOWER(meta_value) LIKE '%%%s%%'", $search_term));

            foreach ($usermeta_results as $usermeta_result) {
	            if (!in_array($usermeta_result->user_id, $user_ids_per_term)) {
                	array_push($user_ids_per_term, $usermeta_result->user_id);
                }
            }
			
			// Query users table
            $users_results = $wpdb->get_results($wpdb->prepare("SELECT DISTINCT ID FROM $wpdb->users WHERE LOWER(user_nicename) LIKE '%%%s%%' OR LOWER(user_email) LIKE '%%%s%%' OR LOWER(display_name) LIKE '%%%s%%'", $search_term, $search_term, $search_term));

            foreach ($users_results as $users_result) {
                if (!in_array($users_result->ID, $user_ids_per_term)) {
                    array_push($user_ids_per_term, $users_result->ID);
                }
            }
            
            // Limit results to matches of all search terms
            if (empty($user_ids)) {
	            $user_ids = array_merge($user_ids, $user_ids_per_term);
            } else {
                if (!empty($user_ids_per_term)) {
                    $user_ids = array_unique(array_intersect($user_ids, $user_ids_per_term));
                }
            }
        }
		
		// Convert IDs to comma separated string
        $ids_string = implode(',', $user_ids);

		if (!empty($ids_string)) {
			// network users search (multisite)
			$wp_user_query->query_where = str_replace("user_nicename LIKE '" . $search_terms . "'", "ID IN(" . $ids_string . ")", $wp_user_query->query_where);
			
			// site (blog) users search
            $wp_user_query->query_where = str_replace("user_nicename LIKE '%" . $search_terms . "%'", "ID IN(" . $ids_string . ")", $wp_user_query->query_where);
            
            // network/site users search by number (WordPress assumes user ID number)
            $wp_user_query->query_where = str_replace("ID = '" . $search_terms . "'", "ID = '" . $search_terms . "' OR ID IN(" . $ids_string . ")", $wp_user_query->query_where);
		}
    }

    return $wp_user_query;
}
add_action('pre_user_query', 'user_search_by_multiple_parameters');

?>

 

This can simply be dropped into your theme’s functions.php file, or can be used to create a plugin. It will work as is, but if you have custom user meta fields, possibly added using Advanced Custom Fields, you can simply add the field key to the $usermeta_keys array to include it in the user query.

Join the Conversation

5 Comments

  1. Why would I have got this… ?

    Warning: Cannot modify header information – headers already sent by (output started at /home/mysite/public_html/wp-content/themes/mytheme/functions.php:68) in /home/mysite/public_html/wp-includes/pluggable.php on line 1210

    1. Sorry for the very late reply, my email notifications weren’t coming through. I’m not sure why, without being able to look at your theme’s functions.php. This specific error happens when something has been output to the output buffer (using echo, var_dump, etc) and then an attempt to modify the header is made. Generally it’s just changing the order in which the code is executed, but I’m not sure of the specific problem.

  2. Hi John,
    I can’t seem to get this working at all on Multisite.
    The specific site is a child, blog_id 2.
    Even when I specify only one custom usermeta field name in usermeta_keys (‘geo_city’) and then enter a search term I know to be present, no results are returned.

    With other methods of achieving the same goal, extending User search to custom field (https://wordpress.org/plugins/better-user-search/ & #3 @ https://rudrastyh.com/wordpress/pre_user_query.html), I have experienced a very different problem… the functionality works, they return results, but the listing/pagination is all broken.

    With your method, however, I don’t get any results at all.

    I think Multisite and/or pre_user_query are the culprits, possible in both kinds of scenario.

    Do you have any insights you can share?

    Many thanks.

  3. Hello Laubsterboy,

    Thank you for this 🙂

    I’m having a strange issue in which my custom usermeta ‘member_id’ works perfectly with your code, but ‘first_name’, ‘shipping_first_name’, etc. do not. Those return zero results.

    The only difference I can see is that my custom ‘member_id’ meta value is always a number, whereas the ‘first_name’, ‘shipping_first_name’, etc. are strings. Other than that, everything else is exactly the same between them.

    I’ll keep at it and will post here if I find a solution, but I was wondering if you might have a clue as to what the issue could be. Thanks!

Leave a comment

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

You can also subscribe without commenting.