Make WordPress Core

Changeset 55657


Ignore:
Timestamp:
04/18/2023 11:48:46 AM (3 years ago)
Author:
spacedmonkey
Message:

Users: Cache database queries within WP_User_Query class.

Cache the results of database queries within WP_User_Query class. Only cache queries that are requesting 3 or less fields so that caches are not storing full user objects. Cache results are stored in a new global cache group named users-queries. Add a new parameter to WP_User_Query called cache_results to allow developers to opt out of a receiving cached results. cache_results parameter defaults to true. Also add a new helper function called wp_cache_set_users_last_changed, similar to wp_cache_set_posts_last_changed that incroments last changed value in cache group users. Ensure that wp_cache_set_users_last_changed is called whenever user / user meta is modified for proper cache invalidation.

Props johnjamesjacoby, spacedmonkey, westi, dd32, strategio, srikanthmeenakshi, OllieJones, khoipro, rjasdfiii, flixos90, mukesh27, peterwilsoncc.
Fixes #40613.

Location:
trunk
Files:
1 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-user-query.php

    r55654 r55657  
    120120                        'login__in'           => array(),
    121121                        'login__not_in'       => array(),
     122                        'cache_results'       => true,
    122123                );
    123124
     
    141142         * @since 5.3.0 Introduced the 'meta_type_key' parameter.
    142143         * @since 5.9.0 Added 'capability', 'capability__in', and 'capability__not_in' parameters.
     144         * @since 6.3.0 Added 'cache_results' parameter.
    143145         *
    144146         * @global wpdb     $wpdb     WordPress database abstraction object.
     
    255257         *     @type string[]        $login__not_in       An array of logins to exclude. Users matching one of these
    256258         *                                                logins will not be included in results. Default empty array.
     259         *     @type bool            $cache_results       Whether to cache user information. Default true.
    257260         * }
    258261         */
     
    790793
    791794                $qv =& $this->query_vars;
     795
     796                // Do not cache results if more than 3 fields are requested.
     797                if ( is_array( $qv['fields'] ) && count( $qv['fields'] ) > 3 ) {
     798                        $qv['cache_results'] = false;
     799                }
    792800
    793801                /**
     
    817825                                {$this->query_limit}
    818826                        ";
    819 
    820                         if ( is_array( $qv['fields'] ) ) {
    821                                 $this->results = $wpdb->get_results( $this->request );
     827                        $cache_value   = false;
     828                        $cache_key     = $this->generate_cache_key( $qv, $this->request );
     829                        $cache_group   = 'users-queries';
     830                        if ( $qv['cache_results'] ) {
     831                                $cache_value = wp_cache_get( $cache_key, $cache_group );
     832                        }
     833                        if ( false !== $cache_value ) {
     834                                $this->results     = $cache_value['user_data'];
     835                                $this->total_users = $cache_value['total_users'];
    822836                        } else {
    823                                 $this->results = $wpdb->get_col( $this->request );
    824                         }
    825 
    826                         if ( isset( $qv['count_total'] ) && $qv['count_total'] ) {
    827                                 /**
    828                                  * Filters SELECT FOUND_ROWS() query for the current WP_User_Query instance.
    829                                  *
    830                                  * @since 3.2.0
    831                                  * @since 5.1.0 Added the `$this` parameter.
    832                                  *
    833                                  * @global wpdb $wpdb WordPress database abstraction object.
    834                                  *
    835                                  * @param string        $sql   The SELECT FOUND_ROWS() query for the current WP_User_Query.
    836                                  * @param WP_User_Query $query The current WP_User_Query instance.
    837                                  */
    838                                 $found_users_query = apply_filters( 'found_users_query', 'SELECT FOUND_ROWS()', $this );
    839 
    840                                 $this->total_users = (int) $wpdb->get_var( $found_users_query );
     837
     838                                if ( is_array( $qv['fields'] ) ) {
     839                                        $this->results = $wpdb->get_results( $this->request );
     840                                } else {
     841                                        $this->results = $wpdb->get_col( $this->request );
     842                                }
     843
     844                                if ( isset( $qv['count_total'] ) && $qv['count_total'] ) {
     845                                        /**
     846                                         * Filters SELECT FOUND_ROWS() query for the current WP_User_Query instance.
     847                                         *
     848                                         * @since 3.2.0
     849                                         * @since 5.1.0 Added the `$this` parameter.
     850                                         *
     851                                         * @global wpdb $wpdb WordPress database abstraction object.
     852                                         *
     853                                         * @param string        $sql   The SELECT FOUND_ROWS() query for the current WP_User_Query.
     854                                         * @param WP_User_Query $query The current WP_User_Query instance.
     855                                         */
     856                                        $found_users_query = apply_filters( 'found_users_query', 'SELECT FOUND_ROWS()', $this );
     857
     858                                        $this->total_users = (int) $wpdb->get_var( $found_users_query );
     859                                }
     860
     861                                if ( $qv['cache_results'] ) {
     862                                        $cache_value = array(
     863                                                'user_data'   => $this->results,
     864                                                'total_users' => $this->total_users,
     865                                        );
     866                                        wp_cache_add( $cache_key, $cache_value, $cache_group );
     867                                }
    841868                        }
    842869                }
     
    10121039
    10131040        /**
     1041         * Generate cache key.
     1042         *
     1043         * @since 6.3.0
     1044         *
     1045         * @global wpdb $wpdb WordPress database abstraction object.
     1046         *
     1047         * @param array  $args Query arguments.
     1048         * @param string $sql  SQL statement.
     1049         * @return string Cache key.
     1050         */
     1051        protected function generate_cache_key( array $args, $sql ) {
     1052                global $wpdb;
     1053
     1054                // Replace wpdb placeholder in the SQL statement used by the cache key.
     1055                $sql = $wpdb->remove_placeholder_escape( $sql );
     1056
     1057                $key          = md5( $sql );
     1058                $last_changed = wp_cache_get_last_changed( 'users' );
     1059
     1060                if ( empty( $args['orderby'] ) ) {
     1061                        // Default order is by 'user_login'.
     1062                        $ordersby = array( 'user_login' => '' );
     1063                } elseif ( is_array( $args['orderby'] ) ) {
     1064                        $ordersby = $args['orderby'];
     1065                } else {
     1066                        // 'orderby' values may be a comma- or space-separated list.
     1067                        $ordersby = preg_split( '/[,\s]+/', $args['orderby'] );
     1068                }
     1069
     1070                $blog_id = 0;
     1071                if ( isset( $args['blog_id'] ) ) {
     1072                        $blog_id = absint( $args['blog_id'] );
     1073                }
     1074                if ( ( $args['has_published_posts'] && $blog_id ) || in_array( 'post_count', $ordersby, true ) ) {
     1075                        $switch = get_current_blog_id() !== $blog_id;
     1076                        if ( $switch ) {
     1077                                switch_to_blog( $blog_id );
     1078                        }
     1079                        $last_changed .= wp_cache_get_last_changed( 'posts' );
     1080                        if ( $switch ) {
     1081                                restore_current_blog();
     1082                        }
     1083                }
     1084
     1085                return "get_users:$key:$last_changed";
     1086        }
     1087
     1088        /**
    10141089         * Parses an 'order' query variable and casts it to ASC or DESC as necessary.
    10151090         *
  • trunk/src/wp-includes/default-filters.php

    r55620 r55657  
    115115add_action( 'updated_post_meta', 'wp_cache_set_posts_last_changed' );
    116116add_action( 'deleted_post_meta', 'wp_cache_set_posts_last_changed' );
     117
     118// User meta.
     119add_action( 'added_user_meta', 'wp_cache_set_users_last_changed' );
     120add_action( 'updated_user_meta', 'wp_cache_set_users_last_changed' );
     121add_action( 'deleted_user_meta', 'wp_cache_set_users_last_changed' );
     122add_action( 'add_user_role', 'wp_cache_set_users_last_changed' );
     123add_action( 'set_user_role', 'wp_cache_set_users_last_changed' );
     124add_action( 'remove_user_role', 'wp_cache_set_users_last_changed' );
    117125
    118126// Term meta.
  • trunk/src/wp-includes/load.php

    r55652 r55657  
    777777                                'user_meta',
    778778                                'userslugs',
     779                                'users-queries',
    779780                        )
    780781                );
  • trunk/src/wp-includes/ms-blogs.php

    r55537 r55657  
    574574                                                'user_meta',
    575575                                                'userslugs',
     576                                                'users-queries',
    576577                                        )
    577578                                );
     
    667668                                                'user_meta',
    668669                                                'userslugs',
     670                                                'users-queries',
    669671                                        )
    670672                                );
  • trunk/src/wp-includes/ms-functions.php

    r55642 r55657  
    296296        }
    297297
     298        clean_user_cache( $user_id );
    298299        restore_current_blog();
    299300
  • trunk/src/wp-includes/user.php

    r55584 r55657  
    19081908
    19091909        wp_cache_delete( $user->ID, 'user_meta' );
     1910        wp_cache_set_users_last_changed();
    19101911
    19111912        /**
     
    50175018        );
    50185019}
     5020
     5021/**
     5022 * Sets the last changed time for the 'users' cache group.
     5023 *
     5024 * @since 6.3.0
     5025 */
     5026function wp_cache_set_users_last_changed() {
     5027        wp_cache_set( 'last_changed', microtime(), 'users' );
     5028}
  • trunk/tests/phpunit/includes/abstract-testcase.php

    r55537 r55657  
    413413                                'user_meta',
    414414                                'userslugs',
     415                                'users-queries',
    415416                        )
    416417                );
Note: See TracChangeset for help on using the changeset viewer.