pre_user_query tutorial: hiding the user with the exact ID, hiding the users by the role, extending the user search
First of all you should know one important moment. There are two base user query action hooks:
pre_get_users
— it fires before WP_User_Query has been parsed and allows you to change some query vars likeinclude
,exclude
,order
,orderby
etc.pre_user_query
fires after the user query has been parsed but before the query is executed. Do you see the difference?
Let’s begin with the base example, just copy the following code to your current theme functions.php
file and open a page with the user list. It can be your administration «Users» page.
add_action( 'pre_user_query', 'rudr_pre_user_query_base_example' );
function rudr_pre_user_query_base_example( $u_query ){
print_r( $u_query );
}
I hope you already know what print_r()
function is.
And one more thing, if your WordPress version is lower that 3.1, the following examples won’t work for you (try to use pre_user_search
instead or update your WordPress).
1. How to completely hide the user with the exact ID from your website.
Okay, this user will not be displayed on the website or inside administration area at all. How to archieve it? With the help of pre_user_query
of course.
add_action('pre_user_query','rudr_completely_hide_user');
function rudr_completely_hide_user( $u_query ) {
// let's allow the hidden user to see himself
$current_user = wp_get_current_user();
if ($current_user->ID != 2) { // the user with ID = 2 for example
global $wpdb;
// just str_replace() the SQL query
$u_query->query_where = str_replace('WHERE 1=1', "WHERE 1=1 AND {$wpdb->users}.ID<>2", $u_query->query_where); // do not forget to change user ID here as well
}
}
- You can move the
if
condition outside the function, like here:$current_user = wp_get_current_user(); if ($current_user->ID != 2) add_action('pre_user_query','rudr_completely_hide_user');
- Nobody could see that user on the website, but please notice that the function don’t change user counts:
Do not worry about that — there are plenty of filters that can help you.
2. How to remove the ability for other users to view administrators in user lists?
It is the more interesting example than the previous one, it based on the same principle, but you can see the complex SQL query in it.
add_action('pre_user_query','rudr_hide_all_administrators');
function rudr_hide_all_administrators( $u_query ) {
// let's do the trick only for non-administrators
$current_user = wp_get_current_user();
if ( $current_user->roles[0] != 'administrator' ) {
global $wpdb;
$u_query->query_where = str_replace(
'WHERE 1=1',
"WHERE 1=1 AND {$wpdb->users}.ID IN (
SELECT {$wpdb->usermeta}.user_id FROM $wpdb->usermeta
WHERE {$wpdb->usermeta}.meta_key = '{$wpdb->prefix}capabilities'
AND {$wpdb->usermeta}.meta_value NOT LIKE '%administrator%')",
$u_query->query_where
);
}
}
Perhaps you know that user roles are stored in wp_usermeta
table (change wp_
to your database prefix) under the wp_capabilities
meta_key. So, in the example above we got all the users which has administrator
word in their wp_capabilities
values.
3. Extend the user search by custom meta_keys from wp_usermeta or custom columns from the other tables.
By default WordPress allows to search users by predefined columns (user_login
, user_email
, user_url
, display_name
, ID
and user_nicename
). You can also use the user_search_columns
filter to exclude some of the predefined columns from the search.
But pre_user_query
allows you to search by a first name, a last name, another user meta key or take wp_posts
table for example and search by post titles, this user has been published.
add_action('pre_user_query','rudr_extend_user_search');
function rudr_extend_user_search( $u_query ){
// make sure that this code will be applied only for user search
if ( $u_query->query_vars['search'] ){
$search_query = trim( $u_query->query_vars['search'], '*' );
if ( $_REQUEST['s'] == $search_query ){
global $wpdb;
// let's search by users first name
$u_query->query_from .= " JOIN {$wpdb->usermeta} fname ON fname.user_id = {$wpdb->users}.ID AND fname.meta_key = 'first_name'";
// you can add here any meta key you want to search by
// $u_query->query_from .= " JOIN {$wpdb->usermeta} cstm ON cstm.user_id = {$wpdb->users}.ID AND cstm.meta_key = 'YOU CUSTOM meta_key'";
// let's search by all the post titles, the user has been published
$u_query->query_from .= " JOIN {$wpdb->posts} psts ON psts.post_author = {$wpdb->users}.ID";
// what fields to include in the search
$search_by = array( 'user_login', 'user_email', 'fname.meta_value', 'psts.post_title' );
// apply to the query
$u_query->query_where = 'WHERE 1=1' . $u_query->get_search_sql( $search_query, $search_by, 'both' );
}
}
}

