Make WordPress Core

Changeset 41613


Ignore:
Timestamp:
09/27/2017 01:03:03 PM (6 years ago)
Author:
johnbillion
Message:

Users: Introduce the concept of a large site in order to speed up the Users screen when there are many users.

Calling the count_users() function is expensive, regardless of the counting strategy that's used, and it gets
slower the more users there are on a site. In order to speed up the Users screen in the admin area, calling
count_users() can be avoided entirely while still displaying the total count for users.

This introduces some new functions:

  • wp_is_large_user_count()
  • wp_get_active_user_count()
  • wp_update_active_user_count()

A corresponding wp_is_large_user_count filter is also introduced.

Props tharsheblows, johnbillion

Fixes #38741

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/class-wp-users-list-table.php

    r41180 r41613  
    167167
    168168        $wp_roles = wp_roles();
     169        $count_users = true;
     170
     171        if ( wp_is_large_user_count() ) {
     172            $count_users = false;
     173        } elseif ( is_multisite() && wp_is_large_network( 'users' ) ) {
     174            $count_users = false;
     175        }
    169176
    170177        if ( $this->is_site_users ) {
    171178            $url = 'site-users.php?id=' . $this->site_id;
    172             switch_to_blog( $this->site_id );
    173             $users_of_blog = count_users( 'time', $this->site_id );
    174             restore_current_blog();
     179            if ( $count_users ) {
     180                switch_to_blog( $this->site_id );
     181                $users_of_blog = count_users( 'time', $this->site_id );
     182                restore_current_blog();
     183            }
    175184        } else {
    176185            $url = 'users.php';
    177             $users_of_blog = count_users();
    178         }
    179 
    180         $total_users = $users_of_blog['total_users'];
    181         $avail_roles =& $users_of_blog['avail_roles'];
    182         unset($users_of_blog);
     186            if ( $count_users ) {
     187                $users_of_blog = count_users();
     188            }
     189        }
     190
     191        if ( $count_users ) {
     192            $total_users = $users_of_blog['total_users'];
     193            $avail_roles =& $users_of_blog['avail_roles'];
     194            unset($users_of_blog);
     195        } else {
     196            $avail_roles = array();
     197        }
    183198
    184199        $class = empty($role) ? ' class="current"' : '';
    185200        $role_links = array();
    186         $role_links['all'] = "<a href='$url'$class>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $total_users, 'users' ), number_format_i18n( $total_users ) ) . '</a>';
     201
     202        if ( $count_users ) {
     203            $role_links['all'] = "<a href='$url'$class>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $total_users, 'users' ), number_format_i18n( $total_users ) ) . '</a>';
     204        } else {
     205            $role_links['all'] = "<a href='$url'$class>" . _x( 'All', 'users' ) . '</a>';
     206        }
    187207        foreach ( $wp_roles->get_names() as $this_role => $name ) {
    188             if ( !isset($avail_roles[$this_role]) )
     208            if ( $count_users && !isset($avail_roles[$this_role]) ) {
    189209                continue;
     210            }
    190211
    191212            $class = '';
     
    196217
    197218            $name = translate_user_role( $name );
    198             /* translators: User role name with count */
    199             $name = sprintf( __('%1$s <span class="count">(%2$s)</span>'), $name, number_format_i18n( $avail_roles[$this_role] ) );
     219            if ( $count_users ) {
     220                /* translators: User role name with count */
     221                $name = sprintf( __('%1$s <span class="count">(%2$s)</span>'), $name, number_format_i18n( $avail_roles[$this_role] ) );
     222            }
    200223            $role_links[$this_role] = "<a href='" . esc_url( add_query_arg( 'role', $this_role, $url ) ) . "'$class>$name</a>";
    201224        }
    202225
    203         if ( ! empty( $avail_roles['none' ] ) ) {
     226        if ( ! $count_users || ! empty( $avail_roles['none' ] ) ) {
    204227
    205228            $class = '';
     
    210233
    211234            $name = __( 'No role' );
    212             /* translators: User role name with count */
    213             $name = sprintf( __('%1$s <span class="count">(%2$s)</span>'), $name, number_format_i18n( $avail_roles['none' ] ) );
     235            if ( $count_users ) {
     236                /* translators: User role name with count */
     237                $name = sprintf( __('%1$s <span class="count">(%2$s)</span>'), $name, number_format_i18n( $avail_roles['none' ] ) );
     238            }
    214239            $role_links['none'] = "<a href='" . esc_url( add_query_arg( 'role', 'none', $url ) ) . "'$class>$name</a>";
    215240
  • trunk/src/wp-includes/default-filters.php

    r41361 r41613  
    467467add_action( 'init', 'wp_widgets_init', 1 );
    468468
     469// User counts
     470foreach ( array( 'user_register', 'deleted_user' ) as $action ){
     471    add_action( $action, 'wp_update_active_user_count' );
     472}
     473
    469474// Admin Bar
    470475// Don't remove. Wrong way to disable.
  • trunk/src/wp-includes/functions.php

    r41388 r41613  
    58345834    ), $email_change_email['message'], $email_change_email['headers'] );
    58355835}
     5836
     5837/**
     5838 * Whether or not we have a large site, based on its number of users.
     5839 *
     5840 * The default criteria for a large site is more than 10,000 users.
     5841 *
     5842 * @since 4.9.0
     5843 *
     5844 * @return bool True if the site meets the criteria for large. False otherwise.
     5845 */
     5846function wp_is_large_user_count() {
     5847    $count = wp_get_active_user_count();
     5848
     5849    /**
     5850     * Filters whether the site is considered large, based on its number of users.
     5851     *
     5852     * The default criteria for a large site is more than 10,000 users.
     5853     *
     5854     * @since 4.9.0
     5855     *
     5856     * @param bool $is_large_user_count Whether the site is considered large.
     5857     * @param int  $count               The number of users on the site.
     5858     */
     5859    return apply_filters( 'wp_is_large_user_count', $count > 10000, $count );
     5860}
     5861
     5862/**
     5863 * Update the active user count.
     5864 *
     5865 * @since 4.9.0
     5866 * @global wpdb $wpdb WordPress database abstraction object.
     5867 *
     5868 * @return int The active user count.
     5869 */
     5870function wp_update_active_user_count() {
     5871    global $wpdb;
     5872
     5873    $count = $wpdb->get_var( "
     5874        SELECT COUNT(ID) as c
     5875        FROM {$wpdb->users}
     5876    " );
     5877    $count=12345;
     5878    update_option( 'active_user_count', $count );
     5879
     5880    return (int) $count;
     5881}
     5882
     5883/**
     5884 * The number of active users.
     5885 *
     5886 * @since 4.9.0
     5887 *
     5888 * @return int The active user count.
     5889 */
     5890function wp_get_active_user_count() {
     5891    $count = get_option( 'active_user_count', false );
     5892
     5893    if ( false === $count ) {
     5894        $count = wp_update_active_user_count();
     5895    }
     5896    return (int) $count;
     5897}
  • trunk/src/wp-includes/ms-functions.php

    r41596 r41613  
    25542554    if ( 'users' == $using ) {
    25552555        $count = get_user_count( $network_id );
     2556        $is_large = ( $count > 10000 );
     2557
     2558        /** This filter is documented in wp-includes/functions.php */
     2559        $is_large = apply_filters( 'wp_is_large_user_count', $is_large, $count );
     2560
    25562561        /**
    25572562         * Filters whether the network is considered large.
     
    25652570         * @param int    $network_id       The ID of the network being checked.
    25662571         */
    2567         return apply_filters( 'wp_is_large_network', $count > 10000, 'users', $count, $network_id );
     2572        return apply_filters( 'wp_is_large_network', $is_large, 'users', $count, $network_id );
    25682573    }
    25692574
  • trunk/src/wp-includes/update.php

    r41605 r41613  
    7979        $multisite_enabled = 1;
    8080    } else {
    81         $user_count = count_users();
    82         $user_count = $user_count['total_users'];
     81        $user_count = wp_get_active_user_count();
    8382        $multisite_enabled = 0;
    8483        $num_blogs = 1;
  • trunk/tests/phpunit/tests/functions.php

    r41388 r41613  
    11611161        return $data;
    11621162    }
     1163
     1164    /**
     1165     * @ticket 38741
     1166     */
     1167    public function test_wp_get_active_user_count() {
     1168        $user_count = wp_get_active_user_count();
     1169        $this->assertSame( $user_count, 1 );
     1170
     1171        // make twenty additional users to make 21 users
     1172        self::factory()->user->create_many( 20 );
     1173
     1174        $user_count = wp_get_active_user_count();
     1175        $this->assertSame( $user_count, 21 );
     1176    }
     1177
     1178    /**
     1179     * @ticket 38741
     1180     */
     1181    public function test_wp_get_active_user_count_caching() {
     1182        global $wpdb;
     1183
     1184        // Ensure we start with 1 user
     1185        $user_count = wp_get_active_user_count();
     1186        $this->assertSame( $user_count, 1 );
     1187
     1188        self::factory()->user->create();
     1189
     1190        delete_option( 'active_user_count' );
     1191
     1192        // Ensure we now have 2 users
     1193        $user_count = wp_get_active_user_count();
     1194        $this->assertSame( $user_count, 2 );
     1195
     1196        $queries = $wpdb->num_queries;
     1197
     1198        // Ensure that caching inside wp_get_active_user_count() works as expected
     1199        $user_count = wp_get_active_user_count();
     1200        $this->assertSame( $user_count, 2 );
     1201        $this->assertSame( $queries, $wpdb->num_queries );
     1202    }
     1203
     1204    /**
     1205     * @ticket 38741
     1206     */
     1207    public function test_wp_is_large_user_count() {
     1208        // set the 'active_user_count' value to over 10000 to emulate a large site
     1209        update_option( 'active_user_count', 10001 );
     1210        $user_count = wp_get_active_user_count();
     1211        $this->assertSame( $user_count, 10001 );
     1212        $this->assertTrue( wp_is_large_user_count() );
     1213
     1214        delete_option( 'active_user_count' );
     1215        $this->assertFalse( wp_is_large_user_count() );
     1216    }
    11631217}
Note: See TracChangeset for help on using the changeset viewer.