diff --git a/wp-includes/class-wp-user-query.php b/wp-includes/class-wp-user-query.php index 446cc746fa..c39d4bf552 100644 --- a/wp-includes/class-wp-user-query.php +++ b/wp-includes/class-wp-user-query.php @@ -119,6 +119,7 @@ class WP_User_Query { 'login' => '', 'login__in' => array(), 'login__not_in' => array(), + 'cache_results' => true, ); return wp_parse_args( $args, $defaults ); @@ -140,6 +141,7 @@ class WP_User_Query { * @since 5.1.0 Introduced the 'meta_compare_key' parameter. * @since 5.3.0 Introduced the 'meta_type_key' parameter. * @since 5.9.0 Added 'capability', 'capability__in', and 'capability__not_in' parameters. + * @since 6.3.0 Added 'cache_results' parameter. * * @global wpdb $wpdb WordPress database abstraction object. * @global WP_Roles $wp_roles WordPress role management object. @@ -254,6 +256,7 @@ class WP_User_Query { * logins will be included in results. Default empty array. * @type string[] $login__not_in An array of logins to exclude. Users matching one of these * logins will not be included in results. Default empty array. + * @type bool $cache_results Whether to cache user information. Default true. * } */ public function prepare_query( $query = array() ) { @@ -790,6 +793,11 @@ class WP_User_Query { $qv =& $this->query_vars; + // Do not cache results if more than 3 fields are requested. + if ( is_array( $qv['fields'] ) && count( $qv['fields'] ) > 3 ) { + $qv['cache_results'] = false; + } + /** * Filters the users array before the query takes place. * @@ -816,28 +824,47 @@ class WP_User_Query { {$this->query_orderby} {$this->query_limit} "; - - if ( is_array( $qv['fields'] ) ) { - $this->results = $wpdb->get_results( $this->request ); - } else { - $this->results = $wpdb->get_col( $this->request ); + $cache_value = false; + $cache_key = $this->generate_cache_key( $qv, $this->request ); + $cache_group = 'users-queries'; + if ( $qv['cache_results'] ) { + $cache_value = wp_cache_get( $cache_key, $cache_group ); } + if ( false !== $cache_value ) { + $this->results = $cache_value['user_data']; + $this->total_users = $cache_value['total_users']; + } else { - if ( isset( $qv['count_total'] ) && $qv['count_total'] ) { - /** - * Filters SELECT FOUND_ROWS() query for the current WP_User_Query instance. - * - * @since 3.2.0 - * @since 5.1.0 Added the `$this` parameter. - * - * @global wpdb $wpdb WordPress database abstraction object. - * - * @param string $sql The SELECT FOUND_ROWS() query for the current WP_User_Query. - * @param WP_User_Query $query The current WP_User_Query instance. - */ - $found_users_query = apply_filters( 'found_users_query', 'SELECT FOUND_ROWS()', $this ); + if ( is_array( $qv['fields'] ) ) { + $this->results = $wpdb->get_results( $this->request ); + } else { + $this->results = $wpdb->get_col( $this->request ); + } - $this->total_users = (int) $wpdb->get_var( $found_users_query ); + if ( isset( $qv['count_total'] ) && $qv['count_total'] ) { + /** + * Filters SELECT FOUND_ROWS() query for the current WP_User_Query instance. + * + * @since 3.2.0 + * @since 5.1.0 Added the `$this` parameter. + * + * @global wpdb $wpdb WordPress database abstraction object. + * + * @param string $sql The SELECT FOUND_ROWS() query for the current WP_User_Query. + * @param WP_User_Query $query The current WP_User_Query instance. + */ + $found_users_query = apply_filters( 'found_users_query', 'SELECT FOUND_ROWS()', $this ); + + $this->total_users = (int) $wpdb->get_var( $found_users_query ); + } + + if ( $qv['cache_results'] ) { + $cache_value = array( + 'user_data' => $this->results, + 'total_users' => $this->total_users, + ); + wp_cache_add( $cache_key, $cache_value, $cache_group ); + } } } @@ -1010,6 +1037,54 @@ class WP_User_Query { return $_orderby; } + /** + * Generate cache key. + * + * @since 6.3.0 + * + * @global wpdb $wpdb WordPress database abstraction object. + * + * @param array $args Query arguments. + * @param string $sql SQL statement. + * @return string Cache key. + */ + protected function generate_cache_key( array $args, $sql ) { + global $wpdb; + + // Replace wpdb placeholder in the SQL statement used by the cache key. + $sql = $wpdb->remove_placeholder_escape( $sql ); + + $key = md5( $sql ); + $last_changed = wp_cache_get_last_changed( 'users' ); + + if ( empty( $args['orderby'] ) ) { + // Default order is by 'user_login'. + $ordersby = array( 'user_login' => '' ); + } elseif ( is_array( $args['orderby'] ) ) { + $ordersby = $args['orderby']; + } else { + // 'orderby' values may be a comma- or space-separated list. + $ordersby = preg_split( '/[,\s]+/', $args['orderby'] ); + } + + $blog_id = 0; + if ( isset( $args['blog_id'] ) ) { + $blog_id = absint( $args['blog_id'] ); + } + if ( ( $args['has_published_posts'] && $blog_id ) || in_array( 'post_count', $ordersby, true ) ) { + $switch = get_current_blog_id() !== $blog_id; + if ( $switch ) { + switch_to_blog( $blog_id ); + } + $last_changed .= wp_cache_get_last_changed( 'posts' ); + if ( $switch ) { + restore_current_blog(); + } + } + + return "get_users:$key:$last_changed"; + } + /** * Parses an 'order' query variable and casts it to ASC or DESC as necessary. * diff --git a/wp-includes/default-filters.php b/wp-includes/default-filters.php index beddde2687..92c4c643f9 100644 --- a/wp-includes/default-filters.php +++ b/wp-includes/default-filters.php @@ -115,6 +115,14 @@ add_action( 'added_post_meta', 'wp_cache_set_posts_last_changed' ); add_action( 'updated_post_meta', 'wp_cache_set_posts_last_changed' ); add_action( 'deleted_post_meta', 'wp_cache_set_posts_last_changed' ); +// User meta. +add_action( 'added_user_meta', 'wp_cache_set_users_last_changed' ); +add_action( 'updated_user_meta', 'wp_cache_set_users_last_changed' ); +add_action( 'deleted_user_meta', 'wp_cache_set_users_last_changed' ); +add_action( 'add_user_role', 'wp_cache_set_users_last_changed' ); +add_action( 'set_user_role', 'wp_cache_set_users_last_changed' ); +add_action( 'remove_user_role', 'wp_cache_set_users_last_changed' ); + // Term meta. add_action( 'added_term_meta', 'wp_cache_set_terms_last_changed' ); add_action( 'updated_term_meta', 'wp_cache_set_terms_last_changed' ); diff --git a/wp-includes/load.php b/wp-includes/load.php index 4ad4bad207..6f5a4502c7 100644 --- a/wp-includes/load.php +++ b/wp-includes/load.php @@ -776,6 +776,7 @@ function wp_start_object_cache() { 'usermeta', 'user_meta', 'userslugs', + 'users-queries', ) ); diff --git a/wp-includes/ms-blogs.php b/wp-includes/ms-blogs.php index 0f5ff5d510..e6cfcc2296 100644 --- a/wp-includes/ms-blogs.php +++ b/wp-includes/ms-blogs.php @@ -573,6 +573,7 @@ function switch_to_blog( $new_blog_id, $deprecated = null ) { 'usermeta', 'user_meta', 'userslugs', + 'users-queries', ) ); } @@ -666,6 +667,7 @@ function restore_current_blog() { 'usermeta', 'user_meta', 'userslugs', + 'users-queries', ) ); } diff --git a/wp-includes/ms-functions.php b/wp-includes/ms-functions.php index 9f39266231..3ecbf7691f 100644 --- a/wp-includes/ms-functions.php +++ b/wp-includes/ms-functions.php @@ -295,6 +295,7 @@ function remove_user_from_blog( $user_id, $blog_id = 0, $reassign = 0 ) { } } + clean_user_cache( $user_id ); restore_current_blog(); return true; diff --git a/wp-includes/user.php b/wp-includes/user.php index ee7c87f8a6..7495004d25 100644 --- a/wp-includes/user.php +++ b/wp-includes/user.php @@ -1907,6 +1907,7 @@ function clean_user_cache( $user ) { } wp_cache_delete( $user->ID, 'user_meta' ); + wp_cache_set_users_last_changed(); /** * Fires immediately after the given user's cache is cleaned. @@ -5016,3 +5017,12 @@ function wp_register_persisted_preferences_meta() { ) ); } + +/** + * Sets the last changed time for the 'users' cache group. + * + * @since 6.3.0 + */ +function wp_cache_set_users_last_changed() { + wp_cache_set( 'last_changed', microtime(), 'users' ); +} diff --git a/wp-includes/version.php b/wp-includes/version.php index 953d7eae0d..1f40359f1c 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.3-alpha-55656'; +$wp_version = '6.3-alpha-55657'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.