* Retrieve user meta field for a user.
* @link https://developer.wordpress.org/reference/functions/get_user_meta/
* @param int $user_id User ID.
* @param string $key Optional. The meta key to retrieve. By default,
* returns data for all keys.
* @param bool $single Optional. Whether to return a single value.
* This parameter has no effect if $key is not specified.
* @return mixed An array if $single is false. The value of meta data field
* if $single is true. False for an invalid $user_id.
function get_user_meta( $user_id, $key = '', $single = false ) {
return get_metadata( 'user', $user_id, $key, $single );
* Update user meta field based on user ID.
* Use the $prev_value parameter to differentiate between meta fields with the
* If the meta field for the user does not exist, it will be added.
* @link https://developer.wordpress.org/reference/functions/update_user_meta/
* @param int $user_id User ID.
* @param string $meta_key Metadata key.
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
* @param mixed $prev_value Optional. Previous value to check before updating.
* If specified, only update existing metadata entries with
* this value. Otherwise, update all entries. Default empty.
* @return int|bool Meta ID if the key didn't exist, true on successful update,
* false on failure or if the value passed to the function
* is the same as the one that is already in the database.
function update_user_meta( $user_id, $meta_key, $meta_value, $prev_value = '' ) {
return update_metadata( 'user', $user_id, $meta_key, $meta_value, $prev_value );
* Count number of users who have each of the user roles.
* 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.
* @since 4.4.0 The number of users with no role is now included in the `none` element.
* @since 4.9.0 The `$site_id` parameter was added to support multisite.
* @global wpdb $wpdb WordPress database abstraction object.
* @param string $strategy Optional. The computational strategy to use when counting the users.
* Accepts either 'time' or 'memory'. Default 'time'.
* @param int|null $site_id Optional. The site ID to count users for. Defaults to the current site.
* @type int $total_users Total number of users on the site.
* @type int[] $avail_roles Array of user counts keyed by user role.
function count_users( $strategy = 'time', $site_id = null ) {
$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.
* @param null|string $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|null $site_id Optional. The site ID to count users for. Defaults to the current site.
$pre = apply_filters( 'pre_count_users', null, $strategy, $site_id );
$blog_prefix = $wpdb->get_blog_prefix( $site_id );
if ( 'time' === $strategy ) {
if ( is_multisite() && get_current_blog_id() != $site_id ) {
switch_to_blog( $site_id );
$avail_roles = wp_roles()->get_names();
$avail_roles = wp_roles()->get_names();
// Build a CPU-intensive query that will return concise information.
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.
SELECT {$select_count}, COUNT(*)
INNER JOIN {$wpdb->users} ON user_id = ID
WHERE meta_key = '{$blog_prefix}capabilities'
// Run the previous loop again to associate results with role names.
foreach ( $avail_roles as $this_role => $name ) {
$count = (int) $row[ $col++ ];
$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;
$users_of_blog = $wpdb->get_col(
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 ) ) {
if ( empty( $b_roles ) ) {
foreach ( $b_roles as $b_role => $val ) {
if ( isset( $avail_roles[ $b_role ] ) ) {
$avail_roles[ $b_role ]++;
$avail_roles[ $b_role ] = 1;
$result['total_users'] = count( $users_of_blog );
$result['avail_roles'] =& $avail_roles;
// Private helper functions.
* Set up global user vars.
* Used by wp_set_current_user() for back compat. Might be deprecated in the future.
* @global string $user_login The user username for logging in
* @global WP_User $userdata User data.
* @global int $user_level The level of the user
* @global int $user_ID The ID of the user
* @global string $user_email The email address of the user
* @global string $user_url The url in the user's profile
* @global string $user_identity The display name of the user
* @param int $for_user_id Optional. User ID to set up global data. Default 0.
function setup_userdata( $for_user_id = 0 ) {
global $user_login, $userdata, $user_level, $user_ID, $user_email, $user_url, $user_identity;
$for_user_id = get_current_user_id();
$user = get_userdata( $for_user_id );
$user_ID = (int) $user->ID;
$user_level = (int) $user->user_level;
$user_login = $user->user_login;
$user_email = $user->user_email;
$user_url = $user->user_url;
$user_identity = $user->display_name;
* Create dropdown HTML content of users.
* The content can either be displayed, which it is by default or retrieved by
* setting the 'echo' argument. The 'include' and 'exclude' arguments do not
* need to be used; all users will be displayed in that case. Only one can be
* used, either 'include' or 'exclude', but not both.
* The available arguments are as follows:
* @since 4.5.0 Added the 'display_name_with_login' value for 'show'.
* @since 4.7.0 Added the `$role`, `$role__in`, and `$role__not_in` parameters.
* @param array|string $args {
* Optional. Array or string of arguments to generate a drop-down of users.
* See WP_User_Query::prepare_query() for additional available arguments.
* @type string $show_option_all Text to show as the drop-down default (all).
* @type string $show_option_none Text to show as the drop-down default when no
* users were found. Default empty.
* @type int|string $option_none_value Value to use for $show_option_non when no users
* were found. Default -1.
* @type string $hide_if_only_one_author Whether to skip generating the drop-down
* if only one user was found. Default empty.
* @type string $orderby Field to order found users by. Accepts user fields.
* Default 'display_name'.
* @type string $order Whether to order users in ascending or descending
* order. Accepts 'ASC' (ascending) or 'DESC' (descending).
* @type int[]|string $include Array or comma-separated list of user IDs to include.
* @type int[]|string $exclude Array or comma-separated list of user IDs to exclude.
* @type bool|int $multi Whether to skip the ID attribute on the 'select' element.
* Accepts 1|true or 0|false. Default 0|false.
* @type string $show User data to display. If the selected item is empty
* then the 'user_login' will be displayed in parentheses.
* Accepts any user field, or 'display_name_with_login' to show
* the display name with user_login in parentheses.
* Default 'display_name'.
* @type int|bool $echo Whether to echo or return the drop-down. Accepts 1|true (echo)
* or 0|false (return). Default 1|true.
* @type int $selected Which user ID should be selected. Default 0.
* @type bool $include_selected Whether to always include the selected user ID in the drop-
* @type string $name Name attribute of select element. Default 'user'.
* @type string $id ID attribute of the select element. Default is the value of $name.
* @type string $class Class attribute of the select element. Default empty.
* @type int $blog_id ID of blog (Multisite only). Default is ID of the current blog.
* @type string $who Which type of users to query. Accepts only an empty string or
* 'authors'. Default empty.
* @type string|array $role An array or a comma-separated list of role names that users must
* match to be included in results. Note that this is an inclusive
* list: users must match *each* role. Default empty.
* @type string[] $role__in An array of role names. Matched users must have at least one of
* these roles. Default empty array.
* @type string[] $role__not_in An array of role names to exclude. Users matching one or more of
* these roles will not be included in results. Default empty array.
* @return string HTML dropdown list of users.
function wp_dropdown_users( $args = '' ) {
'show_option_none' => '',
'hide_if_only_one_author' => '',
'orderby' => 'display_name',
'show' => 'display_name',
'blog_id' => get_current_blog_id(),
'include_selected' => false,
'option_none_value' => -1,
'role__not_in' => array(),
$defaults['selected'] = is_author() ? get_query_var( 'author' ) : 0;
$parsed_args = wp_parse_args( $args, $defaults );
$query_args = wp_array_slice_assoc( $parsed_args, array( 'blog_id', 'include', 'exclude', 'orderby', 'order', 'who', 'role', 'role__in', 'role__not_in' ) );
$fields = array( 'ID', 'user_login' );
$show = ! empty( $parsed_args['show'] ) ? $parsed_args['show'] : 'display_name';
if ( 'display_name_with_login' === $show ) {
$fields[] = 'display_name';
$query_args['fields'] = $fields;
$show_option_all = $parsed_args['show_option_all'];
$show_option_none = $parsed_args['show_option_none'];
$option_none_value = $parsed_args['option_none_value'];
* Filters the query arguments for the list of users in the dropdown.
* @param array $query_args The query arguments for get_users().
* @param array $parsed_args The arguments passed to wp_dropdown_users() combined with the defaults.
$query_args = apply_filters( 'wp_dropdown_users_args', $query_args, $parsed_args );
$users = get_users( $query_args );
if ( ! empty( $users ) && ( empty( $parsed_args['hide_if_only_one_author'] ) || count( $users ) > 1 ) ) {
$name = esc_attr( $parsed_args['name'] );
if ( $parsed_args['multi'] && ! $parsed_args['id'] ) {
$id = $parsed_args['id'] ? " id='" . esc_attr( $parsed_args['id'] ) . "'" : " id='$name'";
$output = "<select name='{$name}'{$id} class='" . $parsed_args['class'] . "'>\n";
if ( $show_option_all ) {
$output .= "\t<option value='0'>$show_option_all</option>\n";
if ( $show_option_none ) {
$_selected = selected( $option_none_value, $parsed_args['selected'], false );
$output .= "\t<option value='" . esc_attr( $option_none_value ) . "'$_selected>$show_option_none</option>\n";
if ( $parsed_args['include_selected'] && ( $parsed_args['selected'] > 0 ) ) {
$parsed_args['selected'] = (int) $parsed_args['selected'];
foreach ( (array) $users as $user ) {
$user->ID = (int) $user->ID;
if ( $user->ID === $parsed_args['selected'] ) {
if ( ! $found_selected ) {
$selected_user = get_userdata( $parsed_args['selected'] );
$users[] = $selected_user;
foreach ( (array) $users as $user ) {
if ( 'display_name_with_login' === $show ) {
/* translators: 1: User's display name, 2: User login. */
$display = sprintf( _x( '%1$s (%2$s)', 'user dropdown' ), $user->display_name, $user->user_login );
} elseif ( ! empty( $user->$show ) ) {
$display = '(' . $user->user_login . ')';
$_selected = selected( $user->ID, $parsed_args['selected'], false );
$output .= "\t<option value='$user->ID'$_selected>" . esc_html( $display ) . "</option>\n";
* Filters the wp_dropdown_users() HTML output.
* @param string $output HTML output generated by wp_dropdown_users().
$html = apply_filters( 'wp_dropdown_users', $output );
if ( $parsed_args['echo'] ) {
* Sanitize user field based on context.
* Possible context values are: 'raw', 'edit', 'db', 'display', 'attribute' and 'js'. The
* 'display' context is used by default. 'attribute' and 'js' contexts are treated like 'display'
* @param string $field The user Object field name.
* @param mixed $value The user Object value.
* @param int $user_id User ID.
* @param string $context How to sanitize user fields. Looks for 'raw', 'edit', 'db', 'display',
* @return mixed Sanitized value.
function sanitize_user_field( $field, $value, $user_id, $context ) {
$int_fields = array( 'ID' );
if ( in_array( $field, $int_fields, true ) ) {
if ( 'raw' === $context ) {
if ( ! is_string( $value ) && ! is_numeric( $value ) ) {
$prefixed = false !== strpos( $field, 'user_' );
if ( 'edit' === $context ) {
/** This filter is documented in wp-includes/post.php */
$value = apply_filters( "edit_{$field}", $value, $user_id );
* Filters a user field value in the 'edit' context.
* The dynamic portion of the hook name, `$field`, refers to the prefixed user
* field being filtered, such as 'user_login', 'user_email', 'first_name', etc.
* @param mixed $value Value of the prefixed user field.
* @param int $user_id User ID.
$value = apply_filters( "edit_user_{$field}", $value, $user_id );
if ( 'description' === $field ) {
$value = esc_html( $value ); // textarea_escaped?
$value = esc_attr( $value );
} elseif ( 'db' === $context ) {
/** This filter is documented in wp-includes/post.php */
$value = apply_filters( "pre_{$field}", $value );
* Filters the value of a user field in the 'db' context.
* The dynamic portion of the hook name, `$field`, refers to the prefixed user
* field being filtered, such as 'user_login', 'user_email', 'first_name', etc.
* @param mixed $value Value of the prefixed user field.
$value = apply_filters( "pre_user_{$field}", $value );
// Use display filters by default.