Misha Rudrastyh
Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.
Need some developer help? Contact me
Hi Misha, thanks for the good tips and explanations!
About the user counts you say:
— “Do not worry about that — there are plenty of filters that can help you”.
Can you mention what are they?
For example: I like to exclude all users of a role in this count.
Hi Henrique,
you could try this:
Thanks for reply! That’s what I need. =]
Just sharing here, may be helpful for someone reading: Now I found in codex, that is a dynamic hook`views_{$this->screen->id}` (https://developer.wordpress.org/reference/hooks/views_this-screen-id).
The better filter to use is “pre_count_users”. This way you can manipulate the counts and not affect the string construction for the output.
In the case of “3. Extend the user search by custom meta_keys from wp_usermeta or custom columns from the other tables”…
Is there any reason why my back-end User search results would now return a list with only two results per paginated page?
That’s the same issue caused when I try the same effect using the plugin Better User Search, https://wordpress.org/plugins/better-user-search/
Hi Robert,
In the Screen Options how much users is set to be displayed per page? 20?
Hi Mischa,
It’s strange…
– Was 150: only two displayed
– When 200: only two displayed
– When 400: four are displayed
– When 500: four are displayed
– When 600: five are displayed
– When 700: six are displayed
– When 800: six are displayed
I’ve stripped out other functions that could be causing a conflict and isolated this code.
Hi Robert,
I am facing the same issue on Multisite. Do you have any update or fix regarding this?
Any help would be great.
Thanks,
I think that there is an error or conflict in your theme or in another plugin which causes this issue. I recommend to try the code:
1) when all plugins are deactivated
2) when you switched to default WP theme.
Let me know please about your results.
I switched to the WordPress standard theme and deactivated all plugins.
But the result is the same.
WordPress 4.8.1 Multisite.
By the way, what is the current code when a custom field is “bio_title”?
I wondered whether the size of the user volume was affecting this, but wp_is_large_network shows the site is not considered large – approx 4.500 users.
:)))))
Why didn’t you begin with it? I mean that you’re running Multisite.
I think it is the reason. I didn’t test it with Multisite and can not provide you more info right now. But I’ve added it to my task list.
Okay :-)
Hi,
Just curious if you ever found a link to effective working with Multisite.
Thanks.
Hey Robert,
Oh, please sorry, I forgot about your issue.. 🙁
Look, I can suggest you to try some things of course, but it would be better and more effective if you contact me by email and send me the website URL + FTP/admin access and I will help you with your website.
Thank you sir! This post saved today.
Thank you sir! Great Tip of excluding the administrator in users list.
Hey Misha, I love your stuff! Always so informative.
I’m trying to integrate your custom meta search and its working great for bringing in custom meta like billing_first_name, etc. But its actually failing to work for plain old first name. I have it set like this below, just like your example:
$u_query->query_from .= ” JOIN {$wpdb->usermeta} fname ON fname.user_id = {$wpdb->users}.ID AND fname.meta_key = ‘first_name'”;
Any thoughts why? Thanks!
Kane
Hey Kane,
Hmmm.. Everything seems ok, I am not sure why it doesn’t work for you.
Ok thanks for the double check! Maybe I’ve got another plugin overriding somewhere. It’s just weird that when I don’t add this script, I can search by billing first name and such, even though I haven’t added this code. But then when I add it, I can still search by billing details but I loose plain old first name. Gotta be something weird, I’ll figure it out. Keep up the good content!