函数文档

count_users()

💡 云策文档标注

概述

count_users() 函数用于统计站点中每个用户角色的用户数量,返回包含总用户数和按角色分类计数的数组。支持两种计算策略:'time'(CPU 密集型)和 'memory'(内存密集型),并可通过过滤器进行自定义。

关键要点

  • 函数返回一个数组,包含 total_users(总用户数)和 avail_roles(按角色键值对计数的数组)。
  • 接受两个可选参数:$strategy(计算策略,默认为 'time')和 $site_id(站点 ID,默认为当前站点)。
  • 使用 'time' 策略时,通过复杂 SQL 查询高效处理大量用户(约 10^7),但假设角色名称唯一且无重复能力元值。
  • 使用 'memory' 策略时,通过内存操作处理较少用户(约 10^5),但可能存在 WP Bug #12257 相关限制。
  • 提供 pre_count_users 过滤器,允许在查询前自定义返回结果。
  • 支持多站点环境,通过 $site_id 参数指定要统计的站点。

代码示例

$result = count_users();
echo 'There are ', $result['total_users'], ' total users';

foreach( $result['avail_roles'] as $role => $count )
    echo ', ', $count, ' are ', $role, 's';
echo '.';

注意事项

  • 函数假设用户角色名称是唯一短语,且无重复或孤立的能力元值,与 WP_User_Query::prepare_query() 相同。
  • 在 'time' 策略下,如果涉及多站点且非当前站点,会临时切换博客以获取角色列表。
  • 返回的 avail_roles 数组不包含计数为 0 的角色,适合在 foreach 循环中使用。
  • 自 4.9.0 版本起添加 $site_id 参数以支持多站点;4.4.0 版本起在 none 元素中包含无角色用户数。

📄 原文内容

Counts number of users who have each of the user roles.

Description

Assumes there are neither duplicated nor orphaned capabilities meta_values.
Assumes role names are unique phrases. Same assumption made by WP_User_Query::prepare_query() Using $strategy = ‘time’ this is CPU-intensive and should handle around 10^7 users.
Using $strategy = ‘memory’ this is memory-intensive and should handle around 10^5 users, but see WP Bug #12257.

Parameters

$strategystringoptional
The computational strategy to use when counting the users.
Accepts either 'time' or 'memory'. Default 'time'.
$site_idint|nulloptional
The site ID to count users for. Defaults to the current site.

Default:null

Return

array User counts.

  • total_users int
    Total number of users on the site.
  • avail_roles int[]
    Array of user counts keyed by user role.

Source

function count_users( $strategy = 'time', $site_id = null ) {
	global $wpdb;

	// Initialize.
	if ( ! $site_id ) {
		$site_id = get_current_blog_id();
	}

	/**
	 * Filters the user count before queries are run.
	 *
	 * Return a non-null value to cause count_users() to return early.
	 *
	 * @since 5.1.0
	 *
	 * @param null|array $result   The value to return instead. Default null to continue with the query.
	 * @param string     $strategy Optional. The computational strategy to use when counting the users.
	 *                             Accepts either 'time' or 'memory'. Default 'time'.
	 * @param int        $site_id  The site ID to count users for.
	 */
	$pre = apply_filters( 'pre_count_users', null, $strategy, $site_id );

	if ( null !== $pre ) {
		return $pre;
	}

	$blog_prefix = $wpdb->get_blog_prefix( $site_id );
	$result      = array();

	if ( 'time' === $strategy ) {
		if ( is_multisite() && get_current_blog_id() !== $site_id ) {
			switch_to_blog( $site_id );
			$avail_roles = wp_roles()->get_names();
			restore_current_blog();
		} else {
			$avail_roles = wp_roles()->get_names();
		}

		// Build a CPU-intensive query that will return concise information.
		$select_count = array();
		foreach ( $avail_roles as $this_role => $name ) {
			$select_count[] = $wpdb->prepare( 'COUNT(NULLIF(`meta_value` LIKE %s, false))', '%' . $wpdb->esc_like( '"' . $this_role . '"' ) . '%' );
		}
		$select_count[] = "COUNT(NULLIF(`meta_value` = 'a:0:{}', false))";
		$select_count   = implode( ', ', $select_count );

		// Add the meta_value index to the selection list, then run the query.
		$row = $wpdb->get_row(
			"
			SELECT {$select_count}, COUNT(*)
			FROM {$wpdb->usermeta}
			INNER JOIN {$wpdb->users} ON user_id = ID
			WHERE meta_key = '{$blog_prefix}capabilities'
		",
			ARRAY_N
		);

		// Run the previous loop again to associate results with role names.
		$col         = 0;
		$role_counts = array();
		foreach ( $avail_roles as $this_role => $name ) {
			$count = (int) $row[ $col++ ];
			if ( $count > 0 ) {
				$role_counts[ $this_role ] = $count;
			}
		}

		$role_counts['none'] = (int) $row[ $col++ ];

		// Get the meta_value index from the end of the result set.
		$total_users = (int) $row[ $col ];

		$result['total_users'] = $total_users;
		$result['avail_roles'] =& $role_counts;
	} else {
		$avail_roles = array(
			'none' => 0,
		);

		$users_of_blog = $wpdb->get_col(
			"
			SELECT meta_value
			FROM {$wpdb->usermeta}
			INNER JOIN {$wpdb->users} ON user_id = ID
			WHERE meta_key = '{$blog_prefix}capabilities'
		"
		);

		foreach ( $users_of_blog as $caps_meta ) {
			$b_roles = maybe_unserialize( $caps_meta );
			if ( ! is_array( $b_roles ) ) {
				continue;
			}
			if ( empty( $b_roles ) ) {
				++$avail_roles['none'];
			}
			foreach ( $b_roles as $b_role => $val ) {
				if ( isset( $avail_roles[ $b_role ] ) ) {
					++$avail_roles[ $b_role ];
				} else {
					$avail_roles[ $b_role ] = 1;
				}
			}
		}

		$result['total_users'] = count( $users_of_blog );
		$result['avail_roles'] =& $avail_roles;
	}

	return $result;
}

Hooks

apply_filters( ‘pre_count_users’, null|array $result, string $strategy, int $site_id )

Filters the user count before queries are run.

Changelog

Version Description
4.9.0 The $site_id parameter was added to support multisite.
4.4.0 The number of users with no role is now included in the none element.
3.0.0 Introduced.

User Contributed Notes

  1. Skip to note 2 content

    Basic Example

    The call to count_users returns the number of users with each role. It will not return any roles having count == 0, so the results are intended to be used in foreach loops.

    $result = count_users();
    echo 'There are ', $result['total_users'], ' total users';
    
    foreach( $result['avail_roles'] as $role => $count )
        echo ', ', $count, ' are ', $role, 's';
    echo '.';

    Output example is:

    There are 199 total users, 11 are administrators, 4 are contributors.