From c758468faf98ecc6ca977774af82d83ee4af13a5 Mon Sep 17 00:00:00 2001 From: Boone Gorges Date: Thu, 8 Oct 2015 21:28:24 +0000 Subject: [PATCH] `WP_User_Query` role improvement redux. It's back, and it's better than ever: an overhaul of role-related arguments in `WP_User_Query`. This updated version of the previously-reverted [34875] includes support for the use of `$blog_id` without specifying a `$role`, for a 99.7% reduced chance of breaking wordpress.org and other large sites. Props boonebgorges, swissspidy. Fixes #22212. Built from https://develop.svn.wordpress.org/trunk@34959 git-svn-id: http://core.svn.wordpress.org/trunk@34924 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/class-wp-user-query.php | 95 ++++++++++++++++++++++++----- wp-includes/version.php | 2 +- 2 files changed, 82 insertions(+), 15 deletions(-) diff --git a/wp-includes/class-wp-user-query.php b/wp-includes/class-wp-user-query.php index 8f06450d55..55b284b1b8 100644 --- a/wp-includes/class-wp-user-query.php +++ b/wp-includes/class-wp-user-query.php @@ -48,7 +48,7 @@ class WP_User_Query { * * @since 4.2.0 * @access public - * @var object WP_Meta_Query + * @var WP_Meta_Query */ public $meta_query = false; @@ -97,6 +97,8 @@ class WP_User_Query { $defaults = array( 'blog_id' => $GLOBALS['blog_id'], 'role' => '', + 'role__in' => array(), + 'role__not_in' => array(), 'meta_key' => '', 'meta_value' => '', 'meta_compare' => '', @@ -126,7 +128,8 @@ class WP_User_Query { * @since 4.2.0 Added 'meta_value_num' support for `$orderby` parameter. Added multi-dimensional array syntax * for `$orderby` parameter. * @since 4.3.0 Added 'has_published_posts' parameter. - * @since 4.4.0 Added 'paged' parameter. + * @since 4.4.0 Added 'paged', 'role__in', and 'role__not_in' parameters. 'role' parameter was updated to + * permit an array or comma-separated list of values. * @access public * * @global wpdb $wpdb @@ -136,7 +139,13 @@ class WP_User_Query { * Optional. Array or string of Query parameters. * * @type int $blog_id The site ID. Default is the global blog id. - * @type string $role Role name. Default empty. + * @type string|array $role An array or a comma-separated list of role names that users must match + * to be included in results. Note that this is an inclusive list: users + * must match *each* role. Default empty. + * @type array $role__in An array of role names. Matched users must have at least one of these + * roles. Default empty array. + * @type array $role__not_in An array of role names to exclude. Users matching one or more of these + * roles will not be included in results. Default empty array. * @type string $meta_key User meta key. Default empty. * @type string $meta_value User meta value. Default empty. * @type string $meta_compare Comparison operator to test the `$meta_value`. Accepts '=', '!=', @@ -268,27 +277,85 @@ class WP_User_Query { $this->meta_query = new WP_Meta_Query(); $this->meta_query->parse_query_vars( $qv ); - $role = ''; + $roles = array(); if ( isset( $qv['role'] ) ) { - $role = trim( $qv['role'] ); + if ( is_array( $qv['role'] ) ) { + $roles = $qv['role']; + } elseif ( is_string( $qv['role'] ) && ! empty( $qv['role'] ) ) { + $roles = array_map( 'trim', explode( ',', $qv['role'] ) ); + } } - if ( $blog_id && ( $role || is_multisite() ) ) { - $cap_meta_query = array(); - $cap_meta_query['key'] = $wpdb->get_blog_prefix( $blog_id ) . 'capabilities'; + $role__in = array(); + if ( isset( $qv['role__in'] ) ) { + $role__in = (array) $qv['role__in']; + } - if ( $role ) { - $cap_meta_query['value'] = '"' . $role . '"'; - $cap_meta_query['compare'] = 'like'; + $role__not_in = array(); + if ( isset( $qv['role__not_in'] ) ) { + $role__not_in = (array) $qv['role__not_in']; + } + + if ( $blog_id && ( ! empty( $roles ) || ! empty( $role__in ) || ! empty( $role__not_in ) || is_multisite() ) ) { + $role_queries = array(); + + $roles_clauses = array( 'relation' => 'AND' ); + if ( ! empty( $roles ) ) { + foreach ( $roles as $role ) { + $roles_clauses[] = array( + 'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities', + 'value' => $role, + 'compare' => 'LIKE', + ); + } + + $role_queries[] = $roles_clauses; } + $role__in_clauses = array( 'relation' => 'OR' ); + if ( ! empty( $role__in ) ) { + foreach ( $role__in as $role ) { + $role__in_clauses[] = array( + 'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities', + 'value' => $role, + 'compare' => 'LIKE', + ); + } + + $role_queries[] = $role__in_clauses; + } + + $role__not_in_clauses = array( 'relation' => 'AND' ); + if ( ! empty( $role__not_in ) ) { + foreach ( $role__not_in as $role ) { + $role__not_in_clauses[] = array( + 'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities', + 'value' => $role, + 'compare' => 'NOT LIKE', + ); + } + + $role_queries[] = $role__not_in_clauses; + } + + // If there are no specific roles named, make sure the user is a member of the site. + if ( empty( $role_queries ) ) { + $role_queries[] = array( + 'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities', + 'compare' => 'EXISTS', + ); + } + + // Specify that role queries should be joined with AND. + $role_queries['relation'] = 'AND'; + if ( empty( $this->meta_query->queries ) ) { - $this->meta_query->queries = array( $cap_meta_query ); - } elseif ( ! in_array( $cap_meta_query, $this->meta_query->queries, true ) ) { + $this->meta_query->queries = $role_queries; + } else { // Append the cap query to the original queries and reparse the query. $this->meta_query->queries = array( 'relation' => 'AND', - array( $this->meta_query->queries, $cap_meta_query ), + array( $this->meta_query->queries, $role_queries ), ); } diff --git a/wp-includes/version.php b/wp-includes/version.php index 4b55a2d42d..d60b002bfa 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -4,7 +4,7 @@ * * @global string $wp_version */ -$wp_version = '4.4-alpha-34958'; +$wp_version = '4.4-alpha-34959'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.