Make WordPress Core

Opened 9 years ago

Last modified 8 weeks ago

#31383 new feature request

Add WP_Tax_Query support to WP_User_Query

Reported by: desrosj's profile desrosj Owned by:
Milestone: Future Release Priority: normal
Severity: normal Version: 4.2
Component: Query Keywords:
Focuses: Cc:


Users like any other object type in WordPress can have taxonomy terms assigned to them. However, there is currently no way to query by taxonomies in WP_User_Query.

As far as I could find, the only way to really accomplish this right now is to use get_objects_in_term(), filter out the non user objects, and then use the include parameter.

Ideally, I think you should be able to accomplish this by the following:

$user_query = new WP_User_Query( array(
	'tax_query' => array(
			'taxonomy' => 'tax_name',
			'field' => 'slug',
			'terms' => array( 'term-1', 'term-2' ),
) );

Attachments (2)

User WP_Tax_Query support.patch (3.4 KB) - added by desrosj 9 years ago.
First pass.
31383.diff (9.1 KB) - added by desrosj 7 years ago.
Applies WP_Tax_Query support to WP_User_Query, no UX.

Download all attachments as: .zip

Change History (19)

#1 follow-up: @boonebgorges
9 years ago

  • Milestone changed from Awaiting Review to Future Release

This would be easy to add, but I'm somewhat wary. It's possible to assign taxonomies and terms to users, but there's no explicit support for that in the system - you kinda have to hack it. Adding a 'tax_query' parameter would be like an official endorsement for user taxonomies, without actually having them fully implemented.

Maybe we can use this ticket to think about some of the core changes that would be necessary to introduce minimal support for user taxonomies. Off the top of my head:

  • When you register a taxonomy with 'user' as the object type, the taxonomy's UI should appear under the 'Users' menu in the Dashboard
  • We should examine whether we need a user-specific generic 'update_count_callback', along the lines of '_update_post_term_count()' for post types. (I think we probably would, because we'd want, eg, spammed users to be excluded from term counts.)
  • Built-in UI for managing user tax terms on profile.php (maybe?)
  • Built-in support for user taxonomy archives. So would show a list of users with the 'foo' term in the 'user_tax' taxonomy. (another maybe - not sure if this is desirable in core, or necessary for a first pass)

#2 in reply to: ↑ 1 @desrosj
9 years ago

Replying to boonebgorges:

  • When you register a taxonomy with 'user' as the object type, the taxonomy's UI should appear under the 'Users' menu in the Dashboard
  • We should examine whether we need a user-specific generic 'update_count_callback', along the lines of '_update_post_term_count()' for post types. (I think we probably would, because we'd want, eg, spammed users to be excluded from term counts.)

I agree with both of these. Definitely would need this for a round one.

  • Built-in UI for managing user tax terms on profile.php (maybe?)

We would have to consider the differences between hierarchical and non-hierarchical taxonomies. Could potentially be two different interfaces like categories and tags, but I like putting it on profile.php.

Another thing to consider is additions to the users.php page.

  • Adding a column for the taxonomy based on 'show_admin_column' argument.
  • Whether to add dropdown filters.

I can take a first stab at this if you think it has potential for good direction.

#3 follow-up: @boonebgorges
9 years ago

  • Keywords needs-patch added

Cool - this sounds good, desrosj.

I'm positive that this has been mentioned in past Trac tickets, but I'm having a hard time finding it. I'd say that, before starting anything, it's a good idea to do some ticket archaeology. If past discussions have taken place on the subject of user taxonomies, it'd be good to read them over first. I know that there are also some existing plugins that add user taxonomies, so it may be a good idea to look them over - if not for the purposes of reusing code, then at least for studying the parts of the taxonomy API they've seen fit to replicate/build out for user taxonomies.

Regarding patching: let's start very modest. I think that the first two bullet points that you've outlined are probably the absolute minimum that would be required to justify a 'tax_query' param in WP_User_Query. Maybe best to start with those? The profile.php bit, theme template support, and your users.php suggestions are probably not required for a first pass, and may even be best in a plugin (especially the dropdown filters - we don't even offer this with posts). 'show_admin_column' support would be pretty nice, though, and would give good parity with post taxonomies.

#4 @desrosj
9 years ago


I did some digging too, but couldn't find anything either. I couldn't believe there wasn't a ticket for this already though, so I will keep looking.

For the dropdown filters, #23422 is relevant. If that gets added, we could revisit that aspect down the road.

#5 in reply to: ↑ 3 @SergeyBiryukov
9 years ago

Replying to boonebgorges:

I'm positive that this has been mentioned in past Trac tickets, but I'm having a hard time finding it.

Related: #23045

#6 @boonebgorges
9 years ago

#31512 was marked as a duplicate.

9 years ago

First pass.

#7 @desrosj
9 years ago

Patch above accomplishes the following:

  • Shows menu items for taxonomies registered to users linking to a taxonomy management screen.
  • Allows the 'tax_query' parameter to be passed in a WP_User_Query the same as WP_Query calls.
  • Parses a url with a taxonomy's query_var populated into a query (using slugs).

Still have a checklist of what remains, but wanted to post something to show some progress and get feedback. I think the actual query aspect of things is in great shape.

Remaining items:

  • Menu items for taxonomies still need to be selected when on the respective pages.
  • Taxonomy management screens need to link to the user screen instead of posts.
  • Provide a way for terms to be applied to a user.
  • A user-specific generic 'update_count_callback', along the lines of '_update_post_term_count()' for post types.
  • Show a column in the admin when show_admin_column is set to true.

Below is a quick example of what we could do on the user edit screen.

#8 @chrisvanpatten
8 years ago

I'm working on a project that would really benefit from being able to do tax queries on users. There are other ways (with user meta) that could accomplish the same thing, but a tax query would be much easier/more efficient/easier to grok.

Would a refreshed patch be the best way to kick this off, with the aim to get this into 4.7?

Version 0, edited 8 years ago by chrisvanpatten (next)

#9 @boonebgorges
8 years ago

#37256 was marked as a duplicate.

#10 @boonebgorges
8 years ago

@desrosj Thanks for your patch on this ticket, and apologies for letting it fall through the cracks. Your patch is a useful starting point.

@chrisvanpatten asks:

Also, what would be the minimum 'scope of work' on this ticket? Should we just aim to get tax_query in, and then leave UX concerns (taxonomies showing up in the Users menu, edit fields on the User page, etc.) to a future/separate ticket?

This is a great question. I definitely think that 'tax_query' support can be worked on as a standalone patch. (More on WP_Tax_Query support.patch in a moment.) In a pinch, I think we could put 'tax_query' support into a release without any user-facing UX.

That said, I think it would make for a more compelling feature if we could flesh out some of the UX stuff as part of a single release. The operating slogan is, I think, something like this: "If my plugin registers a taxonomy with object type 'user', it should feel like a native part of WP." Obviously, there's some room for interpretation regarding what that means. But I'd say that, at a minimum, it covers the first two items I mentioned in my first comment: admin menu placement and a better fallback for 'update_count_callback'. (The latter is not strictly user-facing, but it does determine the counts that are shown to users.) These two features, plus 'tax_query' in WP_User_Query, seem like a pretty good first pass.

A good next step is a refresh of WP_Tax_Query support.patch. Here are some notes:

  • parse_tax_query() doesn't check to see whether the requested taxonomies are assigned to the 'user' object. Should it? We don't currently do this elsewhere with 'tax_query' - for example, in WP_Query we don't check to see whether the taxonomies match post_type, even though taxonomies are registered against a post_type object. But the potential for confusion rises if we're providing more "official" support for user taxonomies. Here's a way to frame the issue: are we likely to confuse developers if we allow (ie, don't throw errors for) queries like get_users( ... 'tax_query' => ... 'taxonomy=post_tag' )? Or get_posts( ... 'tax_query' => ... 'taxonomy=some_user_taxonomy' )? Or maybe these queries will just always end up empty? We should think through the possible confusions (or, maybe, lack thereof).
  • It looks like the URL parsing ($t->query_var etc) is copied from WP_Query. WP_Query is responsible for the main query, which involves parsing query vars from the URL. WP_User_Query doesn't currently do this, so I think we don't need URL support here. If we introduce user-tax archives, we might consider it - but this is a way off (we don't currently have *any* front-end listings of users built into our theme hierarchy).
  • We'll need inline docs and unit tests.

Thanks for your interest in the ticket! It would be wonderful to see the project move forward.

#11 @desrosj
7 years ago

Incoming updated patch that will apply cleanly to trunk. This patch adds taxonomy query support to user queries with no UX. It includes a few new unit tests, but since this is the first time writing unit tests, I probably missed a bunch.

While refreshing the patch, I realized that there is one main issue we will need to solve in order to make this feature work. Term relationships are based on object IDs. But currently, the object ID is always assumed to be a post. This is an issue because users can have the same ID as posts since they are stored in separate tables. Without addressing this issue, taxonomy support for users can not be added for taxonomies that are not exclusive to users.

Example: if there is a post with an ID of 3, and a user with an ID of 3, calling wp_set_object_terms() will assign the term to both, regardless of the intent.

#38265 was recently opened, and this could be one potential way to fix the issue. Not sure if there are any other ideas how to accomplish this without altering tables.

7 years ago

Applies WP_Tax_Query support to WP_User_Query, no UX.

#12 @Qwindoo
7 years ago


I need taxonomy query support for user queries as well. The patch seems great, however it is not ideal because of the issue mentioned by @desrosj : terms are currently assigned to all objects and there's no non-hackish way of assigning a term to a specific object type.

The cleanest way to fix this seems to be adding a new object_type column in term_relationships, alongside object_id. This would allow us to cleanly distinguish between post-to-term, user-to-term and any other future relationships we might want to support. Functions like wp_set_object_terms could accept an additional argument $object_type, defaulting to post in order to preserve existing functionality.

With this change in place, even without adding the UX stuff, being able to assign terms to users and only users and then to query users based on these terms seems a compelling enough feature to me.

Is there a specific workflow in place to request and discuss such a database schema change?

#13 @boonebgorges
7 years ago

Hi @Qwindoo - #37686 is an existing ticket for what you've proposed.

Without addressing this issue, taxonomy support for users can not be added for taxonomies that are not exclusive to users.

Correct. You can share a taxonomy between post types, but not between object types.

@desrosj Thanks for the refreshed patch. Why the hardcoded if ( 'user' != ... checks in register_taxonomy_for_object_type()? It seems to me that the restriction described above - the fact that taxonomies cannot be shared across multiple object types - will require that we lean heavily on a taxonomy's registered object_type.

#14 @drewcovi
6 years ago

Any chance we can close on this? are we waiting on a response from @desrosj ?

#15 @ejdanderson
4 years ago

  • Keywords needs-patch removed

Would love to see some movement on this, likely needs a new patch?

#16 @mirkolofio
10 months ago

Hey. What if we try to separate things like:

  • patch for the needed fixed into core to full support the user taxonomies
  • feature plugin to create the first proof of concept working feature

There are some usable attempts around like:

Old, poorly supported and a bit raw. But real world working examples.

#17 @rafasashi
8 weeks ago

This is how I implement taxonomy for WP_User_Query but I wish it was simpler...

First set tax_query via pre_get_users the same way you would usually do for Posts:

add_filter( 'pre_get_users', function($query){

	return $query;


This will store the tax query in $query->query_vars

Now you can modify the query via users_pre_query

add_filter( 'users_pre_query', function($results,$query){

	if( !empty($query->query_vars['tax_query']) ){
		global $wpdb;
		$qv =& $query->query_vars;
		if ( is_array( $qv['fields'] ) && count( $qv['fields'] ) > 3 ) {
			$qv['cache_results'] = false;

		$tax_query_sql = get_tax_sql($query->query_vars['tax_query'], $wpdb->users, 'ID');			
		$query->request = "
			SELECT {$query->query_fields}
		$cache_value   = false;
		$cache_key     = $query->generate_cache_key( $qv, $query->request );
		$cache_group   = 'user-queries';
		if ( $qv['cache_results'] ) {
			$cache_value = wp_cache_get( $cache_key, $cache_group );
		if ( false !== $cache_value ) {
			$query->results     = $cache_value['user_data'];
			$query->total_users = $cache_value['total_users'];
		else {

			if( is_array( $qv['fields'] ) ) {
				$query->results = $wpdb->get_results( $query->request );
				$query->results = $wpdb->get_col( $query->request );

			if ( isset( $qv['count_total'] ) && $qv['count_total'] ) {

				$found_users_query = apply_filters( 'found_users_query', 'SELECT FOUND_ROWS()', $query );

				$query->total_users = (int) $wpdb->get_var( $found_users_query );

			if ( $qv['cache_results'] ) {
				$cache_value = array(
					'user_data'   => $query->results,
					'total_users' => $query->total_users,
				wp_cache_add( $cache_key, $cache_value, $cache_group );
		return $query->results;
	return $results;


What about adding get_tax_sql() somewhere bellow?

Note: See TracTickets for help on using tickets.