Instantly share code, notes, and snippets.

Embed
What would you like to do?
Improving `count_users` performance on large sites
diff --git a/wp-admin/includes/class-wp-ms-users-list-table.php b/wp-admin/includes/class-wp-ms-users-list-table.php
index c2216f6..c4358db 100644
--- a/wp-admin/includes/class-wp-ms-users-list-table.php
+++ b/wp-admin/includes/class-wp-ms-users-list-table.php
@@ -130,7 +130,7 @@ class WP_MS_Users_List_Table extends WP_List_Table {
protected function get_views() {
global $role;
- $total_users = get_user_count();
+ $total_users = wp_get_user_count();
$super_admins = get_super_admins();
$total_admins = count( $super_admins );
diff --git a/wp-admin/includes/class-wp-posts-list-table.php b/wp-admin/includes/class-wp-posts-list-table.php
index 5988c3e..a181ac1 100644
--- a/wp-admin/includes/class-wp-posts-list-table.php
+++ b/wp-admin/includes/class-wp-posts-list-table.php
@@ -1429,7 +1429,7 @@ class WP_Posts_List_Table extends WP_List_Table {
<br class="clear" />
<?php endif; // $bulk
- if ( post_type_supports( $screen->post_type, 'author' ) ) :
+ if ( post_type_supports( $screen->post_type, 'author' ) && ! wp_is_large_user_count() ) :
$authors_dropdown = '';
if ( current_user_can( $post_type_object->cap->edit_others_posts ) ) :
diff --git a/wp-admin/includes/class-wp-users-list-table.php b/wp-admin/includes/class-wp-users-list-table.php
index 8dd5793..33b79de 100644
--- a/wp-admin/includes/class-wp-users-list-table.php
+++ b/wp-admin/includes/class-wp-users-list-table.php
@@ -167,26 +167,37 @@ class WP_Users_List_Table extends WP_List_Table {
$wp_roles = wp_roles();
+ $count_users = ! wp_is_large_user_count();
+
if ( $this->is_site_users ) {
$url = 'site-users.php?id=' . $this->site_id;
- switch_to_blog( $this->site_id );
- $users_of_blog = count_users( 'time', $this->site_id );
- restore_current_blog();
} else {
$url = 'users.php';
- $users_of_blog = count_users();
}
- $total_users = $users_of_blog['total_users'];
- $avail_roles =& $users_of_blog['avail_roles'];
- unset($users_of_blog);
+ $role_links = array();
+ if ( $count_users ) {
+ if ( $this->is_site_users ) {
+ switch_to_blog( $this->site_id );
+ $users_of_blog = count_users( 'time', $this->site_id );
+ restore_current_blog();
+ } else {
+ $users_of_blog = count_users();
+ }
+
+ $total_users = $users_of_blog['total_users'];
+ $avail_roles =& $users_of_blog['avail_roles'];
+ unset( $users_of_blog );
+ $role_links['all'] = "<a href='$url'$current_link_attributes>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $total_users, 'users' ), number_format_i18n( $total_users ) ) . '</a>';
+ } else {
+ $avail_roles = array();
+ $role_links['all'] = "<a href='$url'$current_link_attributes>" . __( 'All' ) . '</a>';
+ }
$current_link_attributes = empty( $role ) ? ' class="current" aria-current="page"' : '';
- $role_links = array();
- $role_links['all'] = "<a href='$url'$current_link_attributes>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $total_users, 'users' ), number_format_i18n( $total_users ) ) . '</a>';
foreach ( $wp_roles->get_names() as $this_role => $name ) {
- if ( !isset($avail_roles[$this_role]) )
+ if ( $count_users && ! isset( $avail_roles[$this_role] ) )
continue;
$current_link_attributes = '';
@@ -196,8 +207,10 @@ class WP_Users_List_Table extends WP_List_Table {
}
$name = translate_user_role( $name );
- /* translators: User role name with count */
- $name = sprintf( __('%1$s <span class="count">(%2$s)</span>'), $name, number_format_i18n( $avail_roles[$this_role] ) );
+ if ( $count_users ) {
+ /* translators: User role name with count */
+ $name = sprintf( __( '%1$s <span class="count">(%2$s)</span>' ), $name, number_format_i18n( $avail_roles[ $this_role ] ) );
+ }
$role_links[$this_role] = "<a href='" . esc_url( add_query_arg( 'role', $this_role, $url ) ) . "'$current_link_attributes>$name</a>";
}
diff --git a/wp-admin/includes/dashboard.php b/wp-admin/includes/dashboard.php
index fa1d2ff..5ae9456 100644
--- a/wp-admin/includes/dashboard.php
+++ b/wp-admin/includes/dashboard.php
@@ -389,7 +389,7 @@ function wp_network_dashboard_right_now() {
if ( current_user_can('create_users') )
$actions['create-user'] = '<a href="' . network_admin_url('user-new.php') . '">' . __( 'Create a New User' ) . '</a>';
- $c_users = get_user_count();
+ $c_users = wp_get_user_count();
$c_blogs = get_blog_count();
/* translators: %s: number of users on the network */
diff --git a/wp-admin/includes/schema.php b/wp-admin/includes/schema.php
index 2d048ef..fc4dad4 100644
--- a/wp-admin/includes/schema.php
+++ b/wp-admin/includes/schema.php
@@ -1009,6 +1009,7 @@ We hope you enjoy your new site. Thanks!
'upload_space_check_disabled' => is_multisite() ? get_site_option( 'upload_space_check_disabled' ) : '1',
'subdomain_install' => intval( $subdomain_install ),
'global_terms_enabled' => global_terms_enabled() ? '1' : '0',
+ 'user_count' => get_site_option( 'user_count' ),
'ms_files_rewriting' => is_multisite() ? get_site_option( 'ms_files_rewriting' ) : '0',
'initial_db_version' => get_option( 'initial_db_version' ),
'active_sitewide_plugins' => array(),
diff --git a/wp-includes/default-filters.php b/wp-includes/default-filters.php
index e012beb..d0df558 100644
--- a/wp-includes/default-filters.php
+++ b/wp-includes/default-filters.php
@@ -89,6 +89,13 @@ add_filter( 'post_mime_type', 'sanitize_mime_type' );
// Meta
add_filter( 'register_meta_args', '_wp_register_meta_args_whitelist', 10, 2 );
+// Counts
+add_action( 'admin_init', 'wp_schedule_update_network_counts' );
+add_action( 'update_network_counts', 'wp_update_network_user_counts', 10, 0 );
+foreach ( array( 'user_register', 'deleted_user', 'wpmu_new_user', 'make_spam_user', 'make_ham_user' ) as $action ) {
+ add_action( $action, 'wp_maybe_update_network_user_counts', 10, 0 );
+}
+
// Places to balance tags on input
foreach ( array( 'content_save_pre', 'excerpt_save_pre', 'comment_save_pre', 'pre_comment_content' ) as $filter ) {
add_filter( $filter, 'convert_invalid_entities' );
diff --git a/wp-includes/functions.php b/wp-includes/functions.php
index 5802a34..6da50b2 100644
--- a/wp-includes/functions.php
+++ b/wp-includes/functions.php
@@ -6069,3 +6069,111 @@ function wp_privacy_delete_old_export_files() {
}
}
}
+
+/**
+ * The number of active users in your installation.
+ *
+ * The count is cached and updated twice daily. This is not a live count.
+ *
+ * @since 5.0.0
+ *
+ * @return int Number of active users on the network.
+ */
+function wp_get_user_count() {
+ return get_site_option( 'user_count', -1 );
+}
+
+/**
+ * Update the network-wide users count.
+ *
+ * If enabled through the {@see 'enable_live_network_counts'} filter, update the users count
+ * on a network when a user is created or its status is updated.
+ *
+ * @since 3.7.0
+ * @since 4.8.0 The `$network_id` parameter has been added.
+ * @since 5.0.0 Moved to functions.php
+ *
+ * @param int|null $network_id ID of the network. Default is the current network.
+ *
+ * @return bool
+ */
+function wp_maybe_update_network_user_counts( $network_id = null ) {
+ $is_small_network = ! wp_is_large_user_count();
+
+ if ( ! is_multisite() && $network_id ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Unable to pass $nework_id if not using multisite.' ), '5.0.0' );
+ }
+
+ /** This filter is documented in wp-includes/ms-functions.php */
+ if ( ! apply_filters( 'enable_live_network_counts', $is_small_network, 'users' ) ) {
+ return;
+ }
+
+ return wp_update_network_user_counts( $network_id );
+}
+
+/**
+ * Update the network-wide user count.
+ *
+ * @since 3.7.0
+ * @since 4.8.0 The `$network_id` parameter has been added.
+ * @since 5.0.0 Moved to functions.php
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int|null $network_id ID of the network. Default is the current network.
+ *
+ * @return bool
+ */
+function wp_update_network_user_counts( $network_id = null ) {
+ global $wpdb;
+
+ if ( ! is_multisite() && $network_id ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Unable to pass $nework_id if not using multisite.' ), '5.0.0' );
+ }
+
+ if ( is_multisite() ) {
+ $query = "SELECT COUNT(ID) as c FROM $wpdb->users WHERE spam = '0' AND deleted = '0'";
+ } else {
+ $query = "SELECT COUNT(ID) as c FROM $wpdb->users";
+ }
+
+ $count = $wpdb->get_var( $query );
+
+ return update_network_option( $network_id, 'user_count', $count );
+}
+
+/**
+ * Schedule update of the network-wide counts for the current network.
+ *
+ * @since 3.1.0
+ * @since 5.0.0 Moved to functions.php
+ */
+function wp_schedule_update_network_counts() {
+ if ( ! is_main_site() ) {
+ return;
+ }
+
+ if ( ! wp_next_scheduled( 'update_network_counts' ) && ! wp_installing() ) {
+ wp_schedule_event( time(), 'twicedaily', 'update_network_counts' );
+ }
+}
+
+/**
+ * @since 5.0.0
+ *
+ * @return boolean
+ */
+function wp_is_large_user_count() {
+ $count = wp_get_user_count();
+
+ /**
+ * Filters whether the site is considered large, based on its number of users.
+ *
+ * @since x.x.x
+ *
+ * @param bool $is_large_user_count Whether the site has more than 10000 users.
+ * @param int $count The count of items for the component.
+ */
+ return apply_filters( 'wp_is_large_user_count', $count > 10000, $count );
+}
diff --git a/wp-includes/ms-default-filters.php b/wp-includes/ms-default-filters.php
index fe66f0a..95adb38 100644
--- a/wp-includes/ms-default-filters.php
+++ b/wp-includes/ms-default-filters.php
@@ -57,10 +57,7 @@ add_action( 'transition_post_status', '_update_blog_date_on_post_publish', 10, 3
add_action( 'transition_post_status', '_update_posts_count_on_transition_post_status', 10, 3 );
// Counts
-add_action( 'admin_init', 'wp_schedule_update_network_counts');
-add_action( 'update_network_counts', 'wp_update_network_counts', 10, 0 );
-foreach ( array( 'user_register', 'deleted_user', 'wpmu_new_user', 'make_spam_user', 'make_ham_user' ) as $action )
- add_action( $action, 'wp_maybe_update_network_user_counts', 10, 0 );
+add_action( 'update_network_counts', 'wp_update_network_site_counts', 10, 0 );
foreach ( array( 'make_spam_blog', 'make_ham_blog', 'archive_blog', 'unarchive_blog', 'make_delete_blog', 'make_undelete_blog' ) as $action )
add_action( $action, 'wp_maybe_update_network_site_counts', 10, 0 );
unset( $action );
diff --git a/wp-includes/ms-deprecated.php b/wp-includes/ms-deprecated.php
index e1f9176..bcfa472 100644
--- a/wp-includes/ms-deprecated.php
+++ b/wp-includes/ms-deprecated.php
@@ -546,3 +546,20 @@ function is_user_option_local( $key, $user_id = 0, $blog_id = 0 ) {
return isset( $current_user->$local_key );
}
+
+/**
+ * The number of active users in your installation.
+ *
+ * The count is cached and updated twice daily. This is not a live count.
+ *
+ * @since MU (3.0.0)
+ * @since 4.8.0 The `$network_id` parameter has been added.
+ * @deprecated 4.9.0
+ *
+ * @param int|null $network_id ID of the network. Default is the current network.
+ * @return int Number of active users on the network.
+ */
+function get_user_count( $network_id = null ) {
+ _deprecated_function( __FUNCTION__, '5.0.0', 'wp_get_user_count()' );
+ return get_network_option( $network_id, 'user_count' );
+}
diff --git a/wp-includes/ms-functions.php b/wp-includes/ms-functions.php
index 2289ad3..d083b87 100644
--- a/wp-includes/ms-functions.php
+++ b/wp-includes/ms-functions.php
@@ -17,7 +17,7 @@
function get_sitestats() {
$stats = array(
'blogs' => get_blog_count(),
- 'users' => get_user_count(),
+ 'users' => wp_get_user_count(),
);
return $stats;
@@ -91,21 +91,6 @@ function get_active_blog_for_user( $user_id ) {
}
}
-/**
- * The number of active users in your installation.
- *
- * The count is cached and updated twice daily. This is not a live count.
- *
- * @since MU (3.0.0)
- * @since 4.8.0 The $network_id parameter has been added.
- *
- * @param int|null $network_id ID of the network. Default is the current network.
- * @return int Number of active users on the network.
- */
-function get_user_count( $network_id = null ) {
- return get_network_option( $network_id, 'user_count' );
-}
-
/**
* The number of active sites on your installation.
*
@@ -2286,19 +2271,6 @@ function filter_SSL( $url ) {
return $url;
}
-/**
- * Schedule update of the network-wide counts for the current network.
- *
- * @since 3.1.0
- */
-function wp_schedule_update_network_counts() {
- if ( !is_main_site() )
- return;
-
- if ( ! wp_next_scheduled('update_network_counts') && ! wp_installing() )
- wp_schedule_event(time(), 'twicedaily', 'update_network_counts');
-}
-
/**
* Update the network-wide counts for the current network.
*
@@ -2312,57 +2284,6 @@ function wp_update_network_counts( $network_id = null ) {
wp_update_network_site_counts( $network_id );
}
-/**
- * Update the count of sites for the current network.
- *
- * If enabled through the {@see 'enable_live_network_counts'} filter, update the sites count
- * on a network when a site is created or its status is updated.
- *
- * @since 3.7.0
- * @since 4.8.0 The $network_id parameter has been added.
- *
- * @param int|null $network_id ID of the network. Default is the current network.
- */
-function wp_maybe_update_network_site_counts( $network_id = null ) {
- $is_small_network = ! wp_is_large_network( 'sites', $network_id );
-
- /**
- * Filters whether to update network site or user counts when a new site is created.
- *
- * @since 3.7.0
- *
- * @see wp_is_large_network()
- *
- * @param bool $small_network Whether the network is considered small.
- * @param string $context Context. Either 'users' or 'sites'.
- */
- if ( ! apply_filters( 'enable_live_network_counts', $is_small_network, 'sites' ) )
- return;
-
- wp_update_network_site_counts( $network_id );
-}
-
-/**
- * Update the network-wide users count.
- *
- * If enabled through the {@see 'enable_live_network_counts'} filter, update the users count
- * on a network when a user is created or its status is updated.
- *
- * @since 3.7.0
- * @since 4.8.0 The $network_id parameter has been added.
- *
- * @param int|null $network_id ID of the network. Default is the current network.
- */
-function wp_maybe_update_network_user_counts( $network_id = null ) {
- $is_small_network = ! wp_is_large_network( 'users', $network_id );
-
- /** This filter is documented in wp-includes/ms-functions.php */
- if ( ! apply_filters( 'enable_live_network_counts', $is_small_network, 'users' ) )
- return;
-
- wp_update_network_user_counts( $network_id );
-}
-
/**
* Update the network-wide site count.
*
@@ -2516,19 +2437,30 @@ function upload_size_limit_filter( $size ) {
*
* @since 3.3.0
* @since 4.8.0 The $network_id parameter has been added.
+ * @since 5.0.0 Deprecated $network_id
*
* @param string $using 'sites or 'users'. Default is 'sites'.
* @param int|null $network_id ID of the network. Default is the current network.
* @return bool True if the network meets the criteria for large. False otherwise.
*/
-function wp_is_large_network( $using = 'sites', $network_id = null ) {
- $network_id = (int) $network_id;
+function wp_is_large_network( $using = 'sites', $deprecated = null ) {
+
+ if ( null !== $deprecated ) {
+ _deprecated_argument( __FUNCTION__, __( 'Unable to pass $network_id. ' ), '5.0.0' );
+ }
+ $network_id = (int) $deprecated;
+
if ( ! $network_id ) {
$network_id = get_current_network_id();
}
if ( 'users' == $using ) {
- $count = get_user_count( $network_id );
+
+ $count = wp_get_user_count();
+
+ /** This filter is documented in wp-includes/functions.php */
+ $is_large_network = apply_filters( 'wp_is_large_user_count', $count > 10000, $count );
+
/**
* Filters whether the network is considered large.
*
@@ -2540,10 +2472,10 @@ function wp_is_large_network( $using = 'sites', $network_id = null ) {
* @param int $count The count of items for the component.
* @param int $network_id The ID of the network being checked.
*/
- return apply_filters( 'wp_is_large_network', $count > 10000, 'users', $count, $network_id );
+ return apply_filters( 'wp_is_large_network', $is_large_network, 'users', $count, $network_id );
}
- $count = get_blog_count( $network_id );
+ $count = get_blog_count();
/** This filter is documented in wp-includes/ms-functions.php */
return apply_filters( 'wp_is_large_network', $count > 10000, 'sites', $count, $network_id );
}
diff --git a/wp-includes/update.php b/wp-includes/update.php
index e23811b..2c80f26 100644
--- a/wp-includes/update.php
+++ b/wp-includes/update.php
@@ -72,14 +72,12 @@ function wp_version_check( $extra_stats = array(), $force_check = false ) {
else
$mysql_version = 'N/A';
+ $user_count = wp_get_user_count();
if ( is_multisite() ) {
- $user_count = get_user_count();
$num_blogs = get_blog_count();
$wp_install = network_site_url();
$multisite_enabled = 1;
} else {
- $user_count = count_users();
- $user_count = $user_count['total_users'];
$multisite_enabled = 0;
$num_blogs = 1;
$wp_install = home_url( '/' );
@@ -106,7 +104,7 @@ function wp_version_check( $extra_stats = array(), $force_check = false ) {
* @since 4.9.0
*
* @param array $query {
- * Version check query arguments.
+ * Version check query arguments.
*
* @type string $version WordPress version number.
* @type string $php PHP version number.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment