Make WordPress Core

Changeset 55657


Ignore:
Timestamp:
04/18/2023 11:48:46 AM (19 months 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.