Make WordPress Core

Changeset 33749


Ignore:
Timestamp:
08/26/2015 04:19:32 AM (9 years ago)
Author:
wonderboymusic
Message:

Users: move WP_User_Query into its own file. user.php loads the new files, so this is 100% BC if someone is loading user.php directly (a lot of plugins do). New files created using svn cp.

Creates:
class-wp-user-query.php
user-functions.php

user.php contains only top-level code. Class file only contains the class. Functions file only contains functions.

See #33413.

Location:
trunk/src/wp-includes
Files:
1 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-user-query.php

    r33746 r33749  
    11<?php
    2 /**
    3  * WordPress User API
    4  *
    5  * @package WordPress
    6  * @subpackage Users
    7  */
    8 
    9 /**
    10  * Authenticate user with remember capability.
    11  *
    12  * The credentials is an array that has 'user_login', 'user_password', and
    13  * 'remember' indices. If the credentials is not given, then the log in form
    14  * will be assumed and used if set.
    15  *
    16  * The various authentication cookies will be set by this function and will be
    17  * set for a longer period depending on if the 'remember' credential is set to
    18  * true.
    19  *
    20  * @since 2.5.0
    21  *
    22  * @global string $auth_secure_cookie
    23  *
    24  * @param array       $credentials   Optional. User info in order to sign on.
    25  * @param string|bool $secure_cookie Optional. Whether to use secure cookie.
    26  * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
    27  */
    28 function wp_signon( $credentials = array(), $secure_cookie = '' ) {
    29     if ( empty($credentials) ) {
    30         if ( ! empty($_POST['log']) )
    31             $credentials['user_login'] = $_POST['log'];
    32         if ( ! empty($_POST['pwd']) )
    33             $credentials['user_password'] = $_POST['pwd'];
    34         if ( ! empty($_POST['rememberme']) )
    35             $credentials['remember'] = $_POST['rememberme'];
    36     }
    37 
    38     if ( !empty($credentials['remember']) )
    39         $credentials['remember'] = true;
    40     else
    41         $credentials['remember'] = false;
    42 
    43     /**
    44      * Fires before the user is authenticated.
    45      *
    46      * The variables passed to the callbacks are passed by reference,
    47      * and can be modified by callback functions.
    48      *
    49      * @since 1.5.1
    50      *
    51      * @todo Decide whether to deprecate the wp_authenticate action.
    52      *
    53      * @param string $user_login    Username, passed by reference.
    54      * @param string $user_password User password, passed by reference.
    55      */
    56     do_action_ref_array( 'wp_authenticate', array( &$credentials['user_login'], &$credentials['user_password'] ) );
    57 
    58     if ( '' === $secure_cookie )
    59         $secure_cookie = is_ssl();
    60 
    61     /**
    62      * Filter whether to use a secure sign-on cookie.
    63      *
    64      * @since 3.1.0
    65      *
    66      * @param bool  $secure_cookie Whether to use a secure sign-on cookie.
    67      * @param array $credentials {
    68      *     Array of entered sign-on data.
    69      *
    70      *     @type string $user_login    Username.
    71      *     @type string $user_password Password entered.
    72      *     @type bool   $remember      Whether to 'remember' the user. Increases the time
    73      *                                 that the cookie will be kept. Default false.
    74      * }
    75      */
    76     $secure_cookie = apply_filters( 'secure_signon_cookie', $secure_cookie, $credentials );
    77 
    78     global $auth_secure_cookie; // XXX ugly hack to pass this to wp_authenticate_cookie
    79     $auth_secure_cookie = $secure_cookie;
    80 
    81     add_filter('authenticate', 'wp_authenticate_cookie', 30, 3);
    82 
    83     $user = wp_authenticate($credentials['user_login'], $credentials['user_password']);
    84 
    85     if ( is_wp_error($user) ) {
    86         if ( $user->get_error_codes() == array('empty_username', 'empty_password') ) {
    87             $user = new WP_Error('', '');
    88         }
    89 
    90         return $user;
    91     }
    92 
    93     wp_set_auth_cookie($user->ID, $credentials['remember'], $secure_cookie);
    94     /**
    95      * Fires after the user has successfully logged in.
    96      *
    97      * @since 1.5.0
    98      *
    99      * @param string  $user_login Username.
    100      * @param WP_User $user       WP_User object of the logged-in user.
    101      */
    102     do_action( 'wp_login', $user->user_login, $user );
    103     return $user;
    104 }
    105 
    106 /**
    107  * Authenticate the user using the username and password.
    108  *
    109  * @since 2.8.0
    110  *
    111  * @param WP_User|WP_Error|null $user     WP_User or WP_Error object from a previous callback. Default null.
    112  * @param string                $username Username for authentication.
    113  * @param string                $password Password for authentication.
    114  * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
    115  */
    116 function wp_authenticate_username_password($user, $username, $password) {
    117     if ( $user instanceof WP_User ) {
    118         return $user;
    119     }
    120 
    121     if ( empty($username) || empty($password) ) {
    122         if ( is_wp_error( $user ) )
    123             return $user;
    124 
    125         $error = new WP_Error();
    126 
    127         if ( empty($username) )
    128             $error->add('empty_username', __('<strong>ERROR</strong>: The username field is empty.'));
    129 
    130         if ( empty($password) )
    131             $error->add('empty_password', __('<strong>ERROR</strong>: The password field is empty.'));
    132 
    133         return $error;
    134     }
    135 
    136     $user = get_user_by('login', $username);
    137 
    138     if ( !$user )
    139         return new WP_Error( 'invalid_username', sprintf( __( '<strong>ERROR</strong>: Invalid username. <a href="%s">Lost your password?</a>' ), wp_lostpassword_url() ) );
    140 
    141     /**
    142      * Filter whether the given user can be authenticated with the provided $password.
    143      *
    144      * @since 2.5.0
    145      *
    146      * @param WP_User|WP_Error $user     WP_User or WP_Error object if a previous
    147      *                                   callback failed authentication.
    148      * @param string           $password Password to check against the user.
    149      */
    150     $user = apply_filters( 'wp_authenticate_user', $user, $password );
    151     if ( is_wp_error($user) )
    152         return $user;
    153 
    154     if ( !wp_check_password($password, $user->user_pass, $user->ID) )
    155         return new WP_Error( 'incorrect_password', sprintf( __( '<strong>ERROR</strong>: The password you entered for the username <strong>%1$s</strong> is incorrect. <a href="%2$s">Lost your password?</a>' ),
    156         $username, wp_lostpassword_url() ) );
    157 
    158     return $user;
    159 }
    160 
    161 /**
    162  * Authenticate the user using the WordPress auth cookie.
    163  *
    164  * @since 2.8.0
    165  *
    166  * @global string $auth_secure_cookie
    167  *
    168  * @param WP_User|WP_Error|null $user     WP_User or WP_Error object from a previous callback. Default null.
    169  * @param string                $username Username. If not empty, cancels the cookie authentication.
    170  * @param string                $password Password. If not empty, cancels the cookie authentication.
    171  * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
    172  */
    173 function wp_authenticate_cookie($user, $username, $password) {
    174     if ( $user instanceof WP_User ) {
    175         return $user;
    176     }
    177 
    178     if ( empty($username) && empty($password) ) {
    179         $user_id = wp_validate_auth_cookie();
    180         if ( $user_id )
    181             return new WP_User($user_id);
    182 
    183         global $auth_secure_cookie;
    184 
    185         if ( $auth_secure_cookie )
    186             $auth_cookie = SECURE_AUTH_COOKIE;
    187         else
    188             $auth_cookie = AUTH_COOKIE;
    189 
    190         if ( !empty($_COOKIE[$auth_cookie]) )
    191             return new WP_Error('expired_session', __('Please log in again.'));
    192 
    193         // If the cookie is not set, be silent.
    194     }
    195 
    196     return $user;
    197 }
    198 
    199 /**
    200  * For Multisite blogs, check if the authenticated user has been marked as a
    201  * spammer, or if the user's primary blog has been marked as spam.
    202  *
    203  * @since 3.7.0
    204  *
    205  * @param WP_User|WP_Error|null $user WP_User or WP_Error object from a previous callback. Default null.
    206  * @return WP_User|WP_Error WP_User on success, WP_Error if the user is considered a spammer.
    207  */
    208 function wp_authenticate_spam_check( $user ) {
    209     if ( $user instanceof WP_User && is_multisite() ) {
    210         /**
    211          * Filter whether the user has been marked as a spammer.
    212          *
    213          * @since 3.7.0
    214          *
    215          * @param bool    $spammed Whether the user is considered a spammer.
    216          * @param WP_User $user    User to check against.
    217          */
    218         $spammed = apply_filters( 'check_is_user_spammed', is_user_spammy(), $user );
    219 
    220         if ( $spammed )
    221             return new WP_Error( 'spammer_account', __( '<strong>ERROR</strong>: Your account has been marked as a spammer.' ) );
    222     }
    223     return $user;
    224 }
    225 
    226 /**
    227  * Validate the logged-in cookie.
    228  *
    229  * Checks the logged-in cookie if the previous auth cookie could not be
    230  * validated and parsed.
    231  *
    232  * This is a callback for the determine_current_user filter, rather than API.
    233  *
    234  * @since 3.9.0
    235  *
    236  * @param int|bool $user_id The user ID (or false) as received from the
    237  *                       determine_current_user filter.
    238  * @return int|false User ID if validated, false otherwise. If a user ID from
    239  *                   an earlier filter callback is received, that value is returned.
    240  */
    241 function wp_validate_logged_in_cookie( $user_id ) {
    242     if ( $user_id ) {
    243         return $user_id;
    244     }
    245 
    246     if ( is_blog_admin() || is_network_admin() || empty( $_COOKIE[LOGGED_IN_COOKIE] ) ) {
    247         return false;
    248     }
    249 
    250     return wp_validate_auth_cookie( $_COOKIE[LOGGED_IN_COOKIE], 'logged_in' );
    251 }
    252 
    253 /**
    254  * Number of posts user has written.
    255  *
    256  * @since 3.0.0
    257  * @since 4.1.0 Added `$post_type` argument.
    258  * @since 4.3.0 Added `$public_only` argument. Added the ability to pass an array
    259  *              of post types to `$post_type`.
    260  *
    261  * @global wpdb $wpdb WordPress database object for queries.
    262  *
    263  * @param int          $userid      User ID.
    264  * @param array|string $post_type   Optional. Single post type or array of post types to count the number of posts for. Default 'post'.
    265  * @param bool         $public_only Optional. Whether to only return counts for public posts. Default false.
    266  * @return int Number of posts the user has written in this post type.
    267  */
    268 function count_user_posts( $userid, $post_type = 'post', $public_only = false ) {
    269     global $wpdb;
    270 
    271     $where = get_posts_by_author_sql( $post_type, true, $userid, $public_only );
    272 
    273     $count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts $where" );
    274 
    275     /**
    276      * Filter the number of posts a user has written.
    277      *
    278      * @since 2.7.0
    279      * @since 4.1.0 Added `$post_type` argument.
    280      * @since 4.3.1 Added `$public_only` argument.
    281      *
    282      * @param int          $count       The user's post count.
    283      * @param int          $userid      User ID.
    284      * @param string|array $post_type   Single post type or array of post types to count the number of posts for.
    285      * @param bool         $public_only Whether to limit counted posts to public posts.
    286      */
    287     return apply_filters( 'get_usernumposts', $count, $userid, $post_type, $public_only );
    288 }
    289 
    290 /**
    291  * Number of posts written by a list of users.
    292  *
    293  * @since 3.0.0
    294  *
    295  * @global wpdb $wpdb
    296  *
    297  * @param array        $users       Array of user IDs.
    298  * @param string|array $post_type   Optional. Single post type or array of post types to check. Defaults to 'post'.
    299  * @param bool         $public_only Optional. Only return counts for public posts.  Defaults to false.
    300  * @return array Amount of posts each user has written.
    301  */
    302 function count_many_users_posts( $users, $post_type = 'post', $public_only = false ) {
    303     global $wpdb;
    304 
    305     $count = array();
    306     if ( empty( $users ) || ! is_array( $users ) )
    307         return $count;
    308 
    309     $userlist = implode( ',', array_map( 'absint', $users ) );
    310     $where = get_posts_by_author_sql( $post_type, true, null, $public_only );
    311 
    312     $result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author", ARRAY_N );
    313     foreach ( $result as $row ) {
    314         $count[ $row[0] ] = $row[1];
    315     }
    316 
    317     foreach ( $users as $id ) {
    318         if ( ! isset( $count[ $id ] ) )
    319             $count[ $id ] = 0;
    320     }
    321 
    322     return $count;
    323 }
    324 
    325 //
    326 // User option functions
    327 //
    328 
    329 /**
    330  * Get the current user's ID
    331  *
    332  * @since MU
    333  *
    334  * @return int The current user's ID
    335  */
    336 function get_current_user_id() {
    337     if ( ! function_exists( 'wp_get_current_user' ) )
    338         return 0;
    339     $user = wp_get_current_user();
    340     return ( isset( $user->ID ) ? (int) $user->ID : 0 );
    341 }
    342 
    343 /**
    344  * Retrieve user option that can be either per Site or per Network.
    345  *
    346  * If the user ID is not given, then the current user will be used instead. If
    347  * the user ID is given, then the user data will be retrieved. The filter for
    348  * the result, will also pass the original option name and finally the user data
    349  * object as the third parameter.
    350  *
    351  * The option will first check for the per site name and then the per Network name.
    352  *
    353  * @since 2.0.0
    354  *
    355  * @global wpdb $wpdb WordPress database object for queries.
    356  *
    357  * @param string $option     User option name.
    358  * @param int    $user       Optional. User ID.
    359  * @param string $deprecated Use get_option() to check for an option in the options table.
    360  * @return mixed User option value on success, false on failure.
    361  */
    362 function get_user_option( $option, $user = 0, $deprecated = '' ) {
    363     global $wpdb;
    364 
    365     if ( !empty( $deprecated ) )
    366         _deprecated_argument( __FUNCTION__, '3.0' );
    367 
    368     if ( empty( $user ) )
    369         $user = get_current_user_id();
    370 
    371     if ( ! $user = get_userdata( $user ) )
    372         return false;
    373 
    374     $prefix = $wpdb->get_blog_prefix();
    375     if ( $user->has_prop( $prefix . $option ) ) // Blog specific
    376         $result = $user->get( $prefix . $option );
    377     elseif ( $user->has_prop( $option ) ) // User specific and cross-blog
    378         $result = $user->get( $option );
    379     else
    380         $result = false;
    381 
    382     /**
    383      * Filter a specific user option value.
    384      *
    385      * The dynamic portion of the hook name, `$option`, refers to the user option name.
    386      *
    387      * @since 2.5.0
    388      *
    389      * @param mixed   $result Value for the user's option.
    390      * @param string  $option Name of the option being retrieved.
    391      * @param WP_User $user   WP_User object of the user whose option is being retrieved.
    392      */
    393     return apply_filters( "get_user_option_{$option}", $result, $option, $user );
    394 }
    395 
    396 /**
    397  * Update user option with global blog capability.
    398  *
    399  * User options are just like user metadata except that they have support for
    400  * global blog options. If the 'global' parameter is false, which it is by default
    401  * it will prepend the WordPress table prefix to the option name.
    402  *
    403  * Deletes the user option if $newvalue is empty.
    404  *
    405  * @since 2.0.0
    406  *
    407  * @global wpdb $wpdb WordPress database object for queries.
    408  *
    409  * @param int    $user_id     User ID.
    410  * @param string $option_name User option name.
    411  * @param mixed  $newvalue    User option value.
    412  * @param bool   $global      Optional. Whether option name is global or blog specific.
    413  *                            Default false (blog specific).
    414  * @return int|bool User meta ID if the option didn't exist, true on successful update,
    415  *                  false on failure.
    416  */
    417 function update_user_option( $user_id, $option_name, $newvalue, $global = false ) {
    418     global $wpdb;
    419 
    420     if ( !$global )
    421         $option_name = $wpdb->get_blog_prefix() . $option_name;
    422 
    423     return update_user_meta( $user_id, $option_name, $newvalue );
    424 }
    425 
    426 /**
    427  * Delete user option with global blog capability.
    428  *
    429  * User options are just like user metadata except that they have support for
    430  * global blog options. If the 'global' parameter is false, which it is by default
    431  * it will prepend the WordPress table prefix to the option name.
    432  *
    433  * @since 3.0.0
    434  *
    435  * @global wpdb $wpdb WordPress database object for queries.
    436  *
    437  * @param int    $user_id     User ID
    438  * @param string $option_name User option name.
    439  * @param bool   $global      Optional. Whether option name is global or blog specific.
    440  *                            Default false (blog specific).
    441  * @return bool True on success, false on failure.
    442  */
    443 function delete_user_option( $user_id, $option_name, $global = false ) {
    444     global $wpdb;
    445 
    446     if ( !$global )
    447         $option_name = $wpdb->get_blog_prefix() . $option_name;
    448     return delete_user_meta( $user_id, $option_name );
    449 }
    450 
    4512/**
    4523 * WordPress User Query class.
    4534 *
    4545 * @since 3.1.0
     6 * @package WordPress
     7 * @subpackage Users
    4558 *
    4569 * @see WP_User_Query::prepare_query() for information on accepted arguments.
     
    1135688    }
    1136689}
    1137 
    1138 /**
    1139  * Retrieve list of users matching criteria.
    1140  *
    1141  * @since 3.1.0
    1142  *
    1143  * @see WP_User_Query
    1144  *
    1145  * @param array $args Optional. Arguments to retrieve users. See {@see WP_User_Query::prepare_query()}
    1146  *                    for more information on accepted arguments.
    1147  * @return array List of users.
    1148  */
    1149 function get_users( $args = array() ) {
    1150 
    1151     $args = wp_parse_args( $args );
    1152     $args['count_total'] = false;
    1153 
    1154     $user_search = new WP_User_Query($args);
    1155 
    1156     return (array) $user_search->get_results();
    1157 }
    1158 
    1159 /**
    1160  * Get the blogs a user belongs to.
    1161  *
    1162  * @since 3.0.0
    1163  *
    1164  * @global wpdb $wpdb WordPress database object for queries.
    1165  *
    1166  * @param int  $user_id User ID
    1167  * @param bool $all     Whether to retrieve all blogs, or only blogs that are not
    1168  *                      marked as deleted, archived, or spam.
    1169  * @return array A list of the user's blogs. An empty array if the user doesn't exist
    1170  *               or belongs to no blogs.
    1171  */
    1172 function get_blogs_of_user( $user_id, $all = false ) {
    1173     global $wpdb;
    1174 
    1175     $user_id = (int) $user_id;
    1176 
    1177     // Logged out users can't have blogs
    1178     if ( empty( $user_id ) )
    1179         return array();
    1180 
    1181     $keys = get_user_meta( $user_id );
    1182     if ( empty( $keys ) )
    1183         return array();
    1184 
    1185     if ( ! is_multisite() ) {
    1186         $blog_id = get_current_blog_id();
    1187         $blogs = array( $blog_id => new stdClass );
    1188         $blogs[ $blog_id ]->userblog_id = $blog_id;
    1189         $blogs[ $blog_id ]->blogname = get_option('blogname');
    1190         $blogs[ $blog_id ]->domain = '';
    1191         $blogs[ $blog_id ]->path = '';
    1192         $blogs[ $blog_id ]->site_id = 1;
    1193         $blogs[ $blog_id ]->siteurl = get_option('siteurl');
    1194         $blogs[ $blog_id ]->archived = 0;
    1195         $blogs[ $blog_id ]->spam = 0;
    1196         $blogs[ $blog_id ]->deleted = 0;
    1197         return $blogs;
    1198     }
    1199 
    1200     $blogs = array();
    1201 
    1202     if ( isset( $keys[ $wpdb->base_prefix . 'capabilities' ] ) && defined( 'MULTISITE' ) ) {
    1203         $blog = get_blog_details( 1 );
    1204         if ( $blog && isset( $blog->domain ) && ( $all || ( ! $blog->archived && ! $blog->spam && ! $blog->deleted ) ) ) {
    1205             $blogs[ 1 ] = (object) array(
    1206                 'userblog_id' => 1,
    1207                 'blogname'    => $blog->blogname,
    1208                 'domain'      => $blog->domain,
    1209                 'path'        => $blog->path,
    1210                 'site_id'     => $blog->site_id,
    1211                 'siteurl'     => $blog->siteurl,
    1212                 'archived'    => $blog->archived,
    1213                 'mature'      => $blog->mature,
    1214                 'spam'        => $blog->spam,
    1215                 'deleted'     => $blog->deleted,
    1216             );
    1217         }
    1218         unset( $keys[ $wpdb->base_prefix . 'capabilities' ] );
    1219     }
    1220 
    1221     $keys = array_keys( $keys );
    1222 
    1223     foreach ( $keys as $key ) {
    1224         if ( 'capabilities' !== substr( $key, -12 ) )
    1225             continue;
    1226         if ( $wpdb->base_prefix && 0 !== strpos( $key, $wpdb->base_prefix ) )
    1227             continue;
    1228         $blog_id = str_replace( array( $wpdb->base_prefix, '_capabilities' ), '', $key );
    1229         if ( ! is_numeric( $blog_id ) )
    1230             continue;
    1231 
    1232         $blog_id = (int) $blog_id;
    1233         $blog = get_blog_details( $blog_id );
    1234         if ( $blog && isset( $blog->domain ) && ( $all || ( ! $blog->archived && ! $blog->spam && ! $blog->deleted ) ) ) {
    1235             $blogs[ $blog_id ] = (object) array(
    1236                 'userblog_id' => $blog_id,
    1237                 'blogname'    => $blog->blogname,
    1238                 'domain'      => $blog->domain,
    1239                 'path'        => $blog->path,
    1240                 'site_id'     => $blog->site_id,
    1241                 'siteurl'     => $blog->siteurl,
    1242                 'archived'    => $blog->archived,
    1243                 'mature'      => $blog->mature,
    1244                 'spam'        => $blog->spam,
    1245                 'deleted'     => $blog->deleted,
    1246             );
    1247         }
    1248     }
    1249 
    1250     /**
    1251      * Filter the list of blogs a user belongs to.
    1252      *
    1253      * @since MU
    1254      *
    1255      * @param array $blogs   An array of blog objects belonging to the user.
    1256      * @param int   $user_id User ID.
    1257      * @param bool  $all     Whether the returned blogs array should contain all blogs, including
    1258      *                       those marked 'deleted', 'archived', or 'spam'. Default false.
    1259      */
    1260     return apply_filters( 'get_blogs_of_user', $blogs, $user_id, $all );
    1261 }
    1262 
    1263 /**
    1264  * Find out whether a user is a member of a given blog.
    1265  *
    1266  * @since MU 1.1
    1267  *
    1268  * @param int $user_id Optional. The unique ID of the user. Defaults to the current user.
    1269  * @param int $blog_id Optional. ID of the blog to check. Defaults to the current site.
    1270  * @return bool
    1271  */
    1272 function is_user_member_of_blog( $user_id = 0, $blog_id = 0 ) {
    1273     $user_id = (int) $user_id;
    1274     $blog_id = (int) $blog_id;
    1275 
    1276     if ( empty( $user_id ) )
    1277         $user_id = get_current_user_id();
    1278 
    1279     if ( empty( $blog_id ) )
    1280         $blog_id = get_current_blog_id();
    1281 
    1282     $blogs = get_blogs_of_user( $user_id );
    1283     return array_key_exists( $blog_id, $blogs );
    1284 }
    1285 
    1286 /**
    1287  * Add meta data field to a user.
    1288  *
    1289  * Post meta data is called "Custom Fields" on the Administration Screens.
    1290  *
    1291  * @since 3.0.0
    1292  * @link https://codex.wordpress.org/Function_Reference/add_user_meta
    1293  *
    1294  * @param int    $user_id    User ID.
    1295  * @param string $meta_key   Metadata name.
    1296  * @param mixed  $meta_value Metadata value.
    1297  * @param bool   $unique     Optional, default is false. Whether the same key should not be added.
    1298  * @return int|false Meta ID on success, false on failure.
    1299  */
    1300 function add_user_meta($user_id, $meta_key, $meta_value, $unique = false) {
    1301     return add_metadata('user', $user_id, $meta_key, $meta_value, $unique);
    1302 }
    1303 
    1304 /**
    1305  * Remove metadata matching criteria from a user.
    1306  *
    1307  * You can match based on the key, or key and value. Removing based on key and
    1308  * value, will keep from removing duplicate metadata with the same key. It also
    1309  * allows removing all metadata matching key, if needed.
    1310  *
    1311  * @since 3.0.0
    1312  * @link https://codex.wordpress.org/Function_Reference/delete_user_meta
    1313  *
    1314  * @param int    $user_id    User ID
    1315  * @param string $meta_key   Metadata name.
    1316  * @param mixed  $meta_value Optional. Metadata value.
    1317  * @return bool True on success, false on failure.
    1318  */
    1319 function delete_user_meta($user_id, $meta_key, $meta_value = '') {
    1320     return delete_metadata('user', $user_id, $meta_key, $meta_value);
    1321 }
    1322 
    1323 /**
    1324  * Retrieve user meta field for a user.
    1325  *
    1326  * @since 3.0.0
    1327  * @link https://codex.wordpress.org/Function_Reference/get_user_meta
    1328  *
    1329  * @param int    $user_id User ID.
    1330  * @param string $key     Optional. The meta key to retrieve. By default, returns data for all keys.
    1331  * @param bool   $single  Whether to return a single value.
    1332  * @return mixed Will be an array if $single is false. Will be value of meta data field if $single is true.
    1333  */
    1334 function get_user_meta($user_id, $key = '', $single = false) {
    1335     return get_metadata('user', $user_id, $key, $single);
    1336 }
    1337 
    1338 /**
    1339  * Update user meta field based on user ID.
    1340  *
    1341  * Use the $prev_value parameter to differentiate between meta fields with the
    1342  * same key and user ID.
    1343  *
    1344  * If the meta field for the user does not exist, it will be added.
    1345  *
    1346  * @since 3.0.0
    1347  * @link https://codex.wordpress.org/Function_Reference/update_user_meta
    1348  *
    1349  * @param int    $user_id    User ID.
    1350  * @param string $meta_key   Metadata key.
    1351  * @param mixed  $meta_value Metadata value.
    1352  * @param mixed  $prev_value Optional. Previous value to check before removing.
    1353  * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
    1354  */
    1355 function update_user_meta($user_id, $meta_key, $meta_value, $prev_value = '') {
    1356     return update_metadata('user', $user_id, $meta_key, $meta_value, $prev_value);
    1357 }
    1358 
    1359 /**
    1360  * Count number of users who have each of the user roles.
    1361  *
    1362  * Assumes there are neither duplicated nor orphaned capabilities meta_values.
    1363  * Assumes role names are unique phrases. Same assumption made by WP_User_Query::prepare_query()
    1364  * Using $strategy = 'time' this is CPU-intensive and should handle around 10^7 users.
    1365  * Using $strategy = 'memory' this is memory-intensive and should handle around 10^5 users, but see WP Bug #12257.
    1366  *
    1367  * @since 3.0.0
    1368  *
    1369  * @global wpdb $wpdb
    1370  *
    1371  * @param string $strategy 'time' or 'memory'
    1372  * @return array Includes a grand total and an array of counts indexed by role strings.
    1373  */
    1374 function count_users($strategy = 'time') {
    1375     global $wpdb;
    1376 
    1377     // Initialize
    1378     $id = get_current_blog_id();
    1379     $blog_prefix = $wpdb->get_blog_prefix($id);
    1380     $result = array();
    1381 
    1382     if ( 'time' == $strategy ) {
    1383         $avail_roles = wp_roles()->get_names();
    1384 
    1385         // Build a CPU-intensive query that will return concise information.
    1386         $select_count = array();
    1387         foreach ( $avail_roles as $this_role => $name ) {
    1388             $select_count[] = $wpdb->prepare( "COUNT(NULLIF(`meta_value` LIKE %s, false))", '%' . $wpdb->esc_like( '"' . $this_role . '"' ) . '%');
    1389         }
    1390         $select_count = implode(', ', $select_count);
    1391 
    1392         // Add the meta_value index to the selection list, then run the query.
    1393         $row = $wpdb->get_row( "SELECT $select_count, COUNT(*) FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'", ARRAY_N );
    1394 
    1395         // Run the previous loop again to associate results with role names.
    1396         $col = 0;
    1397         $role_counts = array();
    1398         foreach ( $avail_roles as $this_role => $name ) {
    1399             $count = (int) $row[$col++];
    1400             if ($count > 0) {
    1401                 $role_counts[$this_role] = $count;
    1402             }
    1403         }
    1404 
    1405         // Get the meta_value index from the end of the result set.
    1406         $total_users = (int) $row[$col];
    1407 
    1408         $result['total_users'] = $total_users;
    1409         $result['avail_roles'] =& $role_counts;
    1410     } else {
    1411         $avail_roles = array();
    1412 
    1413         $users_of_blog = $wpdb->get_col( "SELECT meta_value FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'" );
    1414 
    1415         foreach ( $users_of_blog as $caps_meta ) {
    1416             $b_roles = maybe_unserialize($caps_meta);
    1417             if ( ! is_array( $b_roles ) )
    1418                 continue;
    1419             foreach ( $b_roles as $b_role => $val ) {
    1420                 if ( isset($avail_roles[$b_role]) ) {
    1421                     $avail_roles[$b_role]++;
    1422                 } else {
    1423                     $avail_roles[$b_role] = 1;
    1424                 }
    1425             }
    1426         }
    1427 
    1428         $result['total_users'] = count( $users_of_blog );
    1429         $result['avail_roles'] =& $avail_roles;
    1430     }
    1431 
    1432     return $result;
    1433 }
    1434 
    1435 //
    1436 // Private helper functions
    1437 //
    1438 
    1439 /**
    1440  * Set up global user vars.
    1441  *
    1442  * Used by wp_set_current_user() for back compat. Might be deprecated in the future.
    1443  *
    1444  * @since 2.0.4
    1445  *
    1446  * @global string $user_login    The user username for logging in
    1447  * @global object $userdata      User data.
    1448  * @global int    $user_level    The level of the user
    1449  * @global int    $user_ID       The ID of the user
    1450  * @global string $user_email    The email address of the user
    1451  * @global string $user_url      The url in the user's profile
    1452  * @global string $user_identity The display name of the user
    1453  *
    1454  * @param int $for_user_id Optional. User ID to set up global data.
    1455  */
    1456 function setup_userdata($for_user_id = '') {
    1457     global $user_login, $userdata, $user_level, $user_ID, $user_email, $user_url, $user_identity;
    1458 
    1459     if ( '' == $for_user_id )
    1460         $for_user_id = get_current_user_id();
    1461     $user = get_userdata( $for_user_id );
    1462 
    1463     if ( ! $user ) {
    1464         $user_ID = 0;
    1465         $user_level = 0;
    1466         $userdata = null;
    1467         $user_login = $user_email = $user_url = $user_identity = '';
    1468         return;
    1469     }
    1470 
    1471     $user_ID    = (int) $user->ID;
    1472     $user_level = (int) $user->user_level;
    1473     $userdata   = $user;
    1474     $user_login = $user->user_login;
    1475     $user_email = $user->user_email;
    1476     $user_url   = $user->user_url;
    1477     $user_identity = $user->display_name;
    1478 }
    1479 
    1480 /**
    1481  * Create dropdown HTML content of users.
    1482  *
    1483  * The content can either be displayed, which it is by default or retrieved by
    1484  * setting the 'echo' argument. The 'include' and 'exclude' arguments do not
    1485  * need to be used; all users will be displayed in that case. Only one can be
    1486  * used, either 'include' or 'exclude', but not both.
    1487  *
    1488  * The available arguments are as follows:
    1489  *
    1490  * @since 2.3.0
    1491  *
    1492  * @global wpdb $wpdb WordPress database object for queries.
    1493  * @global int  $blog_id
    1494  *
    1495  * @param array|string $args {
    1496  *     Optional. Array or string of arguments to generate a drop-down of users.
    1497  *     {@see WP_User_Query::prepare_query() for additional available arguments.
    1498  *
    1499  *     @type string       $show_option_all         Text to show as the drop-down default (all).
    1500  *                                                 Default empty.
    1501  *     @type string       $show_option_none        Text to show as the drop-down default when no
    1502  *                                                 users were found. Default empty.
    1503  *     @type int|string   $option_none_value       Value to use for $show_option_non when no users
    1504  *                                                 were found. Default -1.
    1505  *     @type string       $hide_if_only_one_author Whether to skip generating the drop-down
    1506  *                                                 if only one user was found. Default empty.
    1507  *     @type string       $orderby                 Field to order found users by. Accepts user fields.
    1508  *                                                 Default 'display_name'.
    1509  *     @type string       $order                   Whether to order users in ascending or descending
    1510  *                                                 order. Accepts 'ASC' (ascending) or 'DESC' (descending).
    1511  *                                                 Default 'ASC'.
    1512  *     @type array|string $include                 Array or comma-separated list of user IDs to include.
    1513  *                                                 Default empty.
    1514  *     @type array|string $exclude                 Array or comma-separated list of user IDs to exclude.
    1515  *                                                 Default empty.
    1516  *     @type bool|int     $multi                   Whether to skip the ID attribute on the 'select' element.
    1517  *                                                 Accepts 1|true or 0|false. Default 0|false.
    1518  *     @type string       $show                    User table column to display. If the selected item is empty
    1519  *                                                 then the 'user_login' will be displayed in parentheses.
    1520  *                                                 Accepts user fields. Default 'display_name'.
    1521  *     @type int|bool     $echo                    Whether to echo or return the drop-down. Accepts 1|true (echo)
    1522  *                                                 or 0|false (return). Default 1|true.
    1523  *     @type int          $selected                Which user ID should be selected. Default 0.
    1524  *     @type bool         $include_selected        Whether to always include the selected user ID in the drop-
    1525  *                                                 down. Default false.
    1526  *     @type string       $name                    Name attribute of select element. Default 'user'.
    1527  *     @type string       $id                      ID attribute of the select element. Default is the value of $name.
    1528  *     @type string       $class                   Class attribute of the select element. Default empty.
    1529  *     @type int          $blog_id                 ID of blog (Multisite only). Default is ID of the current blog.
    1530  *     @type string       $who                     Which type of users to query. Accepts only an empty string or
    1531  *                                                 'authors'. Default empty.
    1532  * }
    1533  * @return string String of HTML content.
    1534  */
    1535 function wp_dropdown_users( $args = '' ) {
    1536     $defaults = array(
    1537         'show_option_all' => '', 'show_option_none' => '', 'hide_if_only_one_author' => '',
    1538         'orderby' => 'display_name', 'order' => 'ASC',
    1539         'include' => '', 'exclude' => '', 'multi' => 0,
    1540         'show' => 'display_name', 'echo' => 1,
    1541         'selected' => 0, 'name' => 'user', 'class' => '', 'id' => '',
    1542         'blog_id' => $GLOBALS['blog_id'], 'who' => '', 'include_selected' => false,
    1543         'option_none_value' => -1
    1544     );
    1545 
    1546     $defaults['selected'] = is_author() ? get_query_var( 'author' ) : 0;
    1547 
    1548     $r = wp_parse_args( $args, $defaults );
    1549     $show = $r['show'];
    1550     $show_option_all = $r['show_option_all'];
    1551     $show_option_none = $r['show_option_none'];
    1552     $option_none_value = $r['option_none_value'];
    1553 
    1554     $query_args = wp_array_slice_assoc( $r, array( 'blog_id', 'include', 'exclude', 'orderby', 'order', 'who' ) );
    1555     $query_args['fields'] = array( 'ID', 'user_login', $show );
    1556     $users = get_users( $query_args );
    1557 
    1558     $output = '';
    1559     if ( ! empty( $users ) && ( empty( $r['hide_if_only_one_author'] ) || count( $users ) > 1 ) ) {
    1560         $name = esc_attr( $r['name'] );
    1561         if ( $r['multi'] && ! $r['id'] ) {
    1562             $id = '';
    1563         } else {
    1564             $id = $r['id'] ? " id='" . esc_attr( $r['id'] ) . "'" : " id='$name'";
    1565         }
    1566         $output = "<select name='{$name}'{$id} class='" . $r['class'] . "'>\n";
    1567 
    1568         if ( $show_option_all ) {
    1569             $output .= "\t<option value='0'>$show_option_all</option>\n";
    1570         }
    1571 
    1572         if ( $show_option_none ) {
    1573             $_selected = selected( $option_none_value, $r['selected'], false );
    1574             $output .= "\t<option value='" . esc_attr( $option_none_value ) . "'$_selected>$show_option_none</option>\n";
    1575         }
    1576 
    1577         $found_selected = false;
    1578         foreach ( (array) $users as $user ) {
    1579             $user->ID = (int) $user->ID;
    1580             $_selected = selected( $user->ID, $r['selected'], false );
    1581             if ( $_selected ) {
    1582                 $found_selected = true;
    1583             }
    1584             $display = ! empty( $user->$show ) ? $user->$show : '('. $user->user_login . ')';
    1585             $output .= "\t<option value='$user->ID'$_selected>" . esc_html( $display ) . "</option>\n";
    1586         }
    1587 
    1588         if ( $r['include_selected'] && ! $found_selected && ( $r['selected'] > 0 ) ) {
    1589             $user = get_userdata( $r['selected'] );
    1590             $_selected = selected( $user->ID, $r['selected'], false );
    1591             $display = ! empty( $user->$show ) ? $user->$show : '('. $user->user_login . ')';
    1592             $output .= "\t<option value='$user->ID'$_selected>" . esc_html( $display ) . "</option>\n";
    1593         }
    1594 
    1595         $output .= "</select>";
    1596     }
    1597 
    1598     /**
    1599      * Filter the wp_dropdown_users() HTML output.
    1600      *
    1601      * @since 2.3.0
    1602      *
    1603      * @param string $output HTML output generated by wp_dropdown_users().
    1604      */
    1605     $html = apply_filters( 'wp_dropdown_users', $output );
    1606 
    1607     if ( $r['echo'] ) {
    1608         echo $html;
    1609     }
    1610     return $html;
    1611 }
    1612 
    1613 /**
    1614  * Sanitize user field based on context.
    1615  *
    1616  * Possible context values are:  'raw', 'edit', 'db', 'display', 'attribute' and 'js'. The
    1617  * 'display' context is used by default. 'attribute' and 'js' contexts are treated like 'display'
    1618  * when calling filters.
    1619  *
    1620  * @since 2.3.0
    1621  *
    1622  * @param string $field   The user Object field name.
    1623  * @param mixed  $value   The user Object value.
    1624  * @param int    $user_id User ID.
    1625  * @param string $context How to sanitize user fields. Looks for 'raw', 'edit', 'db', 'display',
    1626  *                        'attribute' and 'js'.
    1627  * @return mixed Sanitized value.
    1628  */
    1629 function sanitize_user_field($field, $value, $user_id, $context) {
    1630     $int_fields = array('ID');
    1631     if ( in_array($field, $int_fields) )
    1632         $value = (int) $value;
    1633 
    1634     if ( 'raw' == $context )
    1635         return $value;
    1636 
    1637     if ( !is_string($value) && !is_numeric($value) )
    1638         return $value;
    1639 
    1640     $prefixed = false !== strpos( $field, 'user_' );
    1641 
    1642     if ( 'edit' == $context ) {
    1643         if ( $prefixed ) {
    1644 
    1645             /** This filter is documented in wp-includes/post.php */
    1646             $value = apply_filters( "edit_{$field}", $value, $user_id );
    1647         } else {
    1648 
    1649             /**
    1650              * Filter a user field value in the 'edit' context.
    1651              *
    1652              * The dynamic portion of the hook name, `$field`, refers to the prefixed user
    1653              * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.
    1654              *
    1655              * @since 2.9.0
    1656              *
    1657              * @param mixed $value   Value of the prefixed user field.
    1658              * @param int   $user_id User ID.
    1659              */
    1660             $value = apply_filters( "edit_user_{$field}", $value, $user_id );
    1661         }
    1662 
    1663         if ( 'description' == $field )
    1664             $value = esc_html( $value ); // textarea_escaped?
    1665         else
    1666             $value = esc_attr($value);
    1667     } elseif ( 'db' == $context ) {
    1668         if ( $prefixed ) {
    1669             /** This filter is documented in wp-includes/post.php */
    1670             $value = apply_filters( "pre_{$field}", $value );
    1671         } else {
    1672 
    1673             /**
    1674              * Filter the value of a user field in the 'db' context.
    1675              *
    1676              * The dynamic portion of the hook name, `$field`, refers to the prefixed user
    1677              * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.
    1678              *
    1679              * @since 2.9.0
    1680              *
    1681              * @param mixed $value Value of the prefixed user field.
    1682              */
    1683             $value = apply_filters( "pre_user_{$field}", $value );
    1684         }
    1685     } else {
    1686         // Use display filters by default.
    1687         if ( $prefixed ) {
    1688 
    1689             /** This filter is documented in wp-includes/post.php */
    1690             $value = apply_filters( $field, $value, $user_id, $context );
    1691         } else {
    1692 
    1693             /**
    1694              * Filter the value of a user field in a standard context.
    1695              *
    1696              * The dynamic portion of the hook name, `$field`, refers to the prefixed user
    1697              * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.
    1698              *
    1699              * @since 2.9.0
    1700              *
    1701              * @param mixed  $value   The user object value to sanitize.
    1702              * @param int    $user_id User ID.
    1703              * @param string $context The context to filter within.
    1704              */
    1705             $value = apply_filters( "user_{$field}", $value, $user_id, $context );
    1706         }
    1707     }
    1708 
    1709     if ( 'user_url' == $field )
    1710         $value = esc_url($value);
    1711 
    1712     if ( 'attribute' == $context ) {
    1713         $value = esc_attr( $value );
    1714     } elseif ( 'js' == $context ) {
    1715         $value = esc_js( $value );
    1716     }
    1717     return $value;
    1718 }
    1719 
    1720 /**
    1721  * Update all user caches
    1722  *
    1723  * @since 3.0.0
    1724  *
    1725  * @param object $user User object to be cached
    1726  */
    1727 function update_user_caches($user) {
    1728     wp_cache_add($user->ID, $user, 'users');
    1729     wp_cache_add($user->user_login, $user->ID, 'userlogins');
    1730     wp_cache_add($user->user_email, $user->ID, 'useremail');
    1731     wp_cache_add($user->user_nicename, $user->ID, 'userslugs');
    1732 }
    1733 
    1734 /**
    1735  * Clean all user caches
    1736  *
    1737  * @since 3.0.0
    1738  *
    1739  * @param WP_User|int $user User object or ID to be cleaned from the cache
    1740  */
    1741 function clean_user_cache( $user ) {
    1742     if ( is_numeric( $user ) )
    1743         $user = new WP_User( $user );
    1744 
    1745     if ( ! $user->exists() )
    1746         return;
    1747 
    1748     wp_cache_delete( $user->ID, 'users' );
    1749     wp_cache_delete( $user->user_login, 'userlogins' );
    1750     wp_cache_delete( $user->user_email, 'useremail' );
    1751     wp_cache_delete( $user->user_nicename, 'userslugs' );
    1752 }
    1753 
    1754 /**
    1755  * Checks whether the given username exists.
    1756  *
    1757  * @since 2.0.0
    1758  *
    1759  * @param string $username Username.
    1760  * @return int|false The user's ID on success, and false on failure.
    1761  */
    1762 function username_exists( $username ) {
    1763     if ( $user = get_user_by( 'login', $username ) ) {
    1764         return $user->ID;
    1765     }
    1766     return false;
    1767 }
    1768 
    1769 /**
    1770  * Checks whether the given email exists.
    1771  *
    1772  * @since 2.1.0
    1773  *
    1774  * @param string $email Email.
    1775  * @return int|false The user's ID on success, and false on failure.
    1776  */
    1777 function email_exists( $email ) {
    1778     if ( $user = get_user_by( 'email', $email) ) {
    1779         return $user->ID;
    1780     }
    1781     return false;
    1782 }
    1783 
    1784 /**
    1785  * Checks whether a username is valid.
    1786  *
    1787  * @since 2.0.1
    1788  *
    1789  * @param string $username Username.
    1790  * @return bool Whether username given is valid
    1791  */
    1792 function validate_username( $username ) {
    1793     $sanitized = sanitize_user( $username, true );
    1794     $valid = ( $sanitized == $username );
    1795     /**
    1796      * Filter whether the provided username is valid or not.
    1797      *
    1798      * @since 2.0.1
    1799      *
    1800      * @param bool   $valid    Whether given username is valid.
    1801      * @param string $username Username to check.
    1802      */
    1803     return apply_filters( 'validate_username', $valid, $username );
    1804 }
    1805 
    1806 /**
    1807  * Insert a user into the database.
    1808  *
    1809  * Most of the `$userdata` array fields have filters associated with the values. Exceptions are
    1810  * 'ID', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl',
    1811  * 'user_registered', and 'role'. The filters have the prefix 'pre_user_' followed by the field
    1812  * name. An example using 'description' would have the filter called, 'pre_user_description' that
    1813  * can be hooked into.
    1814  *
    1815  * @since 2.0.0
    1816  * @since 3.6.0 The `aim`, `jabber`, and `yim` fields were removed as default user contact
    1817  *              methods for new installs. See wp_get_user_contact_methods().
    1818  *
    1819  * @global wpdb $wpdb WordPress database object for queries.
    1820  *
    1821  * @param array|object|WP_User $userdata {
    1822  *     An array, object, or WP_User object of user data arguments.
    1823  *
    1824  *     @type int         $ID                   User ID. If supplied, the user will be updated.
    1825  *     @type string      $user_pass            The plain-text user password.
    1826  *     @type string      $user_login           The user's login username.
    1827  *     @type string      $user_nicename        The URL-friendly user name.
    1828  *     @type string      $user_url             The user URL.
    1829  *     @type string      $user_email           The user email address.
    1830  *     @type string      $display_name         The user's display name.
    1831  *                                             Default is the the user's username.
    1832  *     @type string      $nickname             The user's nickname.
    1833  *                                             Default is the the user's username.
    1834  *     @type string      $first_name           The user's first name. For new users, will be used
    1835  *                                             to build the first part of the user's display name
    1836  *                                             if `$display_name` is not specified.
    1837  *     @type string      $last_name            The user's last name. For new users, will be used
    1838  *                                             to build the second part of the user's display name
    1839  *                                             if `$display_name` is not specified.
    1840  *     @type string      $description          The user's biographical description.
    1841  *     @type string|bool $rich_editing         Whether to enable the rich-editor for the user.
    1842  *                                             False if not empty.
    1843  *     @type string|bool $comment_shortcuts    Whether to enable comment moderation keyboard
    1844  *                                             shortcuts for the user. Default false.
    1845  *     @type string      $admin_color          Admin color scheme for the user. Default 'fresh'.
    1846  *     @type bool        $use_ssl              Whether the user should always access the admin over
    1847  *                                             https. Default false.
    1848  *     @type string      $user_registered      Date the user registered. Format is 'Y-m-d H:i:s'.
    1849  *     @type string|bool $show_admin_bar_front Whether to display the Admin Bar for the user on the
    1850  *                                             site's frontend. Default true.
    1851  *     @type string      $role                 User's role.
    1852  * }
    1853  * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not
    1854  *                      be created.
    1855  */
    1856 function wp_insert_user( $userdata ) {
    1857     global $wpdb;
    1858 
    1859     if ( $userdata instanceof stdClass ) {
    1860         $userdata = get_object_vars( $userdata );
    1861     } elseif ( $userdata instanceof WP_User ) {
    1862         $userdata = $userdata->to_array();
    1863     }
    1864     // Are we updating or creating?
    1865     if ( ! empty( $userdata['ID'] ) ) {
    1866         $ID = (int) $userdata['ID'];
    1867         $update = true;
    1868         $old_user_data = WP_User::get_data_by( 'id', $ID );
    1869         // hashed in wp_update_user(), plaintext if called directly
    1870         $user_pass = $userdata['user_pass'];
    1871     } else {
    1872         $update = false;
    1873         // Hash the password
    1874         $user_pass = wp_hash_password( $userdata['user_pass'] );
    1875     }
    1876 
    1877     $sanitized_user_login = sanitize_user( $userdata['user_login'], true );
    1878 
    1879     /**
    1880      * Filter a username after it has been sanitized.
    1881      *
    1882      * This filter is called before the user is created or updated.
    1883      *
    1884      * @since 2.0.3
    1885      *
    1886      * @param string $sanitized_user_login Username after it has been sanitized.
    1887      */
    1888     $pre_user_login = apply_filters( 'pre_user_login', $sanitized_user_login );
    1889 
    1890     //Remove any non-printable chars from the login string to see if we have ended up with an empty username
    1891     $user_login = trim( $pre_user_login );
    1892 
    1893     if ( empty( $user_login ) ) {
    1894         return new WP_Error('empty_user_login', __('Cannot create a user with an empty login name.') );
    1895     }
    1896     if ( ! $update && username_exists( $user_login ) ) {
    1897         return new WP_Error( 'existing_user_login', __( 'Sorry, that username already exists!' ) );
    1898     }
    1899 
    1900     // If a nicename is provided, remove unsafe user characters before
    1901     // using it. Otherwise build a nicename from the user_login.
    1902     if ( ! empty( $userdata['user_nicename'] ) ) {
    1903         $user_nicename = sanitize_user( $userdata['user_nicename'], true );
    1904     } else {
    1905         $user_nicename = $user_login;
    1906     }
    1907 
    1908     $user_nicename = sanitize_title( $user_nicename );
    1909 
    1910     // Store values to save in user meta.
    1911     $meta = array();
    1912 
    1913     /**
    1914      * Filter a user's nicename before the user is created or updated.
    1915      *
    1916      * @since 2.0.3
    1917      *
    1918      * @param string $user_nicename The user's nicename.
    1919      */
    1920     $user_nicename = apply_filters( 'pre_user_nicename', $user_nicename );
    1921 
    1922     $raw_user_url = empty( $userdata['user_url'] ) ? '' : $userdata['user_url'];
    1923 
    1924     /**
    1925      * Filter a user's URL before the user is created or updated.
    1926      *
    1927      * @since 2.0.3
    1928      *
    1929      * @param string $raw_user_url The user's URL.
    1930      */
    1931     $user_url = apply_filters( 'pre_user_url', $raw_user_url );
    1932 
    1933     $raw_user_email = empty( $userdata['user_email'] ) ? '' : $userdata['user_email'];
    1934 
    1935     /**
    1936      * Filter a user's email before the user is created or updated.
    1937      *
    1938      * @since 2.0.3
    1939      *
    1940      * @param string $raw_user_email The user's email.
    1941      */
    1942     $user_email = apply_filters( 'pre_user_email', $raw_user_email );
    1943 
    1944     /*
    1945      * If there is no update, just check for `email_exists`. If there is an update,
    1946      * check if current email and new email are the same, or not, and check `email_exists`
    1947      * accordingly.
    1948      */
    1949     if ( ( ! $update || ( ! empty( $old_user_data ) && 0 !== strcasecmp( $user_email, $old_user_data->user_email ) ) )
    1950         && ! defined( 'WP_IMPORTING' )
    1951         && email_exists( $user_email )
    1952     ) {
    1953         return new WP_Error( 'existing_user_email', __( 'Sorry, that email address is already used!' ) );
    1954     }
    1955     $nickname = empty( $userdata['nickname'] ) ? $user_login : $userdata['nickname'];
    1956 
    1957     /**
    1958      * Filter a user's nickname before the user is created or updated.
    1959      *
    1960      * @since 2.0.3
    1961      *
    1962      * @param string $nickname The user's nickname.
    1963      */
    1964     $meta['nickname'] = apply_filters( 'pre_user_nickname', $nickname );
    1965 
    1966     $first_name = empty( $userdata['first_name'] ) ? '' : $userdata['first_name'];
    1967 
    1968     /**
    1969      * Filter a user's first name before the user is created or updated.
    1970      *
    1971      * @since 2.0.3
    1972      *
    1973      * @param string $first_name The user's first name.
    1974      */
    1975     $meta['first_name'] = apply_filters( 'pre_user_first_name', $first_name );
    1976 
    1977     $last_name = empty( $userdata['last_name'] ) ? '' : $userdata['last_name'];
    1978 
    1979     /**
    1980      * Filter a user's last name before the user is created or updated.
    1981      *
    1982      * @since 2.0.3
    1983      *
    1984      * @param string $last_name The user's last name.
    1985      */
    1986     $meta['last_name'] = apply_filters( 'pre_user_last_name', $last_name );
    1987 
    1988     if ( empty( $userdata['display_name'] ) ) {
    1989         if ( $update ) {
    1990             $display_name = $user_login;
    1991         } elseif ( $meta['first_name'] && $meta['last_name'] ) {
    1992             /* translators: 1: first name, 2: last name */
    1993             $display_name = sprintf( _x( '%1$s %2$s', 'Display name based on first name and last name' ), $meta['first_name'], $meta['last_name'] );
    1994         } elseif ( $meta['first_name'] ) {
    1995             $display_name = $meta['first_name'];
    1996         } elseif ( $meta['last_name'] ) {
    1997             $display_name = $meta['last_name'];
    1998         } else {
    1999             $display_name = $user_login;
    2000         }
    2001     } else {
    2002         $display_name = $userdata['display_name'];
    2003     }
    2004 
    2005     /**
    2006      * Filter a user's display name before the user is created or updated.
    2007      *
    2008      * @since 2.0.3
    2009      *
    2010      * @param string $display_name The user's display name.
    2011      */
    2012     $display_name = apply_filters( 'pre_user_display_name', $display_name );
    2013 
    2014     $description = empty( $userdata['description'] ) ? '' : $userdata['description'];
    2015 
    2016     /**
    2017      * Filter a user's description before the user is created or updated.
    2018      *
    2019      * @since 2.0.3
    2020      *
    2021      * @param string $description The user's description.
    2022      */
    2023     $meta['description'] = apply_filters( 'pre_user_description', $description );
    2024 
    2025     $meta['rich_editing'] = empty( $userdata['rich_editing'] ) ? 'true' : $userdata['rich_editing'];
    2026 
    2027     $meta['comment_shortcuts'] = empty( $userdata['comment_shortcuts'] ) || 'false' === $userdata['comment_shortcuts'] ? 'false' : 'true';
    2028 
    2029     $admin_color = empty( $userdata['admin_color'] ) ? 'fresh' : $userdata['admin_color'];
    2030     $meta['admin_color'] = preg_replace( '|[^a-z0-9 _.\-@]|i', '', $admin_color );
    2031 
    2032     $meta['use_ssl'] = empty( $userdata['use_ssl'] ) ? 0 : $userdata['use_ssl'];
    2033 
    2034     $user_registered = empty( $userdata['user_registered'] ) ? gmdate( 'Y-m-d H:i:s' ) : $userdata['user_registered'];
    2035 
    2036     $meta['show_admin_bar_front'] = empty( $userdata['show_admin_bar_front'] ) ? 'true' : $userdata['show_admin_bar_front'];
    2037 
    2038     $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $user_nicename, $user_login));
    2039 
    2040     if ( $user_nicename_check ) {
    2041         $suffix = 2;
    2042         while ($user_nicename_check) {
    2043             $alt_user_nicename = $user_nicename . "-$suffix";
    2044             $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $alt_user_nicename, $user_login));
    2045             $suffix++;
    2046         }
    2047         $user_nicename = $alt_user_nicename;
    2048     }
    2049 
    2050     $compacted = compact( 'user_pass', 'user_email', 'user_url', 'user_nicename', 'display_name', 'user_registered' );
    2051     $data = wp_unslash( $compacted );
    2052 
    2053     if ( $update ) {
    2054         if ( $user_email !== $old_user_data->user_email ) {
    2055             $data['user_activation_key'] = '';
    2056         }
    2057         $wpdb->update( $wpdb->users, $data, compact( 'ID' ) );
    2058         $user_id = (int) $ID;
    2059     } else {
    2060         $wpdb->insert( $wpdb->users, $data + compact( 'user_login' ) );
    2061         $user_id = (int) $wpdb->insert_id;
    2062     }
    2063 
    2064     $user = new WP_User( $user_id );
    2065 
    2066     /**
    2067      * Filter a user's meta values and keys before the user is created or updated.
    2068      *
    2069      * Does not include contact methods. These are added using `wp_get_user_contact_methods( $user )`.
    2070      *
    2071      * @since 4.4.0
    2072      *
    2073      * @param array $meta {
    2074      *     Default meta values and keys for the user.
    2075      *
    2076      *     @type string   $nickname             The user's nickname. Default is the the user's username.
    2077      *     @type string   $first_name           The user's first name.
    2078      *     @type string   $last_name            The user's last name.
    2079      *     @type string   $description          The user's description.
    2080      *     @type bool     $rich_editing         Whether to enable the rich-editor for the user. False if not empty.
    2081      *     @type bool     $comment_shortcuts    Whether to enable keyboard shortcuts for the user. Default false.
    2082      *     @type string   $admin_color          The color scheme for a user's admin screen. Default 'fresh'.
    2083      *     @type int|bool $use_ssl              Whether to force SSL on the user's admin area. 0|false if SSL is
    2084      *                                          not forced.
    2085      *     @type bool     $show_admin_bar_front Whether to show the admin bar on the front end for the user.
    2086      *                                          Default true.
    2087      * }
    2088      * @param WP_User $user User object.
    2089      */
    2090     $meta = apply_filters( 'insert_user_meta', $meta, $user );
    2091 
    2092     // Update user meta.
    2093     foreach ( $meta as $key => $value ) {
    2094         update_user_meta( $user_id, $key, $value );
    2095     }
    2096 
    2097     foreach ( wp_get_user_contact_methods( $user ) as $key => $value ) {
    2098         if ( isset( $userdata[ $key ] ) ) {
    2099             update_user_meta( $user_id, $key, $userdata[ $key ] );
    2100         }
    2101     }
    2102 
    2103     if ( isset( $userdata['role'] ) ) {
    2104         $user->set_role( $userdata['role'] );
    2105     } elseif ( ! $update ) {
    2106         $user->set_role(get_option('default_role'));
    2107     }
    2108     wp_cache_delete( $user_id, 'users' );
    2109     wp_cache_delete( $user_login, 'userlogins' );
    2110 
    2111     if ( $update ) {
    2112         /**
    2113          * Fires immediately after an existing user is updated.
    2114          *
    2115          * @since 2.0.0
    2116          *
    2117          * @param int    $user_id       User ID.
    2118          * @param object $old_user_data Object containing user's data prior to update.
    2119          */
    2120         do_action( 'profile_update', $user_id, $old_user_data );
    2121     } else {
    2122         /**
    2123          * Fires immediately after a new user is registered.
    2124          *
    2125          * @since 1.5.0
    2126          *
    2127          * @param int $user_id User ID.
    2128          */
    2129         do_action( 'user_register', $user_id );
    2130     }
    2131 
    2132     return $user_id;
    2133 }
    2134 
    2135 /**
    2136  * Update a user in the database.
    2137  *
    2138  * It is possible to update a user's password by specifying the 'user_pass'
    2139  * value in the $userdata parameter array.
    2140  *
    2141  * If current user's password is being updated, then the cookies will be
    2142  * cleared.
    2143  *
    2144  * @since 2.0.0
    2145  *
    2146  * @see wp_insert_user() For what fields can be set in $userdata.
    2147  *
    2148  * @param mixed $userdata An array of user data or a user object of type stdClass or WP_User.
    2149  * @return int|WP_Error The updated user's ID or a WP_Error object if the user could not be updated.
    2150  */
    2151 function wp_update_user($userdata) {
    2152     if ( $userdata instanceof stdClass ) {
    2153         $userdata = get_object_vars( $userdata );
    2154     } elseif ( $userdata instanceof WP_User ) {
    2155         $userdata = $userdata->to_array();
    2156     }
    2157 
    2158     $ID = isset( $userdata['ID'] ) ? (int) $userdata['ID'] : 0;
    2159     if ( ! $ID ) {
    2160         return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
    2161     }
    2162 
    2163     // First, get all of the original fields
    2164     $user_obj = get_userdata( $ID );
    2165     if ( ! $user_obj ) {
    2166         return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
    2167     }
    2168 
    2169     $user = $user_obj->to_array();
    2170 
    2171     // Add additional custom fields
    2172     foreach ( _get_additional_user_keys( $user_obj ) as $key ) {
    2173         $user[ $key ] = get_user_meta( $ID, $key, true );
    2174     }
    2175 
    2176     // Escape data pulled from DB.
    2177     $user = add_magic_quotes( $user );
    2178 
    2179     if ( ! empty($userdata['user_pass']) ) {
    2180         // If password is changing, hash it now
    2181         $plaintext_pass = $userdata['user_pass'];
    2182         $userdata['user_pass'] = wp_hash_password( $userdata['user_pass'] );
    2183 
    2184         /**
    2185          * Filter whether to send the password change email.
    2186          *
    2187          * @since 4.3.0
    2188          *
    2189          * @see wp_insert_user() For `$user` and `$userdata` fields.
    2190          *
    2191          * @param bool  $send     Whether to send the email.
    2192          * @param array $user     The original user array.
    2193          * @param array $userdata The updated user array.
    2194          *
    2195          */
    2196         $send_password_change_email = apply_filters( 'send_password_change_email', true, $user, $userdata );
    2197     }
    2198 
    2199     if ( isset( $userdata['user_email'] ) && $user['user_email'] !== $userdata['user_email'] ) {
    2200         /**
    2201          * Filter whether to send the email change email.
    2202          *
    2203          * @since 4.3.0
    2204          *
    2205          * @see wp_insert_user() For `$user` and `$userdata` fields.
    2206          *
    2207          * @param bool  $send     Whether to send the email.
    2208          * @param array $user     The original user array.
    2209          * @param array $userdata The updated user array.
    2210          *
    2211          */
    2212         $send_email_change_email = apply_filters( 'send_email_change_email', true, $user, $userdata );
    2213     }
    2214 
    2215     wp_cache_delete( $user['user_email'], 'useremail' );
    2216 
    2217     // Merge old and new fields with new fields overwriting old ones.
    2218     $userdata = array_merge( $user, $userdata );
    2219     $user_id = wp_insert_user( $userdata );
    2220 
    2221     if ( ! is_wp_error( $user_id ) ) {
    2222 
    2223         $blog_name = wp_specialchars_decode( get_option( 'blogname' ) );
    2224 
    2225         if ( ! empty( $send_password_change_email ) ) {
    2226 
    2227             /* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
    2228             $pass_change_text = __( 'Hi ###USERNAME###,
    2229 
    2230 This notice confirms that your password was changed on ###SITENAME###.
    2231 
    2232 If you did not change your password, please contact the Site Administrator at
    2233 ###ADMIN_EMAIL###
    2234 
    2235 This email has been sent to ###EMAIL###
    2236 
    2237 Regards,
    2238 All at ###SITENAME###
    2239 ###SITEURL###' );
    2240 
    2241             $pass_change_email = array(
    2242                 'to'      => $user['user_email'],
    2243                 'subject' => __( '[%s] Notice of Password Change' ),
    2244                 'message' => $pass_change_text,
    2245                 'headers' => '',
    2246             );
    2247 
    2248             /**
    2249              * Filter the contents of the email sent when the user's password is changed.
    2250              *
    2251              * @since 4.3.0
    2252              *
    2253              * @param array $pass_change_email {
    2254              *            Used to build wp_mail().
    2255              *            @type string $to      The intended recipients. Add emails in a comma separated string.
    2256              *            @type string $subject The subject of the email.
    2257              *            @type string $message The content of the email.
    2258              *                The following strings have a special meaning and will get replaced dynamically:
    2259              *                - ###USERNAME###    The current user's username.
    2260              *                - ###ADMIN_EMAIL### The admin email in case this was unexpected.
    2261              *                - ###EMAIL###       The old email.
    2262              *                - ###SITENAME###    The name of the site.
    2263              *                - ###SITEURL###     The URL to the site.
    2264              *            @type string $headers Headers. Add headers in a newline (\r\n) separated string.
    2265              *        }
    2266              * @param array $user     The original user array.
    2267              * @param array $userdata The updated user array.
    2268              *
    2269              */
    2270             $pass_change_email = apply_filters( 'password_change_email', $pass_change_email, $user, $userdata );
    2271 
    2272             $pass_change_email['message'] = str_replace( '###USERNAME###', $user['user_login'], $pass_change_email['message'] );
    2273             $pass_change_email['message'] = str_replace( '###ADMIN_EMAIL###', get_option( 'admin_email' ), $pass_change_email['message'] );
    2274             $pass_change_email['message'] = str_replace( '###EMAIL###', $user['user_email'], $pass_change_email['message'] );
    2275             $pass_change_email['message'] = str_replace( '###SITENAME###', get_option( 'blogname' ), $pass_change_email['message'] );
    2276             $pass_change_email['message'] = str_replace( '###SITEURL###', get_option( 'siteurl' ), $pass_change_email['message'] );
    2277 
    2278             wp_mail( $pass_change_email['to'], sprintf( $pass_change_email['subject'], $blog_name ), $pass_change_email['message'], $pass_change_email['headers'] );
    2279         }
    2280 
    2281         if ( ! empty( $send_email_change_email ) ) {
    2282             /* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
    2283             $email_change_text = __( 'Hi ###USERNAME###,
    2284 
    2285 This notice confirms that your email was changed on ###SITENAME###.
    2286 
    2287 If you did not change your email, please contact the Site Administrator at
    2288 ###ADMIN_EMAIL###
    2289 
    2290 This email has been sent to ###EMAIL###
    2291 
    2292 Regards,
    2293 All at ###SITENAME###
    2294 ###SITEURL###' );
    2295 
    2296             $email_change_email = array(
    2297                 'to'      => $user['user_email'],
    2298                 'subject' => __( '[%s] Notice of Email Change' ),
    2299                 'message' => $email_change_text,
    2300                 'headers' => '',
    2301             );
    2302 
    2303             /**
    2304              * Filter the contents of the email sent when the user's email is changed.
    2305              *
    2306              * @since 4.3.0
    2307              *
    2308              * @param array $email_change_email {
    2309              *            Used to build wp_mail().
    2310              *            @type string $to      The intended recipients.
    2311              *            @type string $subject The subject of the email.
    2312              *            @type string $message The content of the email.
    2313              *                The following strings have a special meaning and will get replaced dynamically:
    2314              *                - ###USERNAME###    The current user's username.
    2315              *                - ###ADMIN_EMAIL### The admin email in case this was unexpected.
    2316              *                - ###EMAIL###       The old email.
    2317              *                - ###SITENAME###    The name of the site.
    2318              *                - ###SITEURL###     The URL to the site.
    2319              *            @type string $headers Headers.
    2320              *        }
    2321              * @param array $user The original user array.
    2322              * @param array $userdata The updated user array.
    2323              */
    2324             $email_change_email = apply_filters( 'email_change_email', $email_change_email, $user, $userdata );
    2325 
    2326             $email_change_email['message'] = str_replace( '###USERNAME###', $user['user_login'], $email_change_email['message'] );
    2327             $email_change_email['message'] = str_replace( '###ADMIN_EMAIL###', get_option( 'admin_email' ), $email_change_email['message'] );
    2328             $email_change_email['message'] = str_replace( '###EMAIL###', $user['user_email'], $email_change_email['message'] );
    2329             $email_change_email['message'] = str_replace( '###SITENAME###', get_option( 'blogname' ), $email_change_email['message'] );
    2330             $email_change_email['message'] = str_replace( '###SITEURL###', get_option( 'siteurl' ), $email_change_email['message'] );
    2331 
    2332             wp_mail( $email_change_email['to'], sprintf( $email_change_email['subject'], $blog_name ), $email_change_email['message'], $email_change_email['headers'] );
    2333         }
    2334     }
    2335 
    2336     // Update the cookies if the password changed.
    2337     $current_user = wp_get_current_user();
    2338     if ( $current_user->ID == $ID ) {
    2339         if ( isset($plaintext_pass) ) {
    2340             wp_clear_auth_cookie();
    2341 
    2342             // Here we calculate the expiration length of the current auth cookie and compare it to the default expiration.
    2343             // If it's greater than this, then we know the user checked 'Remember Me' when they logged in.
    2344             $logged_in_cookie    = wp_parse_auth_cookie( '', 'logged_in' );
    2345             /** This filter is documented in wp-includes/pluggable.php */
    2346             $default_cookie_life = apply_filters( 'auth_cookie_expiration', ( 2 * DAY_IN_SECONDS ), $ID, false );
    2347             $remember            = ( ( $logged_in_cookie['expiration'] - time() ) > $default_cookie_life );
    2348 
    2349             wp_set_auth_cookie( $ID, $remember );
    2350         }
    2351     }
    2352 
    2353     return $user_id;
    2354 }
    2355 
    2356 /**
    2357  * A simpler way of inserting a user into the database.
    2358  *
    2359  * Creates a new user with just the username, password, and email. For more
    2360  * complex user creation use {@see wp_insert_user()} to specify more information.
    2361  *
    2362  * @since 2.0.0
    2363  * @see wp_insert_user() More complete way to create a new user
    2364  *
    2365  * @param string $username The user's username.
    2366  * @param string $password The user's password.
    2367  * @param string $email    Optional. The user's email. Default empty.
    2368  * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not
    2369  *                      be created.
    2370  */
    2371 function wp_create_user($username, $password, $email = '') {
    2372     $user_login = wp_slash( $username );
    2373     $user_email = wp_slash( $email    );
    2374     $user_pass = $password;
    2375 
    2376     $userdata = compact('user_login', 'user_email', 'user_pass');
    2377     return wp_insert_user($userdata);
    2378 }
    2379 
    2380 /**
    2381  * Returns a list of meta keys to be (maybe) populated in wp_update_user().
    2382  *
    2383  * The list of keys returned via this function are dependent on the presence
    2384  * of those keys in the user meta data to be set.
    2385  *
    2386  * @since 3.3.0
    2387  * @access private
    2388  *
    2389  * @param WP_User $user WP_User instance.
    2390  * @return array List of user keys to be populated in wp_update_user().
    2391  */
    2392 function _get_additional_user_keys( $user ) {
    2393     $keys = array( 'first_name', 'last_name', 'nickname', 'description', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl', 'show_admin_bar_front' );
    2394     return array_merge( $keys, array_keys( wp_get_user_contact_methods( $user ) ) );
    2395 }
    2396 
    2397 /**
    2398  * Set up the user contact methods.
    2399  *
    2400  * Default contact methods were removed in 3.6. A filter dictates contact methods.
    2401  *
    2402  * @since 3.7.0
    2403  *
    2404  * @param WP_User $user Optional. WP_User object.
    2405  * @return array Array of contact methods and their labels.
    2406  */
    2407 function wp_get_user_contact_methods( $user = null ) {
    2408     $methods = array();
    2409     if ( get_site_option( 'initial_db_version' ) < 23588 ) {
    2410         $methods = array(
    2411             'aim'    => __( 'AIM' ),
    2412             'yim'    => __( 'Yahoo IM' ),
    2413             'jabber' => __( 'Jabber / Google Talk' )
    2414         );
    2415     }
    2416 
    2417     /**
    2418      * Filter the user contact methods.
    2419      *
    2420      * @since 2.9.0
    2421      *
    2422      * @param array   $methods Array of contact methods and their labels.
    2423      * @param WP_User $user    WP_User object.
    2424      */
    2425     return apply_filters( 'user_contactmethods', $methods, $user );
    2426 }
    2427 
    2428 /**
    2429  * The old private function for setting up user contact methods.
    2430  *
    2431  * @since 2.9.0
    2432  * @access private
    2433  */
    2434 function _wp_get_user_contactmethods( $user = null ) {
    2435     return wp_get_user_contact_methods( $user );
    2436 }
    2437 
    2438 /**
    2439  * Gets the text suggesting how to create strong passwords.
    2440  *
    2441  * @since 4.1.0
    2442  *
    2443  * @return string The password hint text.
    2444  */
    2445 function wp_get_password_hint() {
    2446     $hint = __( 'Hint: The password should be at least twelve characters long. To make it stronger, use upper and lower case letters, numbers, and symbols like ! " ? $ % ^ &amp; ).' );
    2447 
    2448     /**
    2449      * Filter the text describing the site's password complexity policy.
    2450      *
    2451      * @since 4.1.0
    2452      *
    2453      * @param string $hint The password hint text.
    2454      */
    2455     return apply_filters( 'password_hint', $hint );
    2456 }
    2457 
    2458 /**
    2459  * Retrieves a user row based on password reset key and login
    2460  *
    2461  * A key is considered 'expired' if it exactly matches the value of the
    2462  * user_activation_key field, rather than being matched after going through the
    2463  * hashing process. This field is now hashed; old values are no longer accepted
    2464  * but have a different WP_Error code so good user feedback can be provided.
    2465  *
    2466  * @since 3.1.0
    2467  *
    2468  * @global wpdb         $wpdb      WordPress database object for queries.
    2469  * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
    2470  *
    2471  * @param string $key       Hash to validate sending user's password.
    2472  * @param string $login     The user login.
    2473  * @return WP_User|WP_Error WP_User object on success, WP_Error object for invalid or expired keys.
    2474  */
    2475 function check_password_reset_key($key, $login) {
    2476     global $wpdb, $wp_hasher;
    2477 
    2478     $key = preg_replace('/[^a-z0-9]/i', '', $key);
    2479 
    2480     if ( empty( $key ) || !is_string( $key ) )
    2481         return new WP_Error('invalid_key', __('Invalid key'));
    2482 
    2483     if ( empty($login) || !is_string($login) )
    2484         return new WP_Error('invalid_key', __('Invalid key'));
    2485 
    2486     $row = $wpdb->get_row( $wpdb->prepare( "SELECT ID, user_activation_key FROM $wpdb->users WHERE user_login = %s", $login ) );
    2487     if ( ! $row )
    2488         return new WP_Error('invalid_key', __('Invalid key'));
    2489 
    2490     if ( empty( $wp_hasher ) ) {
    2491         require_once ABSPATH . WPINC . '/class-phpass.php';
    2492         $wp_hasher = new PasswordHash( 8, true );
    2493     }
    2494 
    2495     /**
    2496      * Filter the expiration time of password reset keys.
    2497      *
    2498      * @since 4.3.0
    2499      *
    2500      * @param int $expiration The expiration time in seconds.
    2501      */
    2502     $expiration_duration = apply_filters( 'password_reset_expiration', DAY_IN_SECONDS );
    2503 
    2504     if ( false !== strpos( $row->user_activation_key, ':' ) ) {
    2505         list( $pass_request_time, $pass_key ) = explode( ':', $row->user_activation_key, 2 );
    2506         $expiration_time = $pass_request_time + $expiration_duration;
    2507     } else {
    2508         $pass_key = $row->user_activation_key;
    2509         $expiration_time = false;
    2510     }
    2511 
    2512     $hash_is_correct = $wp_hasher->CheckPassword( $key, $pass_key );
    2513 
    2514     if ( $hash_is_correct && $expiration_time && time() < $expiration_time ) {
    2515         return get_userdata( $row->ID );
    2516     } elseif ( $hash_is_correct && $expiration_time ) {
    2517         // Key has an expiration time that's passed
    2518         return new WP_Error( 'expired_key', __( 'Invalid key' ) );
    2519     }
    2520 
    2521     if ( hash_equals( $row->user_activation_key, $key ) || ( $hash_is_correct && ! $expiration_time ) ) {
    2522         $return = new WP_Error( 'expired_key', __( 'Invalid key' ) );
    2523         $user_id = $row->ID;
    2524 
    2525         /**
    2526          * Filter the return value of check_password_reset_key() when an
    2527          * old-style key is used.
    2528          *
    2529          * @since 3.7.0 Previously plain-text keys were stored in the database.
    2530          * @since 4.3.0 Previously key hashes were stored without an expiration time.
    2531          *
    2532          * @param WP_Error $return  A WP_Error object denoting an expired key.
    2533          *                          Return a WP_User object to validate the key.
    2534          * @param int      $user_id The matched user ID.
    2535          */
    2536         return apply_filters( 'password_reset_key_expired', $return, $user_id );
    2537     }
    2538 
    2539     return new WP_Error( 'invalid_key', __( 'Invalid key' ) );
    2540 }
    2541 
    2542 /**
    2543  * Handles resetting the user's password.
    2544  *
    2545  * @since 2.5.0
    2546  *
    2547  * @param object $user     The user
    2548  * @param string $new_pass New password for the user in plaintext
    2549  */
    2550 function reset_password( $user, $new_pass ) {
    2551     /**
    2552      * Fires before the user's password is reset.
    2553      *
    2554      * @since 1.5.0
    2555      *
    2556      * @param object $user     The user.
    2557      * @param string $new_pass New user password.
    2558      */
    2559     do_action( 'password_reset', $user, $new_pass );
    2560 
    2561     wp_set_password( $new_pass, $user->ID );
    2562     update_user_option( $user->ID, 'default_password_nag', false, true );
    2563 
    2564     wp_password_change_notification( $user );
    2565 }
    2566 
    2567 /**
    2568  * Handles registering a new user.
    2569  *
    2570  * @since 2.5.0
    2571  *
    2572  * @param string $user_login User's username for logging in
    2573  * @param string $user_email User's email address to send password and add
    2574  * @return int|WP_Error Either user's ID or error on failure.
    2575  */
    2576 function register_new_user( $user_login, $user_email ) {
    2577     $errors = new WP_Error();
    2578 
    2579     $sanitized_user_login = sanitize_user( $user_login );
    2580     /**
    2581      * Filter the email address of a user being registered.
    2582      *
    2583      * @since 2.1.0
    2584      *
    2585      * @param string $user_email The email address of the new user.
    2586      */
    2587     $user_email = apply_filters( 'user_registration_email', $user_email );
    2588 
    2589     // Check the username
    2590     if ( $sanitized_user_login == '' ) {
    2591         $errors->add( 'empty_username', __( '<strong>ERROR</strong>: Please enter a username.' ) );
    2592     } elseif ( ! validate_username( $user_login ) ) {
    2593         $errors->add( 'invalid_username', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ) );
    2594         $sanitized_user_login = '';
    2595     } elseif ( username_exists( $sanitized_user_login ) ) {
    2596         $errors->add( 'username_exists', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ) );
    2597     }
    2598 
    2599     // Check the e-mail address
    2600     if ( $user_email == '' ) {
    2601         $errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please type your e-mail address.' ) );
    2602     } elseif ( ! is_email( $user_email ) ) {
    2603         $errors->add( 'invalid_email', __( '<strong>ERROR</strong>: The email address isn&#8217;t correct.' ) );
    2604         $user_email = '';
    2605     } elseif ( email_exists( $user_email ) ) {
    2606         $errors->add( 'email_exists', __( '<strong>ERROR</strong>: This email is already registered, please choose another one.' ) );
    2607     }
    2608 
    2609     /**
    2610      * Fires when submitting registration form data, before the user is created.
    2611      *
    2612      * @since 2.1.0
    2613      *
    2614      * @param string   $sanitized_user_login The submitted username after being sanitized.
    2615      * @param string   $user_email           The submitted email.
    2616      * @param WP_Error $errors               Contains any errors with submitted username and email,
    2617      *                                       e.g., an empty field, an invalid username or email,
    2618      *                                       or an existing username or email.
    2619      */
    2620     do_action( 'register_post', $sanitized_user_login, $user_email, $errors );
    2621 
    2622     /**
    2623      * Filter the errors encountered when a new user is being registered.
    2624      *
    2625      * The filtered WP_Error object may, for example, contain errors for an invalid
    2626      * or existing username or email address. A WP_Error object should always returned,
    2627      * but may or may not contain errors.
    2628      *
    2629      * If any errors are present in $errors, this will abort the user's registration.
    2630      *
    2631      * @since 2.1.0
    2632      *
    2633      * @param WP_Error $errors               A WP_Error object containing any errors encountered
    2634      *                                       during registration.
    2635      * @param string   $sanitized_user_login User's username after it has been sanitized.
    2636      * @param string   $user_email           User's email.
    2637      */
    2638     $errors = apply_filters( 'registration_errors', $errors, $sanitized_user_login, $user_email );
    2639 
    2640     if ( $errors->get_error_code() )
    2641         return $errors;
    2642 
    2643     $user_pass = wp_generate_password( 12, false );
    2644     $user_id = wp_create_user( $sanitized_user_login, $user_pass, $user_email );
    2645     if ( ! $user_id || is_wp_error( $user_id ) ) {
    2646         $errors->add( 'registerfail', sprintf( __( '<strong>ERROR</strong>: Couldn&#8217;t register you&hellip; please contact the <a href="mailto:%s">webmaster</a> !' ), get_option( 'admin_email' ) ) );
    2647         return $errors;
    2648     }
    2649 
    2650     update_user_option( $user_id, 'default_password_nag', true, true ); //Set up the Password change nag.
    2651 
    2652     wp_new_user_notification( $user_id, 'both' );
    2653 
    2654     return $user_id;
    2655 }
    2656 
    2657 /**
    2658  * Retrieve the current session token from the logged_in cookie.
    2659  *
    2660  * @since 4.0.0
    2661  *
    2662  * @return string Token.
    2663  */
    2664 function wp_get_session_token() {
    2665     $cookie = wp_parse_auth_cookie( '', 'logged_in' );
    2666     return ! empty( $cookie['token'] ) ? $cookie['token'] : '';
    2667 }
    2668 
    2669 /**
    2670  * Retrieve a list of sessions for the current user.
    2671  *
    2672  * @since 4.0.0
    2673  * @return array Array of sessions.
    2674  */
    2675 function wp_get_all_sessions() {
    2676     $manager = WP_Session_Tokens::get_instance( get_current_user_id() );
    2677     return $manager->get_all();
    2678 }
    2679 
    2680 /**
    2681  * Remove the current session token from the database.
    2682  *
    2683  * @since 4.0.0
    2684  */
    2685 function wp_destroy_current_session() {
    2686     $token = wp_get_session_token();
    2687     if ( $token ) {
    2688         $manager = WP_Session_Tokens::get_instance( get_current_user_id() );
    2689         $manager->destroy( $token );
    2690     }
    2691 }
    2692 
    2693 /**
    2694  * Remove all but the current session token for the current user for the database.
    2695  *
    2696  * @since 4.0.0
    2697  */
    2698 function wp_destroy_other_sessions() {
    2699     $token = wp_get_session_token();
    2700     if ( $token ) {
    2701         $manager = WP_Session_Tokens::get_instance( get_current_user_id() );
    2702         $manager->destroy_others( $token );
    2703     }
    2704 }
    2705 
    2706 /**
    2707  * Remove all session tokens for the current user from the database.
    2708  *
    2709  * @since 4.0.0
    2710  */
    2711 function wp_destroy_all_sessions() {
    2712     $manager = WP_Session_Tokens::get_instance( get_current_user_id() );
    2713     $manager->destroy_all();
    2714 }
  • trunk/src/wp-includes/user-functions.php

    r33746 r33749  
    447447        $option_name = $wpdb->get_blog_prefix() . $option_name;
    448448    return delete_user_meta( $user_id, $option_name );
    449 }
    450 
    451 /**
    452  * WordPress User Query class.
    453  *
    454  * @since 3.1.0
    455  *
    456  * @see WP_User_Query::prepare_query() for information on accepted arguments.
    457  */
    458 class WP_User_Query {
    459 
    460     /**
    461      * Query vars, after parsing
    462      *
    463      * @since 3.5.0
    464      * @access public
    465      * @var array
    466      */
    467     public $query_vars = array();
    468 
    469     /**
    470      * List of found user ids
    471      *
    472      * @since 3.1.0
    473      * @access private
    474      * @var array
    475      */
    476     private $results;
    477 
    478     /**
    479      * Total number of found users for the current query
    480      *
    481      * @since 3.1.0
    482      * @access private
    483      * @var int
    484      */
    485     private $total_users = 0;
    486 
    487     /**
    488      * Metadata query container.
    489      *
    490      * @since 4.2.0
    491      * @access public
    492      * @var object WP_Meta_Query
    493      */
    494     public $meta_query = false;
    495 
    496     private $compat_fields = array( 'results', 'total_users' );
    497 
    498     // SQL clauses
    499     public $query_fields;
    500     public $query_from;
    501     public $query_where;
    502     public $query_orderby;
    503     public $query_limit;
    504 
    505     /**
    506      * PHP5 constructor.
    507      *
    508      * @since 3.1.0
    509      *
    510      * @param null|string|array $args Optional. The query variables.
    511      */
    512     public function __construct( $query = null ) {
    513         if ( ! empty( $query ) ) {
    514             $this->prepare_query( $query );
    515             $this->query();
    516         }
    517     }
    518 
    519     /**
    520      * Prepare the query variables.
    521      *
    522      * @since 3.1.0
    523      * @since 4.2.0 Added 'meta_value_num' support for `$orderby` parameter. Added multi-dimensional array syntax
    524      *              for `$orderby` parameter.
    525      * @since 4.3.0 Added 'has_published_posts' parameter.
    526      * @access public
    527      *
    528      * @global wpdb $wpdb
    529      * @global int  $blog_id
    530      *
    531      * @param string|array $query {
    532      *     Optional. Array or string of Query parameters.
    533      *
    534      *     @type int          $blog_id             The site ID. Default is the global blog id.
    535      *     @type string       $role                Role name. Default empty.
    536      *     @type string       $meta_key            User meta key. Default empty.
    537      *     @type string       $meta_value          User meta value. Default empty.
    538      *     @type string       $meta_compare        Comparison operator to test the `$meta_value`. Accepts '=', '!=',
    539      *                                             '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN',
    540      *                                             'BETWEEN', 'NOT BETWEEN', 'EXISTS', 'NOT EXISTS', 'REGEXP',
    541      *                                             'NOT REGEXP', or 'RLIKE'. Default '='.
    542      *     @type array        $include             An array of user IDs to include. Default empty array.
    543      *     @type array        $exclude             An array of user IDs to exclude. Default empty array.
    544      *     @type string       $search              Search keyword. Searches for possible string matches on columns.
    545      *                                             When `$search_columns` is left empty, it tries to determine which
    546      *                                             column to search in based on search string. Default empty.
    547      *     @type array        $search_columns      Array of column names to be searched. Accepts 'ID', 'login',
    548      *                                             'nicename', 'email', 'url'. Default empty array.
    549      *     @type string|array $orderby             Field(s) to sort the retrieved users by. May be a single value,
    550      *                                             an array of values, or a multi-dimensional array with fields as
    551      *                                             keys and orders ('ASC' or 'DESC') as values. Accepted values are
    552      *                                             'ID', 'display_name' (or 'name'), 'user_login' (or 'login'),
    553      *                                             'user_nicename' (or 'nicename'), 'user_email' (or 'email'),
    554      *                                             'user_url' (or 'url'), 'user_registered' (or 'registered'),
    555      *                                             'post_count', 'meta_value', 'meta_value_num', the value of
    556      *                                             `$meta_key`, or an array key of `$meta_query`. To use
    557      *                                             'meta_value' or 'meta_value_num', `$meta_key` must be also be
    558      *                                             defined. Default 'user_login'.
    559      *     @type string       $order               Designates ascending or descending order of users. Order values
    560      *                                             passed as part of an `$orderby` array take precedence over this
    561      *                                             parameter. Accepts 'ASC', 'DESC'. Default 'ASC'.
    562      *     @type int          $offset              Number of users to offset in retrieved results. Can be used in
    563      *                                             conjunction with pagination. Default 0.
    564      *     @type int          $number              Number of users to limit the query for. Can be used in
    565      *                                             conjunction with pagination. Value -1 (all) is not supported.
    566      *                                             Default empty (all users).
    567      *     @type bool         $count_total         Whether to count the total number of users found. If pagination
    568      *                                             is not needed, setting this to false can improve performance.
    569      *                                             Default true.
    570      *     @type string|array $fields              Which fields to return. Single or all fields (string), or array
    571      *                                             of fields. Accepts 'ID', 'display_name', 'login', 'nicename',
    572      *                                             'email', 'url', 'registered'. Use 'all' for all fields and
    573      *                                             'all_with_meta' to include meta fields. Default 'all'.
    574      *     @type string       $who                 Type of users to query. Accepts 'authors'.
    575      *                                             Default empty (all users).
    576      *     @type bool|array   $has_published_posts Pass an array of post types to filter results to users who have
    577      *                                             published posts in those post types. `true` is an alias for all
    578      *                                             public post types.
    579      * }
    580      */
    581     public function prepare_query( $query = array() ) {
    582         global $wpdb;
    583 
    584         if ( empty( $this->query_vars ) || ! empty( $query ) ) {
    585             $this->query_limit = null;
    586             $this->query_vars = wp_parse_args( $query, array(
    587                 'blog_id' => $GLOBALS['blog_id'],
    588                 'role' => '',
    589                 'meta_key' => '',
    590                 'meta_value' => '',
    591                 'meta_compare' => '',
    592                 'include' => array(),
    593                 'exclude' => array(),
    594                 'search' => '',
    595                 'search_columns' => array(),
    596                 'orderby' => 'login',
    597                 'order' => 'ASC',
    598                 'offset' => '',
    599                 'number' => '',
    600                 'count_total' => true,
    601                 'fields' => 'all',
    602                 'who' => '',
    603                 'has_published_posts' => null,
    604             ) );
    605         }
    606 
    607         /**
    608          * Fires before the WP_User_Query has been parsed.
    609          *
    610          * The passed WP_User_Query object contains the query variables, not
    611          * yet passed into SQL.
    612          *
    613          * @since 4.0.0
    614          *
    615          * @param WP_User_Query $this The current WP_User_Query instance,
    616          *                            passed by reference.
    617          */
    618         do_action( 'pre_get_users', $this );
    619 
    620         $qv =& $this->query_vars;
    621 
    622         if ( is_array( $qv['fields'] ) ) {
    623             $qv['fields'] = array_unique( $qv['fields'] );
    624 
    625             $this->query_fields = array();
    626             foreach ( $qv['fields'] as $field ) {
    627                 $field = 'ID' === $field ? 'ID' : sanitize_key( $field );
    628                 $this->query_fields[] = "$wpdb->users.$field";
    629             }
    630             $this->query_fields = implode( ',', $this->query_fields );
    631         } elseif ( 'all' == $qv['fields'] ) {
    632             $this->query_fields = "$wpdb->users.*";
    633         } else {
    634             $this->query_fields = "$wpdb->users.ID";
    635         }
    636 
    637         if ( isset( $qv['count_total'] ) && $qv['count_total'] )
    638             $this->query_fields = 'SQL_CALC_FOUND_ROWS ' . $this->query_fields;
    639 
    640         $this->query_from = "FROM $wpdb->users";
    641         $this->query_where = "WHERE 1=1";
    642 
    643         // Parse and sanitize 'include', for use by 'orderby' as well as 'include' below.
    644         if ( ! empty( $qv['include'] ) ) {
    645             $include = wp_parse_id_list( $qv['include'] );
    646         } else {
    647             $include = false;
    648         }
    649 
    650         $blog_id = 0;
    651         if ( isset( $qv['blog_id'] ) ) {
    652             $blog_id = absint( $qv['blog_id'] );
    653         }
    654 
    655         if ( isset( $qv['who'] ) && 'authors' == $qv['who'] && $blog_id ) {
    656             $qv['meta_key'] = $wpdb->get_blog_prefix( $blog_id ) . 'user_level';
    657             $qv['meta_value'] = 0;
    658             $qv['meta_compare'] = '!=';
    659             $qv['blog_id'] = $blog_id = 0; // Prevent extra meta query
    660         }
    661 
    662         if ( $qv['has_published_posts'] && $blog_id ) {
    663             if ( true === $qv['has_published_posts'] ) {
    664                 $post_types = get_post_types( array( 'public' => true ) );
    665             } else {
    666                 $post_types = (array) $qv['has_published_posts'];
    667             }
    668 
    669             foreach ( $post_types as &$post_type ) {
    670                 $post_type = $wpdb->prepare( '%s', $post_type );
    671             }
    672 
    673             $posts_table = $wpdb->get_blog_prefix( $blog_id ) . 'posts';
    674             $this->query_where .= " AND $wpdb->users.ID IN ( SELECT DISTINCT $posts_table.post_author FROM $posts_table WHERE $posts_table.post_status = 'publish' AND $posts_table.post_type IN ( " . join( ", ", $post_types ) . " ) )";
    675         }
    676 
    677         // Meta query.
    678         $this->meta_query = new WP_Meta_Query();
    679         $this->meta_query->parse_query_vars( $qv );
    680 
    681         $role = '';
    682         if ( isset( $qv['role'] ) ) {
    683             $role = trim( $qv['role'] );
    684         }
    685 
    686         if ( $blog_id && ( $role || is_multisite() ) ) {
    687             $cap_meta_query = array();
    688             $cap_meta_query['key'] = $wpdb->get_blog_prefix( $blog_id ) . 'capabilities';
    689 
    690             if ( $role ) {
    691                 $cap_meta_query['value'] = '"' . $role . '"';
    692                 $cap_meta_query['compare'] = 'like';
    693             }
    694 
    695             if ( empty( $this->meta_query->queries ) ) {
    696                 $this->meta_query->queries = array( $cap_meta_query );
    697             } elseif ( ! in_array( $cap_meta_query, $this->meta_query->queries, true ) ) {
    698                 // Append the cap query to the original queries and reparse the query.
    699                 $this->meta_query->queries = array(
    700                     'relation' => 'AND',
    701                     array( $this->meta_query->queries, $cap_meta_query ),
    702                 );
    703             }
    704 
    705             $this->meta_query->parse_query_vars( $this->meta_query->queries );
    706         }
    707 
    708         if ( ! empty( $this->meta_query->queries ) ) {
    709             $clauses = $this->meta_query->get_sql( 'user', $wpdb->users, 'ID', $this );
    710             $this->query_from .= $clauses['join'];
    711             $this->query_where .= $clauses['where'];
    712 
    713             if ( $this->meta_query->has_or_relation() ) {
    714                 $this->query_fields = 'DISTINCT ' . $this->query_fields;
    715             }
    716         }
    717 
    718         // sorting
    719         $qv['order'] = isset( $qv['order'] ) ? strtoupper( $qv['order'] ) : '';
    720         $order = $this->parse_order( $qv['order'] );
    721 
    722         if ( empty( $qv['orderby'] ) ) {
    723             // Default order is by 'user_login'.
    724             $ordersby = array( 'user_login' => $order );
    725         } elseif ( is_array( $qv['orderby'] ) ) {
    726             $ordersby = $qv['orderby'];
    727         } else {
    728             // 'orderby' values may be a comma- or space-separated list.
    729             $ordersby = preg_split( '/[,\s]+/', $qv['orderby'] );
    730         }
    731 
    732         $orderby_array = array();
    733         foreach ( $ordersby as $_key => $_value ) {
    734             if ( ! $_value ) {
    735                 continue;
    736             }
    737 
    738             if ( is_int( $_key ) ) {
    739                 // Integer key means this is a flat array of 'orderby' fields.
    740                 $_orderby = $_value;
    741                 $_order = $order;
    742             } else {
    743                 // Non-integer key means this the key is the field and the value is ASC/DESC.
    744                 $_orderby = $_key;
    745                 $_order = $_value;
    746             }
    747 
    748             $parsed = $this->parse_orderby( $_orderby );
    749 
    750             if ( ! $parsed ) {
    751                 continue;
    752             }
    753 
    754             $orderby_array[] = $parsed . ' ' . $this->parse_order( $_order );
    755         }
    756 
    757         // If no valid clauses were found, order by user_login.
    758         if ( empty( $orderby_array ) ) {
    759             $orderby_array[] = "user_login $order";
    760         }
    761 
    762         $this->query_orderby = 'ORDER BY ' . implode( ', ', $orderby_array );
    763 
    764         // limit
    765         if ( isset( $qv['number'] ) && $qv['number'] ) {
    766             if ( $qv['offset'] )
    767                 $this->query_limit = $wpdb->prepare("LIMIT %d, %d", $qv['offset'], $qv['number']);
    768             else
    769                 $this->query_limit = $wpdb->prepare("LIMIT %d", $qv['number']);
    770         }
    771 
    772         $search = '';
    773         if ( isset( $qv['search'] ) )
    774             $search = trim( $qv['search'] );
    775 
    776         if ( $search ) {
    777             $leading_wild = ( ltrim($search, '*') != $search );
    778             $trailing_wild = ( rtrim($search, '*') != $search );
    779             if ( $leading_wild && $trailing_wild )
    780                 $wild = 'both';
    781             elseif ( $leading_wild )
    782                 $wild = 'leading';
    783             elseif ( $trailing_wild )
    784                 $wild = 'trailing';
    785             else
    786                 $wild = false;
    787             if ( $wild )
    788                 $search = trim($search, '*');
    789 
    790             $search_columns = array();
    791             if ( $qv['search_columns'] )
    792                 $search_columns = array_intersect( $qv['search_columns'], array( 'ID', 'user_login', 'user_email', 'user_url', 'user_nicename' ) );
    793             if ( ! $search_columns ) {
    794                 if ( false !== strpos( $search, '@') )
    795                     $search_columns = array('user_email');
    796                 elseif ( is_numeric($search) )
    797                     $search_columns = array('user_login', 'ID');
    798                 elseif ( preg_match('|^https?://|', $search) && ! ( is_multisite() && wp_is_large_network( 'users' ) ) )
    799                     $search_columns = array('user_url');
    800                 else
    801                     $search_columns = array('user_login', 'user_url', 'user_email', 'user_nicename', 'display_name');
    802             }
    803 
    804             /**
    805              * Filter the columns to search in a WP_User_Query search.
    806              *
    807              * The default columns depend on the search term, and include 'user_email',
    808              * 'user_login', 'ID', 'user_url', 'display_name', and 'user_nicename'.
    809              *
    810              * @since 3.6.0
    811              *
    812              * @param array         $search_columns Array of column names to be searched.
    813              * @param string        $search         Text being searched.
    814              * @param WP_User_Query $this           The current WP_User_Query instance.
    815              */
    816             $search_columns = apply_filters( 'user_search_columns', $search_columns, $search, $this );
    817 
    818             $this->query_where .= $this->get_search_sql( $search, $search_columns, $wild );
    819         }
    820 
    821         if ( ! empty( $include ) ) {
    822             // Sanitized earlier.
    823             $ids = implode( ',', $include );
    824             $this->query_where .= " AND $wpdb->users.ID IN ($ids)";
    825         } elseif ( ! empty( $qv['exclude'] ) ) {
    826             $ids = implode( ',', wp_parse_id_list( $qv['exclude'] ) );
    827             $this->query_where .= " AND $wpdb->users.ID NOT IN ($ids)";
    828         }
    829 
    830         // Date queries are allowed for the user_registered field.
    831         if ( ! empty( $qv['date_query'] ) && is_array( $qv['date_query'] ) ) {
    832             $date_query = new WP_Date_Query( $qv['date_query'], 'user_registered' );
    833             $this->query_where .= $date_query->get_sql();
    834         }
    835 
    836         /**
    837          * Fires after the WP_User_Query has been parsed, and before
    838          * the query is executed.
    839          *
    840          * The passed WP_User_Query object contains SQL parts formed
    841          * from parsing the given query.
    842          *
    843          * @since 3.1.0
    844          *
    845          * @param WP_User_Query $this The current WP_User_Query instance,
    846          *                            passed by reference.
    847          */
    848         do_action_ref_array( 'pre_user_query', array( &$this ) );
    849     }
    850 
    851     /**
    852      * Execute the query, with the current variables.
    853      *
    854      * @since 3.1.0
    855      *
    856      * @global wpdb $wpdb WordPress database object for queries.
    857      */
    858     public function query() {
    859         global $wpdb;
    860 
    861         $qv =& $this->query_vars;
    862 
    863         $query = "SELECT $this->query_fields $this->query_from $this->query_where $this->query_orderby $this->query_limit";
    864 
    865         if ( is_array( $qv['fields'] ) || 'all' == $qv['fields'] ) {
    866             $this->results = $wpdb->get_results( $query );
    867         } else {
    868             $this->results = $wpdb->get_col( $query );
    869         }
    870 
    871         /**
    872          * Filter SELECT FOUND_ROWS() query for the current WP_User_Query instance.
    873          *
    874          * @since 3.2.0
    875          *
    876          * @global wpdb $wpdb WordPress database abstraction object.
    877          *
    878          * @param string $sql The SELECT FOUND_ROWS() query for the current WP_User_Query.
    879          */
    880         if ( isset( $qv['count_total'] ) && $qv['count_total'] )
    881             $this->total_users = $wpdb->get_var( apply_filters( 'found_users_query', 'SELECT FOUND_ROWS()' ) );
    882 
    883         if ( !$this->results )
    884             return;
    885 
    886         if ( 'all_with_meta' == $qv['fields'] ) {
    887             cache_users( $this->results );
    888 
    889             $r = array();
    890             foreach ( $this->results as $userid )
    891                 $r[ $userid ] = new WP_User( $userid, '', $qv['blog_id'] );
    892 
    893             $this->results = $r;
    894         } elseif ( 'all' == $qv['fields'] ) {
    895             foreach ( $this->results as $key => $user ) {
    896                 $this->results[ $key ] = new WP_User( $user, '', $qv['blog_id'] );
    897             }
    898         }
    899     }
    900 
    901     /**
    902      * Retrieve query variable.
    903      *
    904      * @since 3.5.0
    905      * @access public
    906      *
    907      * @param string $query_var Query variable key.
    908      * @return mixed
    909      */
    910     public function get( $query_var ) {
    911         if ( isset( $this->query_vars[$query_var] ) )
    912             return $this->query_vars[$query_var];
    913 
    914         return null;
    915     }
    916 
    917     /**
    918      * Set query variable.
    919      *
    920      * @since 3.5.0
    921      * @access public
    922      *
    923      * @param string $query_var Query variable key.
    924      * @param mixed $value Query variable value.
    925      */
    926     public function set( $query_var, $value ) {
    927         $this->query_vars[$query_var] = $value;
    928     }
    929 
    930     /**
    931      * Used internally to generate an SQL string for searching across multiple columns
    932      *
    933      * @access protected
    934      * @since 3.1.0
    935      *
    936      * @global wpdb $wpdb
    937      *
    938      * @param string $string
    939      * @param array  $cols
    940      * @param bool   $wild   Whether to allow wildcard searches. Default is false for Network Admin, true for single site.
    941      *                       Single site allows leading and trailing wildcards, Network Admin only trailing.
    942      * @return string
    943      */
    944     protected function get_search_sql( $string, $cols, $wild = false ) {
    945         global $wpdb;
    946 
    947         $searches = array();
    948         $leading_wild = ( 'leading' == $wild || 'both' == $wild ) ? '%' : '';
    949         $trailing_wild = ( 'trailing' == $wild || 'both' == $wild ) ? '%' : '';
    950         $like = $leading_wild . $wpdb->esc_like( $string ) . $trailing_wild;
    951 
    952         foreach ( $cols as $col ) {
    953             if ( 'ID' == $col ) {
    954                 $searches[] = $wpdb->prepare( "$col = %s", $string );
    955             } else {
    956                 $searches[] = $wpdb->prepare( "$col LIKE %s", $like );
    957             }
    958         }
    959 
    960         return ' AND (' . implode(' OR ', $searches) . ')';
    961     }
    962 
    963     /**
    964      * Return the list of users.
    965      *
    966      * @since 3.1.0
    967      * @access public
    968      *
    969      * @return array Array of results.
    970      */
    971     public function get_results() {
    972         return $this->results;
    973     }
    974 
    975     /**
    976      * Return the total number of users for the current query.
    977      *
    978      * @since 3.1.0
    979      * @access public
    980      *
    981      * @return int Number of total users.
    982      */
    983     public function get_total() {
    984         return $this->total_users;
    985     }
    986 
    987     /**
    988      * Parse and sanitize 'orderby' keys passed to the user query.
    989      *
    990      * @since 4.2.0
    991      * @access protected
    992      *
    993      * @global wpdb $wpdb WordPress database abstraction object.
    994      *
    995      * @param string $orderby Alias for the field to order by.
    996      * @return string Value to used in the ORDER clause, if `$orderby` is valid.
    997      */
    998     protected function parse_orderby( $orderby ) {
    999         global $wpdb;
    1000 
    1001         $meta_query_clauses = $this->meta_query->get_clauses();
    1002 
    1003         $_orderby = '';
    1004         if ( in_array( $orderby, array( 'login', 'nicename', 'email', 'url', 'registered' ) ) ) {
    1005             $_orderby = 'user_' . $orderby;
    1006         } elseif ( in_array( $orderby, array( 'user_login', 'user_nicename', 'user_email', 'user_url', 'user_registered' ) ) ) {
    1007             $_orderby = $orderby;
    1008         } elseif ( 'name' == $orderby || 'display_name' == $orderby ) {
    1009             $_orderby = 'display_name';
    1010         } elseif ( 'post_count' == $orderby ) {
    1011             // todo: avoid the JOIN
    1012             $where = get_posts_by_author_sql( 'post' );
    1013             $this->query_from .= " LEFT OUTER JOIN (
    1014                 SELECT post_author, COUNT(*) as post_count
    1015                 FROM $wpdb->posts
    1016                 $where
    1017                 GROUP BY post_author
    1018             ) p ON ({$wpdb->users}.ID = p.post_author)
    1019             ";
    1020             $_orderby = 'post_count';
    1021         } elseif ( 'ID' == $orderby || 'id' == $orderby ) {
    1022             $_orderby = 'ID';
    1023         } elseif ( 'meta_value' == $orderby || $this->get( 'meta_key' ) == $orderby ) {
    1024             $_orderby = "$wpdb->usermeta.meta_value";
    1025         } elseif ( 'meta_value_num' == $orderby ) {
    1026             $_orderby = "$wpdb->usermeta.meta_value+0";
    1027         } elseif ( 'include' === $orderby && ! empty( $this->query_vars['include'] ) ) {
    1028             $include = wp_parse_id_list( $this->query_vars['include'] );
    1029             $include_sql = implode( ',', $include );
    1030             $_orderby = "FIELD( $wpdb->users.ID, $include_sql )";
    1031         } elseif ( isset( $meta_query_clauses[ $orderby ] ) ) {
    1032             $meta_clause = $meta_query_clauses[ $orderby ];
    1033             $_orderby = sprintf( "CAST(%s.meta_value AS %s)", esc_sql( $meta_clause['alias'] ), esc_sql( $meta_clause['cast'] ) );
    1034         }
    1035 
    1036         return $_orderby;
    1037     }
    1038 
    1039     /**
    1040      * Parse an 'order' query variable and cast it to ASC or DESC as necessary.
    1041      *
    1042      * @since 4.2.0
    1043      * @access protected
    1044      *
    1045      * @param string $order The 'order' query variable.
    1046      * @return string The sanitized 'order' query variable.
    1047      */
    1048     protected function parse_order( $order ) {
    1049         if ( ! is_string( $order ) || empty( $order ) ) {
    1050             return 'DESC';
    1051         }
    1052 
    1053         if ( 'ASC' === strtoupper( $order ) ) {
    1054             return 'ASC';
    1055         } else {
    1056             return 'DESC';
    1057         }
    1058     }
    1059 
    1060     /**
    1061      * Make private properties readable for backwards compatibility.
    1062      *
    1063      * @since 4.0.0
    1064      * @access public
    1065      *
    1066      * @param string $name Property to get.
    1067      * @return mixed Property.
    1068      */
    1069     public function __get( $name ) {
    1070         if ( in_array( $name, $this->compat_fields ) ) {
    1071             return $this->$name;
    1072         }
    1073     }
    1074 
    1075     /**
    1076      * Make private properties settable for backwards compatibility.
    1077      *
    1078      * @since 4.0.0
    1079      * @access public
    1080      *
    1081      * @param string $name  Property to check if set.
    1082      * @param mixed  $value Property value.
    1083      * @return mixed Newly-set property.
    1084      */
    1085     public function __set( $name, $value ) {
    1086         if ( in_array( $name, $this->compat_fields ) ) {
    1087             return $this->$name = $value;
    1088         }
    1089     }
    1090 
    1091     /**
    1092      * Make private properties checkable for backwards compatibility.
    1093      *
    1094      * @since 4.0.0
    1095      * @access public
    1096      *
    1097      * @param string $name Property to check if set.
    1098      * @return bool Whether the property is set.
    1099      */
    1100     public function __isset( $name ) {
    1101         if ( in_array( $name, $this->compat_fields ) ) {
    1102             return isset( $this->$name );
    1103         }
    1104     }
    1105 
    1106     /**
    1107      * Make private properties un-settable for backwards compatibility.
    1108      *
    1109      * @since 4.0.0
    1110      * @access public
    1111      *
    1112      * @param string $name Property to unset.
    1113      */
    1114     public function __unset( $name ) {
    1115         if ( in_array( $name, $this->compat_fields ) ) {
    1116             unset( $this->$name );
    1117         }
    1118     }
    1119 
    1120     /**
    1121      * Make private/protected methods readable for backwards compatibility.
    1122      *
    1123      * @since 4.0.0
    1124      * @access public
    1125      *
    1126      * @param callable $name      Method to call.
    1127      * @param array    $arguments Arguments to pass when calling.
    1128      * @return mixed Return value of the callback, false otherwise.
    1129      */
    1130     public function __call( $name, $arguments ) {
    1131         if ( 'get_search_sql' === $name ) {
    1132             return call_user_func_array( array( $this, $name ), $arguments );
    1133         }
    1134         return false;
    1135     }
    1136449}
    1137450
  • trunk/src/wp-includes/user.php

    r33725 r33749  
    77 */
    88
    9 /**
    10  * Authenticate user with remember capability.
    11  *
    12  * The credentials is an array that has 'user_login', 'user_password', and
    13  * 'remember' indices. If the credentials is not given, then the log in form
    14  * will be assumed and used if set.
    15  *
    16  * The various authentication cookies will be set by this function and will be
    17  * set for a longer period depending on if the 'remember' credential is set to
    18  * true.
    19  *
    20  * @since 2.5.0
    21  *
    22  * @global string $auth_secure_cookie
    23  *
    24  * @param array       $credentials   Optional. User info in order to sign on.
    25  * @param string|bool $secure_cookie Optional. Whether to use secure cookie.
    26  * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
    27  */
    28 function wp_signon( $credentials = array(), $secure_cookie = '' ) {
    29     if ( empty($credentials) ) {
    30         if ( ! empty($_POST['log']) )
    31             $credentials['user_login'] = $_POST['log'];
    32         if ( ! empty($_POST['pwd']) )
    33             $credentials['user_password'] = $_POST['pwd'];
    34         if ( ! empty($_POST['rememberme']) )
    35             $credentials['remember'] = $_POST['rememberme'];
    36     }
    37 
    38     if ( !empty($credentials['remember']) )
    39         $credentials['remember'] = true;
    40     else
    41         $credentials['remember'] = false;
    42 
    43     /**
    44      * Fires before the user is authenticated.
    45      *
    46      * The variables passed to the callbacks are passed by reference,
    47      * and can be modified by callback functions.
    48      *
    49      * @since 1.5.1
    50      *
    51      * @todo Decide whether to deprecate the wp_authenticate action.
    52      *
    53      * @param string $user_login    Username, passed by reference.
    54      * @param string $user_password User password, passed by reference.
    55      */
    56     do_action_ref_array( 'wp_authenticate', array( &$credentials['user_login'], &$credentials['user_password'] ) );
    57 
    58     if ( '' === $secure_cookie )
    59         $secure_cookie = is_ssl();
    60 
    61     /**
    62      * Filter whether to use a secure sign-on cookie.
    63      *
    64      * @since 3.1.0
    65      *
    66      * @param bool  $secure_cookie Whether to use a secure sign-on cookie.
    67      * @param array $credentials {
    68      *     Array of entered sign-on data.
    69      *
    70      *     @type string $user_login    Username.
    71      *     @type string $user_password Password entered.
    72      *     @type bool   $remember      Whether to 'remember' the user. Increases the time
    73      *                                 that the cookie will be kept. Default false.
    74      * }
    75      */
    76     $secure_cookie = apply_filters( 'secure_signon_cookie', $secure_cookie, $credentials );
    77 
    78     global $auth_secure_cookie; // XXX ugly hack to pass this to wp_authenticate_cookie
    79     $auth_secure_cookie = $secure_cookie;
    80 
    81     add_filter('authenticate', 'wp_authenticate_cookie', 30, 3);
    82 
    83     $user = wp_authenticate($credentials['user_login'], $credentials['user_password']);
    84 
    85     if ( is_wp_error($user) ) {
    86         if ( $user->get_error_codes() == array('empty_username', 'empty_password') ) {
    87             $user = new WP_Error('', '');
    88         }
    89 
    90         return $user;
    91     }
    92 
    93     wp_set_auth_cookie($user->ID, $credentials['remember'], $secure_cookie);
    94     /**
    95      * Fires after the user has successfully logged in.
    96      *
    97      * @since 1.5.0
    98      *
    99      * @param string  $user_login Username.
    100      * @param WP_User $user       WP_User object of the logged-in user.
    101      */
    102     do_action( 'wp_login', $user->user_login, $user );
    103     return $user;
    104 }
    105 
    106 /**
    107  * Authenticate the user using the username and password.
    108  *
    109  * @since 2.8.0
    110  *
    111  * @param WP_User|WP_Error|null $user     WP_User or WP_Error object from a previous callback. Default null.
    112  * @param string                $username Username for authentication.
    113  * @param string                $password Password for authentication.
    114  * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
    115  */
    116 function wp_authenticate_username_password($user, $username, $password) {
    117     if ( $user instanceof WP_User ) {
    118         return $user;
    119     }
    120 
    121     if ( empty($username) || empty($password) ) {
    122         if ( is_wp_error( $user ) )
    123             return $user;
    124 
    125         $error = new WP_Error();
    126 
    127         if ( empty($username) )
    128             $error->add('empty_username', __('<strong>ERROR</strong>: The username field is empty.'));
    129 
    130         if ( empty($password) )
    131             $error->add('empty_password', __('<strong>ERROR</strong>: The password field is empty.'));
    132 
    133         return $error;
    134     }
    135 
    136     $user = get_user_by('login', $username);
    137 
    138     if ( !$user )
    139         return new WP_Error( 'invalid_username', sprintf( __( '<strong>ERROR</strong>: Invalid username. <a href="%s">Lost your password?</a>' ), wp_lostpassword_url() ) );
    140 
    141     /**
    142      * Filter whether the given user can be authenticated with the provided $password.
    143      *
    144      * @since 2.5.0
    145      *
    146      * @param WP_User|WP_Error $user     WP_User or WP_Error object if a previous
    147      *                                   callback failed authentication.
    148      * @param string           $password Password to check against the user.
    149      */
    150     $user = apply_filters( 'wp_authenticate_user', $user, $password );
    151     if ( is_wp_error($user) )
    152         return $user;
    153 
    154     if ( !wp_check_password($password, $user->user_pass, $user->ID) )
    155         return new WP_Error( 'incorrect_password', sprintf( __( '<strong>ERROR</strong>: The password you entered for the username <strong>%1$s</strong> is incorrect. <a href="%2$s">Lost your password?</a>' ),
    156         $username, wp_lostpassword_url() ) );
    157 
    158     return $user;
    159 }
    160 
    161 /**
    162  * Authenticate the user using the WordPress auth cookie.
    163  *
    164  * @since 2.8.0
    165  *
    166  * @global string $auth_secure_cookie
    167  *
    168  * @param WP_User|WP_Error|null $user     WP_User or WP_Error object from a previous callback. Default null.
    169  * @param string                $username Username. If not empty, cancels the cookie authentication.
    170  * @param string                $password Password. If not empty, cancels the cookie authentication.
    171  * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
    172  */
    173 function wp_authenticate_cookie($user, $username, $password) {
    174     if ( $user instanceof WP_User ) {
    175         return $user;
    176     }
    177 
    178     if ( empty($username) && empty($password) ) {
    179         $user_id = wp_validate_auth_cookie();
    180         if ( $user_id )
    181             return new WP_User($user_id);
    182 
    183         global $auth_secure_cookie;
    184 
    185         if ( $auth_secure_cookie )
    186             $auth_cookie = SECURE_AUTH_COOKIE;
    187         else
    188             $auth_cookie = AUTH_COOKIE;
    189 
    190         if ( !empty($_COOKIE[$auth_cookie]) )
    191             return new WP_Error('expired_session', __('Please log in again.'));
    192 
    193         // If the cookie is not set, be silent.
    194     }
    195 
    196     return $user;
    197 }
    198 
    199 /**
    200  * For Multisite blogs, check if the authenticated user has been marked as a
    201  * spammer, or if the user's primary blog has been marked as spam.
    202  *
    203  * @since 3.7.0
    204  *
    205  * @param WP_User|WP_Error|null $user WP_User or WP_Error object from a previous callback. Default null.
    206  * @return WP_User|WP_Error WP_User on success, WP_Error if the user is considered a spammer.
    207  */
    208 function wp_authenticate_spam_check( $user ) {
    209     if ( $user instanceof WP_User && is_multisite() ) {
    210         /**
    211          * Filter whether the user has been marked as a spammer.
    212          *
    213          * @since 3.7.0
    214          *
    215          * @param bool    $spammed Whether the user is considered a spammer.
    216          * @param WP_User $user    User to check against.
    217          */
    218         $spammed = apply_filters( 'check_is_user_spammed', is_user_spammy(), $user );
    219 
    220         if ( $spammed )
    221             return new WP_Error( 'spammer_account', __( '<strong>ERROR</strong>: Your account has been marked as a spammer.' ) );
    222     }
    223     return $user;
    224 }
    225 
    226 /**
    227  * Validate the logged-in cookie.
    228  *
    229  * Checks the logged-in cookie if the previous auth cookie could not be
    230  * validated and parsed.
    231  *
    232  * This is a callback for the determine_current_user filter, rather than API.
    233  *
    234  * @since 3.9.0
    235  *
    236  * @param int|bool $user_id The user ID (or false) as received from the
    237  *                       determine_current_user filter.
    238  * @return int|false User ID if validated, false otherwise. If a user ID from
    239  *                   an earlier filter callback is received, that value is returned.
    240  */
    241 function wp_validate_logged_in_cookie( $user_id ) {
    242     if ( $user_id ) {
    243         return $user_id;
    244     }
    245 
    246     if ( is_blog_admin() || is_network_admin() || empty( $_COOKIE[LOGGED_IN_COOKIE] ) ) {
    247         return false;
    248     }
    249 
    250     return wp_validate_auth_cookie( $_COOKIE[LOGGED_IN_COOKIE], 'logged_in' );
    251 }
    252 
    253 /**
    254  * Number of posts user has written.
    255  *
    256  * @since 3.0.0
    257  * @since 4.1.0 Added `$post_type` argument.
    258  * @since 4.3.0 Added `$public_only` argument. Added the ability to pass an array
    259  *              of post types to `$post_type`.
    260  *
    261  * @global wpdb $wpdb WordPress database object for queries.
    262  *
    263  * @param int          $userid      User ID.
    264  * @param array|string $post_type   Optional. Single post type or array of post types to count the number of posts for. Default 'post'.
    265  * @param bool         $public_only Optional. Whether to only return counts for public posts. Default false.
    266  * @return int Number of posts the user has written in this post type.
    267  */
    268 function count_user_posts( $userid, $post_type = 'post', $public_only = false ) {
    269     global $wpdb;
    270 
    271     $where = get_posts_by_author_sql( $post_type, true, $userid, $public_only );
    272 
    273     $count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts $where" );
    274 
    275     /**
    276      * Filter the number of posts a user has written.
    277      *
    278      * @since 2.7.0
    279      * @since 4.1.0 Added `$post_type` argument.
    280      * @since 4.3.1 Added `$public_only` argument.
    281      *
    282      * @param int          $count       The user's post count.
    283      * @param int          $userid      User ID.
    284      * @param string|array $post_type   Single post type or array of post types to count the number of posts for.
    285      * @param bool         $public_only Whether to limit counted posts to public posts.
    286      */
    287     return apply_filters( 'get_usernumposts', $count, $userid, $post_type, $public_only );
    288 }
    289 
    290 /**
    291  * Number of posts written by a list of users.
    292  *
    293  * @since 3.0.0
    294  *
    295  * @global wpdb $wpdb
    296  *
    297  * @param array        $users       Array of user IDs.
    298  * @param string|array $post_type   Optional. Single post type or array of post types to check. Defaults to 'post'.
    299  * @param bool         $public_only Optional. Only return counts for public posts.  Defaults to false.
    300  * @return array Amount of posts each user has written.
    301  */
    302 function count_many_users_posts( $users, $post_type = 'post', $public_only = false ) {
    303     global $wpdb;
    304 
    305     $count = array();
    306     if ( empty( $users ) || ! is_array( $users ) )
    307         return $count;
    308 
    309     $userlist = implode( ',', array_map( 'absint', $users ) );
    310     $where = get_posts_by_author_sql( $post_type, true, null, $public_only );
    311 
    312     $result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author", ARRAY_N );
    313     foreach ( $result as $row ) {
    314         $count[ $row[0] ] = $row[1];
    315     }
    316 
    317     foreach ( $users as $id ) {
    318         if ( ! isset( $count[ $id ] ) )
    319             $count[ $id ] = 0;
    320     }
    321 
    322     return $count;
    323 }
    324 
    325 //
    326 // User option functions
    327 //
    328 
    329 /**
    330  * Get the current user's ID
    331  *
    332  * @since MU
    333  *
    334  * @return int The current user's ID
    335  */
    336 function get_current_user_id() {
    337     if ( ! function_exists( 'wp_get_current_user' ) )
    338         return 0;
    339     $user = wp_get_current_user();
    340     return ( isset( $user->ID ) ? (int) $user->ID : 0 );
    341 }
    342 
    343 /**
    344  * Retrieve user option that can be either per Site or per Network.
    345  *
    346  * If the user ID is not given, then the current user will be used instead. If
    347  * the user ID is given, then the user data will be retrieved. The filter for
    348  * the result, will also pass the original option name and finally the user data
    349  * object as the third parameter.
    350  *
    351  * The option will first check for the per site name and then the per Network name.
    352  *
    353  * @since 2.0.0
    354  *
    355  * @global wpdb $wpdb WordPress database object for queries.
    356  *
    357  * @param string $option     User option name.
    358  * @param int    $user       Optional. User ID.
    359  * @param string $deprecated Use get_option() to check for an option in the options table.
    360  * @return mixed User option value on success, false on failure.
    361  */
    362 function get_user_option( $option, $user = 0, $deprecated = '' ) {
    363     global $wpdb;
    364 
    365     if ( !empty( $deprecated ) )
    366         _deprecated_argument( __FUNCTION__, '3.0' );
    367 
    368     if ( empty( $user ) )
    369         $user = get_current_user_id();
    370 
    371     if ( ! $user = get_userdata( $user ) )
    372         return false;
    373 
    374     $prefix = $wpdb->get_blog_prefix();
    375     if ( $user->has_prop( $prefix . $option ) ) // Blog specific
    376         $result = $user->get( $prefix . $option );
    377     elseif ( $user->has_prop( $option ) ) // User specific and cross-blog
    378         $result = $user->get( $option );
    379     else
    380         $result = false;
    381 
    382     /**
    383      * Filter a specific user option value.
    384      *
    385      * The dynamic portion of the hook name, `$option`, refers to the user option name.
    386      *
    387      * @since 2.5.0
    388      *
    389      * @param mixed   $result Value for the user's option.
    390      * @param string  $option Name of the option being retrieved.
    391      * @param WP_User $user   WP_User object of the user whose option is being retrieved.
    392      */
    393     return apply_filters( "get_user_option_{$option}", $result, $option, $user );
    394 }
    395 
    396 /**
    397  * Update user option with global blog capability.
    398  *
    399  * User options are just like user metadata except that they have support for
    400  * global blog options. If the 'global' parameter is false, which it is by default
    401  * it will prepend the WordPress table prefix to the option name.
    402  *
    403  * Deletes the user option if $newvalue is empty.
    404  *
    405  * @since 2.0.0
    406  *
    407  * @global wpdb $wpdb WordPress database object for queries.
    408  *
    409  * @param int    $user_id     User ID.
    410  * @param string $option_name User option name.
    411  * @param mixed  $newvalue    User option value.
    412  * @param bool   $global      Optional. Whether option name is global or blog specific.
    413  *                            Default false (blog specific).
    414  * @return int|bool User meta ID if the option didn't exist, true on successful update,
    415  *                  false on failure.
    416  */
    417 function update_user_option( $user_id, $option_name, $newvalue, $global = false ) {
    418     global $wpdb;
    419 
    420     if ( !$global )
    421         $option_name = $wpdb->get_blog_prefix() . $option_name;
    422 
    423     return update_user_meta( $user_id, $option_name, $newvalue );
    424 }
    425 
    426 /**
    427  * Delete user option with global blog capability.
    428  *
    429  * User options are just like user metadata except that they have support for
    430  * global blog options. If the 'global' parameter is false, which it is by default
    431  * it will prepend the WordPress table prefix to the option name.
    432  *
    433  * @since 3.0.0
    434  *
    435  * @global wpdb $wpdb WordPress database object for queries.
    436  *
    437  * @param int    $user_id     User ID
    438  * @param string $option_name User option name.
    439  * @param bool   $global      Optional. Whether option name is global or blog specific.
    440  *                            Default false (blog specific).
    441  * @return bool True on success, false on failure.
    442  */
    443 function delete_user_option( $user_id, $option_name, $global = false ) {
    444     global $wpdb;
    445 
    446     if ( !$global )
    447         $option_name = $wpdb->get_blog_prefix() . $option_name;
    448     return delete_user_meta( $user_id, $option_name );
    449 }
    450 
    451 /**
    452  * WordPress User Query class.
    453  *
    454  * @since 3.1.0
    455  *
    456  * @see WP_User_Query::prepare_query() for information on accepted arguments.
    457  */
    458 class WP_User_Query {
    459 
    460     /**
    461      * Query vars, after parsing
    462      *
    463      * @since 3.5.0
    464      * @access public
    465      * @var array
    466      */
    467     public $query_vars = array();
    468 
    469     /**
    470      * List of found user ids
    471      *
    472      * @since 3.1.0
    473      * @access private
    474      * @var array
    475      */
    476     private $results;
    477 
    478     /**
    479      * Total number of found users for the current query
    480      *
    481      * @since 3.1.0
    482      * @access private
    483      * @var int
    484      */
    485     private $total_users = 0;
    486 
    487     /**
    488      * Metadata query container.
    489      *
    490      * @since 4.2.0
    491      * @access public
    492      * @var object WP_Meta_Query
    493      */
    494     public $meta_query = false;
    495 
    496     private $compat_fields = array( 'results', 'total_users' );
    497 
    498     // SQL clauses
    499     public $query_fields;
    500     public $query_from;
    501     public $query_where;
    502     public $query_orderby;
    503     public $query_limit;
    504 
    505     /**
    506      * PHP5 constructor.
    507      *
    508      * @since 3.1.0
    509      *
    510      * @param null|string|array $args Optional. The query variables.
    511      */
    512     public function __construct( $query = null ) {
    513         if ( ! empty( $query ) ) {
    514             $this->prepare_query( $query );
    515             $this->query();
    516         }
    517     }
    518 
    519     /**
    520      * Prepare the query variables.
    521      *
    522      * @since 3.1.0
    523      * @since 4.2.0 Added 'meta_value_num' support for `$orderby` parameter. Added multi-dimensional array syntax
    524      *              for `$orderby` parameter.
    525      * @since 4.3.0 Added 'has_published_posts' parameter.
    526      * @access public
    527      *
    528      * @global wpdb $wpdb
    529      * @global int  $blog_id
    530      *
    531      * @param string|array $query {
    532      *     Optional. Array or string of Query parameters.
    533      *
    534      *     @type int          $blog_id             The site ID. Default is the global blog id.
    535      *     @type string       $role                Role name. Default empty.
    536      *     @type string       $meta_key            User meta key. Default empty.
    537      *     @type string       $meta_value          User meta value. Default empty.
    538      *     @type string       $meta_compare        Comparison operator to test the `$meta_value`. Accepts '=', '!=',
    539      *                                             '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN',
    540      *                                             'BETWEEN', 'NOT BETWEEN', 'EXISTS', 'NOT EXISTS', 'REGEXP',
    541      *                                             'NOT REGEXP', or 'RLIKE'. Default '='.
    542      *     @type array        $include             An array of user IDs to include. Default empty array.
    543      *     @type array        $exclude             An array of user IDs to exclude. Default empty array.
    544      *     @type string       $search              Search keyword. Searches for possible string matches on columns.
    545      *                                             When `$search_columns` is left empty, it tries to determine which
    546      *                                             column to search in based on search string. Default empty.
    547      *     @type array        $search_columns      Array of column names to be searched. Accepts 'ID', 'login',
    548      *                                             'nicename', 'email', 'url'. Default empty array.
    549      *     @type string|array $orderby             Field(s) to sort the retrieved users by. May be a single value,
    550      *                                             an array of values, or a multi-dimensional array with fields as
    551      *                                             keys and orders ('ASC' or 'DESC') as values. Accepted values are
    552      *                                             'ID', 'display_name' (or 'name'), 'user_login' (or 'login'),
    553      *                                             'user_nicename' (or 'nicename'), 'user_email' (or 'email'),
    554      *                                             'user_url' (or 'url'), 'user_registered' (or 'registered'),
    555      *                                             'post_count', 'meta_value', 'meta_value_num', the value of
    556      *                                             `$meta_key`, or an array key of `$meta_query`. To use
    557      *                                             'meta_value' or 'meta_value_num', `$meta_key` must be also be
    558      *                                             defined. Default 'user_login'.
    559      *     @type string       $order               Designates ascending or descending order of users. Order values
    560      *                                             passed as part of an `$orderby` array take precedence over this
    561      *                                             parameter. Accepts 'ASC', 'DESC'. Default 'ASC'.
    562      *     @type int          $offset              Number of users to offset in retrieved results. Can be used in
    563      *                                             conjunction with pagination. Default 0.
    564      *     @type int          $number              Number of users to limit the query for. Can be used in
    565      *                                             conjunction with pagination. Value -1 (all) is not supported.
    566      *                                             Default empty (all users).
    567      *     @type bool         $count_total         Whether to count the total number of users found. If pagination
    568      *                                             is not needed, setting this to false can improve performance.
    569      *                                             Default true.
    570      *     @type string|array $fields              Which fields to return. Single or all fields (string), or array
    571      *                                             of fields. Accepts 'ID', 'display_name', 'login', 'nicename',
    572      *                                             'email', 'url', 'registered'. Use 'all' for all fields and
    573      *                                             'all_with_meta' to include meta fields. Default 'all'.
    574      *     @type string       $who                 Type of users to query. Accepts 'authors'.
    575      *                                             Default empty (all users).
    576      *     @type bool|array   $has_published_posts Pass an array of post types to filter results to users who have
    577      *                                             published posts in those post types. `true` is an alias for all
    578      *                                             public post types.
    579      * }
    580      */
    581     public function prepare_query( $query = array() ) {
    582         global $wpdb;
    583 
    584         if ( empty( $this->query_vars ) || ! empty( $query ) ) {
    585             $this->query_limit = null;
    586             $this->query_vars = wp_parse_args( $query, array(
    587                 'blog_id' => $GLOBALS['blog_id'],
    588                 'role' => '',
    589                 'meta_key' => '',
    590                 'meta_value' => '',
    591                 'meta_compare' => '',
    592                 'include' => array(),
    593                 'exclude' => array(),
    594                 'search' => '',
    595                 'search_columns' => array(),
    596                 'orderby' => 'login',
    597                 'order' => 'ASC',
    598                 'offset' => '',
    599                 'number' => '',
    600                 'count_total' => true,
    601                 'fields' => 'all',
    602                 'who' => '',
    603                 'has_published_posts' => null,
    604             ) );
    605         }
    606 
    607         /**
    608          * Fires before the WP_User_Query has been parsed.
    609          *
    610          * The passed WP_User_Query object contains the query variables, not
    611          * yet passed into SQL.
    612          *
    613          * @since 4.0.0
    614          *
    615          * @param WP_User_Query $this The current WP_User_Query instance,
    616          *                            passed by reference.
    617          */
    618         do_action( 'pre_get_users', $this );
    619 
    620         $qv =& $this->query_vars;
    621 
    622         if ( is_array( $qv['fields'] ) ) {
    623             $qv['fields'] = array_unique( $qv['fields'] );
    624 
    625             $this->query_fields = array();
    626             foreach ( $qv['fields'] as $field ) {
    627                 $field = 'ID' === $field ? 'ID' : sanitize_key( $field );
    628                 $this->query_fields[] = "$wpdb->users.$field";
    629             }
    630             $this->query_fields = implode( ',', $this->query_fields );
    631         } elseif ( 'all' == $qv['fields'] ) {
    632             $this->query_fields = "$wpdb->users.*";
    633         } else {
    634             $this->query_fields = "$wpdb->users.ID";
    635         }
    636 
    637         if ( isset( $qv['count_total'] ) && $qv['count_total'] )
    638             $this->query_fields = 'SQL_CALC_FOUND_ROWS ' . $this->query_fields;
    639 
    640         $this->query_from = "FROM $wpdb->users";
    641         $this->query_where = "WHERE 1=1";
    642 
    643         // Parse and sanitize 'include', for use by 'orderby' as well as 'include' below.
    644         if ( ! empty( $qv['include'] ) ) {
    645             $include = wp_parse_id_list( $qv['include'] );
    646         } else {
    647             $include = false;
    648         }
    649 
    650         $blog_id = 0;
    651         if ( isset( $qv['blog_id'] ) ) {
    652             $blog_id = absint( $qv['blog_id'] );
    653         }
    654 
    655         if ( isset( $qv['who'] ) && 'authors' == $qv['who'] && $blog_id ) {
    656             $qv['meta_key'] = $wpdb->get_blog_prefix( $blog_id ) . 'user_level';
    657             $qv['meta_value'] = 0;
    658             $qv['meta_compare'] = '!=';
    659             $qv['blog_id'] = $blog_id = 0; // Prevent extra meta query
    660         }
    661 
    662         if ( $qv['has_published_posts'] && $blog_id ) {
    663             if ( true === $qv['has_published_posts'] ) {
    664                 $post_types = get_post_types( array( 'public' => true ) );
    665             } else {
    666                 $post_types = (array) $qv['has_published_posts'];
    667             }
    668 
    669             foreach ( $post_types as &$post_type ) {
    670                 $post_type = $wpdb->prepare( '%s', $post_type );
    671             }
    672 
    673             $posts_table = $wpdb->get_blog_prefix( $blog_id ) . 'posts';
    674             $this->query_where .= " AND $wpdb->users.ID IN ( SELECT DISTINCT $posts_table.post_author FROM $posts_table WHERE $posts_table.post_status = 'publish' AND $posts_table.post_type IN ( " . join( ", ", $post_types ) . " ) )";
    675         }
    676 
    677         // Meta query.
    678         $this->meta_query = new WP_Meta_Query();
    679         $this->meta_query->parse_query_vars( $qv );
    680 
    681         $role = '';
    682         if ( isset( $qv['role'] ) ) {
    683             $role = trim( $qv['role'] );
    684         }
    685 
    686         if ( $blog_id && ( $role || is_multisite() ) ) {
    687             $cap_meta_query = array();
    688             $cap_meta_query['key'] = $wpdb->get_blog_prefix( $blog_id ) . 'capabilities';
    689 
    690             if ( $role ) {
    691                 $cap_meta_query['value'] = '"' . $role . '"';
    692                 $cap_meta_query['compare'] = 'like';
    693             }
    694 
    695             if ( empty( $this->meta_query->queries ) ) {
    696                 $this->meta_query->queries = array( $cap_meta_query );
    697             } elseif ( ! in_array( $cap_meta_query, $this->meta_query->queries, true ) ) {
    698                 // Append the cap query to the original queries and reparse the query.
    699                 $this->meta_query->queries = array(
    700                     'relation' => 'AND',
    701                     array( $this->meta_query->queries, $cap_meta_query ),
    702                 );
    703             }
    704 
    705             $this->meta_query->parse_query_vars( $this->meta_query->queries );
    706         }
    707 
    708         if ( ! empty( $this->meta_query->queries ) ) {
    709             $clauses = $this->meta_query->get_sql( 'user', $wpdb->users, 'ID', $this );
    710             $this->query_from .= $clauses['join'];
    711             $this->query_where .= $clauses['where'];
    712 
    713             if ( $this->meta_query->has_or_relation() ) {
    714                 $this->query_fields = 'DISTINCT ' . $this->query_fields;
    715             }
    716         }
    717 
    718         // sorting
    719         $qv['order'] = isset( $qv['order'] ) ? strtoupper( $qv['order'] ) : '';
    720         $order = $this->parse_order( $qv['order'] );
    721 
    722         if ( empty( $qv['orderby'] ) ) {
    723             // Default order is by 'user_login'.
    724             $ordersby = array( 'user_login' => $order );
    725         } elseif ( is_array( $qv['orderby'] ) ) {
    726             $ordersby = $qv['orderby'];
    727         } else {
    728             // 'orderby' values may be a comma- or space-separated list.
    729             $ordersby = preg_split( '/[,\s]+/', $qv['orderby'] );
    730         }
    731 
    732         $orderby_array = array();
    733         foreach ( $ordersby as $_key => $_value ) {
    734             if ( ! $_value ) {
    735                 continue;
    736             }
    737 
    738             if ( is_int( $_key ) ) {
    739                 // Integer key means this is a flat array of 'orderby' fields.
    740                 $_orderby = $_value;
    741                 $_order = $order;
    742             } else {
    743                 // Non-integer key means this the key is the field and the value is ASC/DESC.
    744                 $_orderby = $_key;
    745                 $_order = $_value;
    746             }
    747 
    748             $parsed = $this->parse_orderby( $_orderby );
    749 
    750             if ( ! $parsed ) {
    751                 continue;
    752             }
    753 
    754             $orderby_array[] = $parsed . ' ' . $this->parse_order( $_order );
    755         }
    756 
    757         // If no valid clauses were found, order by user_login.
    758         if ( empty( $orderby_array ) ) {
    759             $orderby_array[] = "user_login $order";
    760         }
    761 
    762         $this->query_orderby = 'ORDER BY ' . implode( ', ', $orderby_array );
    763 
    764         // limit
    765         if ( isset( $qv['number'] ) && $qv['number'] ) {
    766             if ( $qv['offset'] )
    767                 $this->query_limit = $wpdb->prepare("LIMIT %d, %d", $qv['offset'], $qv['number']);
    768             else
    769                 $this->query_limit = $wpdb->prepare("LIMIT %d", $qv['number']);
    770         }
    771 
    772         $search = '';
    773         if ( isset( $qv['search'] ) )
    774             $search = trim( $qv['search'] );
    775 
    776         if ( $search ) {
    777             $leading_wild = ( ltrim($search, '*') != $search );
    778             $trailing_wild = ( rtrim($search, '*') != $search );
    779             if ( $leading_wild && $trailing_wild )
    780                 $wild = 'both';
    781             elseif ( $leading_wild )
    782                 $wild = 'leading';
    783             elseif ( $trailing_wild )
    784                 $wild = 'trailing';
    785             else
    786                 $wild = false;
    787             if ( $wild )
    788                 $search = trim($search, '*');
    789 
    790             $search_columns = array();
    791             if ( $qv['search_columns'] )
    792                 $search_columns = array_intersect( $qv['search_columns'], array( 'ID', 'user_login', 'user_email', 'user_url', 'user_nicename' ) );
    793             if ( ! $search_columns ) {
    794                 if ( false !== strpos( $search, '@') )
    795                     $search_columns = array('user_email');
    796                 elseif ( is_numeric($search) )
    797                     $search_columns = array('user_login', 'ID');
    798                 elseif ( preg_match('|^https?://|', $search) && ! ( is_multisite() && wp_is_large_network( 'users' ) ) )
    799                     $search_columns = array('user_url');
    800                 else
    801                     $search_columns = array('user_login', 'user_url', 'user_email', 'user_nicename', 'display_name');
    802             }
    803 
    804             /**
    805              * Filter the columns to search in a WP_User_Query search.
    806              *
    807              * The default columns depend on the search term, and include 'user_email',
    808              * 'user_login', 'ID', 'user_url', 'display_name', and 'user_nicename'.
    809              *
    810              * @since 3.6.0
    811              *
    812              * @param array         $search_columns Array of column names to be searched.
    813              * @param string        $search         Text being searched.
    814              * @param WP_User_Query $this           The current WP_User_Query instance.
    815              */
    816             $search_columns = apply_filters( 'user_search_columns', $search_columns, $search, $this );
    817 
    818             $this->query_where .= $this->get_search_sql( $search, $search_columns, $wild );
    819         }
    820 
    821         if ( ! empty( $include ) ) {
    822             // Sanitized earlier.
    823             $ids = implode( ',', $include );
    824             $this->query_where .= " AND $wpdb->users.ID IN ($ids)";
    825         } elseif ( ! empty( $qv['exclude'] ) ) {
    826             $ids = implode( ',', wp_parse_id_list( $qv['exclude'] ) );
    827             $this->query_where .= " AND $wpdb->users.ID NOT IN ($ids)";
    828         }
    829 
    830         // Date queries are allowed for the user_registered field.
    831         if ( ! empty( $qv['date_query'] ) && is_array( $qv['date_query'] ) ) {
    832             $date_query = new WP_Date_Query( $qv['date_query'], 'user_registered' );
    833             $this->query_where .= $date_query->get_sql();
    834         }
    835 
    836         /**
    837          * Fires after the WP_User_Query has been parsed, and before
    838          * the query is executed.
    839          *
    840          * The passed WP_User_Query object contains SQL parts formed
    841          * from parsing the given query.
    842          *
    843          * @since 3.1.0
    844          *
    845          * @param WP_User_Query $this The current WP_User_Query instance,
    846          *                            passed by reference.
    847          */
    848         do_action_ref_array( 'pre_user_query', array( &$this ) );
    849     }
    850 
    851     /**
    852      * Execute the query, with the current variables.
    853      *
    854      * @since 3.1.0
    855      *
    856      * @global wpdb $wpdb WordPress database object for queries.
    857      */
    858     public function query() {
    859         global $wpdb;
    860 
    861         $qv =& $this->query_vars;
    862 
    863         $query = "SELECT $this->query_fields $this->query_from $this->query_where $this->query_orderby $this->query_limit";
    864 
    865         if ( is_array( $qv['fields'] ) || 'all' == $qv['fields'] ) {
    866             $this->results = $wpdb->get_results( $query );
    867         } else {
    868             $this->results = $wpdb->get_col( $query );
    869         }
    870 
    871         /**
    872          * Filter SELECT FOUND_ROWS() query for the current WP_User_Query instance.
    873          *
    874          * @since 3.2.0
    875          *
    876          * @global wpdb $wpdb WordPress database abstraction object.
    877          *
    878          * @param string $sql The SELECT FOUND_ROWS() query for the current WP_User_Query.
    879          */
    880         if ( isset( $qv['count_total'] ) && $qv['count_total'] )
    881             $this->total_users = $wpdb->get_var( apply_filters( 'found_users_query', 'SELECT FOUND_ROWS()' ) );
    882 
    883         if ( !$this->results )
    884             return;
    885 
    886         if ( 'all_with_meta' == $qv['fields'] ) {
    887             cache_users( $this->results );
    888 
    889             $r = array();
    890             foreach ( $this->results as $userid )
    891                 $r[ $userid ] = new WP_User( $userid, '', $qv['blog_id'] );
    892 
    893             $this->results = $r;
    894         } elseif ( 'all' == $qv['fields'] ) {
    895             foreach ( $this->results as $key => $user ) {
    896                 $this->results[ $key ] = new WP_User( $user, '', $qv['blog_id'] );
    897             }
    898         }
    899     }
    900 
    901     /**
    902      * Retrieve query variable.
    903      *
    904      * @since 3.5.0
    905      * @access public
    906      *
    907      * @param string $query_var Query variable key.
    908      * @return mixed
    909      */
    910     public function get( $query_var ) {
    911         if ( isset( $this->query_vars[$query_var] ) )
    912             return $this->query_vars[$query_var];
    913 
    914         return null;
    915     }
    916 
    917     /**
    918      * Set query variable.
    919      *
    920      * @since 3.5.0
    921      * @access public
    922      *
    923      * @param string $query_var Query variable key.
    924      * @param mixed $value Query variable value.
    925      */
    926     public function set( $query_var, $value ) {
    927         $this->query_vars[$query_var] = $value;
    928     }
    929 
    930     /**
    931      * Used internally to generate an SQL string for searching across multiple columns
    932      *
    933      * @access protected
    934      * @since 3.1.0
    935      *
    936      * @global wpdb $wpdb
    937      *
    938      * @param string $string
    939      * @param array  $cols
    940      * @param bool   $wild   Whether to allow wildcard searches. Default is false for Network Admin, true for single site.
    941      *                       Single site allows leading and trailing wildcards, Network Admin only trailing.
    942      * @return string
    943      */
    944     protected function get_search_sql( $string, $cols, $wild = false ) {
    945         global $wpdb;
    946 
    947         $searches = array();
    948         $leading_wild = ( 'leading' == $wild || 'both' == $wild ) ? '%' : '';
    949         $trailing_wild = ( 'trailing' == $wild || 'both' == $wild ) ? '%' : '';
    950         $like = $leading_wild . $wpdb->esc_like( $string ) . $trailing_wild;
    951 
    952         foreach ( $cols as $col ) {
    953             if ( 'ID' == $col ) {
    954                 $searches[] = $wpdb->prepare( "$col = %s", $string );
    955             } else {
    956                 $searches[] = $wpdb->prepare( "$col LIKE %s", $like );
    957             }
    958         }
    959 
    960         return ' AND (' . implode(' OR ', $searches) . ')';
    961     }
    962 
    963     /**
    964      * Return the list of users.
    965      *
    966      * @since 3.1.0
    967      * @access public
    968      *
    969      * @return array Array of results.
    970      */
    971     public function get_results() {
    972         return $this->results;
    973     }
    974 
    975     /**
    976      * Return the total number of users for the current query.
    977      *
    978      * @since 3.1.0
    979      * @access public
    980      *
    981      * @return int Number of total users.
    982      */
    983     public function get_total() {
    984         return $this->total_users;
    985     }
    986 
    987     /**
    988      * Parse and sanitize 'orderby' keys passed to the user query.
    989      *
    990      * @since 4.2.0
    991      * @access protected
    992      *
    993      * @global wpdb $wpdb WordPress database abstraction object.
    994      *
    995      * @param string $orderby Alias for the field to order by.
    996      * @return string Value to used in the ORDER clause, if `$orderby` is valid.
    997      */
    998     protected function parse_orderby( $orderby ) {
    999         global $wpdb;
    1000 
    1001         $meta_query_clauses = $this->meta_query->get_clauses();
    1002 
    1003         $_orderby = '';
    1004         if ( in_array( $orderby, array( 'login', 'nicename', 'email', 'url', 'registered' ) ) ) {
    1005             $_orderby = 'user_' . $orderby;
    1006         } elseif ( in_array( $orderby, array( 'user_login', 'user_nicename', 'user_email', 'user_url', 'user_registered' ) ) ) {
    1007             $_orderby = $orderby;
    1008         } elseif ( 'name' == $orderby || 'display_name' == $orderby ) {
    1009             $_orderby = 'display_name';
    1010         } elseif ( 'post_count' == $orderby ) {
    1011             // todo: avoid the JOIN
    1012             $where = get_posts_by_author_sql( 'post' );
    1013             $this->query_from .= " LEFT OUTER JOIN (
    1014                 SELECT post_author, COUNT(*) as post_count
    1015                 FROM $wpdb->posts
    1016                 $where
    1017                 GROUP BY post_author
    1018             ) p ON ({$wpdb->users}.ID = p.post_author)
    1019             ";
    1020             $_orderby = 'post_count';
    1021         } elseif ( 'ID' == $orderby || 'id' == $orderby ) {
    1022             $_orderby = 'ID';
    1023         } elseif ( 'meta_value' == $orderby || $this->get( 'meta_key' ) == $orderby ) {
    1024             $_orderby = "$wpdb->usermeta.meta_value";
    1025         } elseif ( 'meta_value_num' == $orderby ) {
    1026             $_orderby = "$wpdb->usermeta.meta_value+0";
    1027         } elseif ( 'include' === $orderby && ! empty( $this->query_vars['include'] ) ) {
    1028             $include = wp_parse_id_list( $this->query_vars['include'] );
    1029             $include_sql = implode( ',', $include );
    1030             $_orderby = "FIELD( $wpdb->users.ID, $include_sql )";
    1031         } elseif ( isset( $meta_query_clauses[ $orderby ] ) ) {
    1032             $meta_clause = $meta_query_clauses[ $orderby ];
    1033             $_orderby = sprintf( "CAST(%s.meta_value AS %s)", esc_sql( $meta_clause['alias'] ), esc_sql( $meta_clause['cast'] ) );
    1034         }
    1035 
    1036         return $_orderby;
    1037     }
    1038 
    1039     /**
    1040      * Parse an 'order' query variable and cast it to ASC or DESC as necessary.
    1041      *
    1042      * @since 4.2.0
    1043      * @access protected
    1044      *
    1045      * @param string $order The 'order' query variable.
    1046      * @return string The sanitized 'order' query variable.
    1047      */
    1048     protected function parse_order( $order ) {
    1049         if ( ! is_string( $order ) || empty( $order ) ) {
    1050             return 'DESC';
    1051         }
    1052 
    1053         if ( 'ASC' === strtoupper( $order ) ) {
    1054             return 'ASC';
    1055         } else {
    1056             return 'DESC';
    1057         }
    1058     }
    1059 
    1060     /**
    1061      * Make private properties readable for backwards compatibility.
    1062      *
    1063      * @since 4.0.0
    1064      * @access public
    1065      *
    1066      * @param string $name Property to get.
    1067      * @return mixed Property.
    1068      */
    1069     public function __get( $name ) {
    1070         if ( in_array( $name, $this->compat_fields ) ) {
    1071             return $this->$name;
    1072         }
    1073     }
    1074 
    1075     /**
    1076      * Make private properties settable for backwards compatibility.
    1077      *
    1078      * @since 4.0.0
    1079      * @access public
    1080      *
    1081      * @param string $name  Property to check if set.
    1082      * @param mixed  $value Property value.
    1083      * @return mixed Newly-set property.
    1084      */
    1085     public function __set( $name, $value ) {
    1086         if ( in_array( $name, $this->compat_fields ) ) {
    1087             return $this->$name = $value;
    1088         }
    1089     }
    1090 
    1091     /**
    1092      * Make private properties checkable for backwards compatibility.
    1093      *
    1094      * @since 4.0.0
    1095      * @access public
    1096      *
    1097      * @param string $name Property to check if set.
    1098      * @return bool Whether the property is set.
    1099      */
    1100     public function __isset( $name ) {
    1101         if ( in_array( $name, $this->compat_fields ) ) {
    1102             return isset( $this->$name );
    1103         }
    1104     }
    1105 
    1106     /**
    1107      * Make private properties un-settable for backwards compatibility.
    1108      *
    1109      * @since 4.0.0
    1110      * @access public
    1111      *
    1112      * @param string $name Property to unset.
    1113      */
    1114     public function __unset( $name ) {
    1115         if ( in_array( $name, $this->compat_fields ) ) {
    1116             unset( $this->$name );
    1117         }
    1118     }
    1119 
    1120     /**
    1121      * Make private/protected methods readable for backwards compatibility.
    1122      *
    1123      * @since 4.0.0
    1124      * @access public
    1125      *
    1126      * @param callable $name      Method to call.
    1127      * @param array    $arguments Arguments to pass when calling.
    1128      * @return mixed Return value of the callback, false otherwise.
    1129      */
    1130     public function __call( $name, $arguments ) {
    1131         if ( 'get_search_sql' === $name ) {
    1132             return call_user_func_array( array( $this, $name ), $arguments );
    1133         }
    1134         return false;
    1135     }
    1136 }
    1137 
    1138 /**
    1139  * Retrieve list of users matching criteria.
    1140  *
    1141  * @since 3.1.0
    1142  *
    1143  * @see WP_User_Query
    1144  *
    1145  * @param array $args Optional. Arguments to retrieve users. See {@see WP_User_Query::prepare_query()}
    1146  *                    for more information on accepted arguments.
    1147  * @return array List of users.
    1148  */
    1149 function get_users( $args = array() ) {
    1150 
    1151     $args = wp_parse_args( $args );
    1152     $args['count_total'] = false;
    1153 
    1154     $user_search = new WP_User_Query($args);
    1155 
    1156     return (array) $user_search->get_results();
    1157 }
    1158 
    1159 /**
    1160  * Get the blogs a user belongs to.
    1161  *
    1162  * @since 3.0.0
    1163  *
    1164  * @global wpdb $wpdb WordPress database object for queries.
    1165  *
    1166  * @param int  $user_id User ID
    1167  * @param bool $all     Whether to retrieve all blogs, or only blogs that are not
    1168  *                      marked as deleted, archived, or spam.
    1169  * @return array A list of the user's blogs. An empty array if the user doesn't exist
    1170  *               or belongs to no blogs.
    1171  */
    1172 function get_blogs_of_user( $user_id, $all = false ) {
    1173     global $wpdb;
    1174 
    1175     $user_id = (int) $user_id;
    1176 
    1177     // Logged out users can't have blogs
    1178     if ( empty( $user_id ) )
    1179         return array();
    1180 
    1181     $keys = get_user_meta( $user_id );
    1182     if ( empty( $keys ) )
    1183         return array();
    1184 
    1185     if ( ! is_multisite() ) {
    1186         $blog_id = get_current_blog_id();
    1187         $blogs = array( $blog_id => new stdClass );
    1188         $blogs[ $blog_id ]->userblog_id = $blog_id;
    1189         $blogs[ $blog_id ]->blogname = get_option('blogname');
    1190         $blogs[ $blog_id ]->domain = '';
    1191         $blogs[ $blog_id ]->path = '';
    1192         $blogs[ $blog_id ]->site_id = 1;
    1193         $blogs[ $blog_id ]->siteurl = get_option('siteurl');
    1194         $blogs[ $blog_id ]->archived = 0;
    1195         $blogs[ $blog_id ]->spam = 0;
    1196         $blogs[ $blog_id ]->deleted = 0;
    1197         return $blogs;
    1198     }
    1199 
    1200     $blogs = array();
    1201 
    1202     if ( isset( $keys[ $wpdb->base_prefix . 'capabilities' ] ) && defined( 'MULTISITE' ) ) {
    1203         $blog = get_blog_details( 1 );
    1204         if ( $blog && isset( $blog->domain ) && ( $all || ( ! $blog->archived && ! $blog->spam && ! $blog->deleted ) ) ) {
    1205             $blogs[ 1 ] = (object) array(
    1206                 'userblog_id' => 1,
    1207                 'blogname'    => $blog->blogname,
    1208                 'domain'      => $blog->domain,
    1209                 'path'        => $blog->path,
    1210                 'site_id'     => $blog->site_id,
    1211                 'siteurl'     => $blog->siteurl,
    1212                 'archived'    => $blog->archived,
    1213                 'mature'      => $blog->mature,
    1214                 'spam'        => $blog->spam,
    1215                 'deleted'     => $blog->deleted,
    1216             );
    1217         }
    1218         unset( $keys[ $wpdb->base_prefix . 'capabilities' ] );
    1219     }
    1220 
    1221     $keys = array_keys( $keys );
    1222 
    1223     foreach ( $keys as $key ) {
    1224         if ( 'capabilities' !== substr( $key, -12 ) )
    1225             continue;
    1226         if ( $wpdb->base_prefix && 0 !== strpos( $key, $wpdb->base_prefix ) )
    1227             continue;
    1228         $blog_id = str_replace( array( $wpdb->base_prefix, '_capabilities' ), '', $key );
    1229         if ( ! is_numeric( $blog_id ) )
    1230             continue;
    1231 
    1232         $blog_id = (int) $blog_id;
    1233         $blog = get_blog_details( $blog_id );
    1234         if ( $blog && isset( $blog->domain ) && ( $all || ( ! $blog->archived && ! $blog->spam && ! $blog->deleted ) ) ) {
    1235             $blogs[ $blog_id ] = (object) array(
    1236                 'userblog_id' => $blog_id,
    1237                 'blogname'    => $blog->blogname,
    1238                 'domain'      => $blog->domain,
    1239                 'path'        => $blog->path,
    1240                 'site_id'     => $blog->site_id,
    1241                 'siteurl'     => $blog->siteurl,
    1242                 'archived'    => $blog->archived,
    1243                 'mature'      => $blog->mature,
    1244                 'spam'        => $blog->spam,
    1245                 'deleted'     => $blog->deleted,
    1246             );
    1247         }
    1248     }
    1249 
    1250     /**
    1251      * Filter the list of blogs a user belongs to.
    1252      *
    1253      * @since MU
    1254      *
    1255      * @param array $blogs   An array of blog objects belonging to the user.
    1256      * @param int   $user_id User ID.
    1257      * @param bool  $all     Whether the returned blogs array should contain all blogs, including
    1258      *                       those marked 'deleted', 'archived', or 'spam'. Default false.
    1259      */
    1260     return apply_filters( 'get_blogs_of_user', $blogs, $user_id, $all );
    1261 }
    1262 
    1263 /**
    1264  * Find out whether a user is a member of a given blog.
    1265  *
    1266  * @since MU 1.1
    1267  *
    1268  * @param int $user_id Optional. The unique ID of the user. Defaults to the current user.
    1269  * @param int $blog_id Optional. ID of the blog to check. Defaults to the current site.
    1270  * @return bool
    1271  */
    1272 function is_user_member_of_blog( $user_id = 0, $blog_id = 0 ) {
    1273     $user_id = (int) $user_id;
    1274     $blog_id = (int) $blog_id;
    1275 
    1276     if ( empty( $user_id ) )
    1277         $user_id = get_current_user_id();
    1278 
    1279     if ( empty( $blog_id ) )
    1280         $blog_id = get_current_blog_id();
    1281 
    1282     $blogs = get_blogs_of_user( $user_id );
    1283     return array_key_exists( $blog_id, $blogs );
    1284 }
    1285 
    1286 /**
    1287  * Add meta data field to a user.
    1288  *
    1289  * Post meta data is called "Custom Fields" on the Administration Screens.
    1290  *
    1291  * @since 3.0.0
    1292  * @link https://codex.wordpress.org/Function_Reference/add_user_meta
    1293  *
    1294  * @param int    $user_id    User ID.
    1295  * @param string $meta_key   Metadata name.
    1296  * @param mixed  $meta_value Metadata value.
    1297  * @param bool   $unique     Optional, default is false. Whether the same key should not be added.
    1298  * @return int|false Meta ID on success, false on failure.
    1299  */
    1300 function add_user_meta($user_id, $meta_key, $meta_value, $unique = false) {
    1301     return add_metadata('user', $user_id, $meta_key, $meta_value, $unique);
    1302 }
    1303 
    1304 /**
    1305  * Remove metadata matching criteria from a user.
    1306  *
    1307  * You can match based on the key, or key and value. Removing based on key and
    1308  * value, will keep from removing duplicate metadata with the same key. It also
    1309  * allows removing all metadata matching key, if needed.
    1310  *
    1311  * @since 3.0.0
    1312  * @link https://codex.wordpress.org/Function_Reference/delete_user_meta
    1313  *
    1314  * @param int    $user_id    User ID
    1315  * @param string $meta_key   Metadata name.
    1316  * @param mixed  $meta_value Optional. Metadata value.
    1317  * @return bool True on success, false on failure.
    1318  */
    1319 function delete_user_meta($user_id, $meta_key, $meta_value = '') {
    1320     return delete_metadata('user', $user_id, $meta_key, $meta_value);
    1321 }
    1322 
    1323 /**
    1324  * Retrieve user meta field for a user.
    1325  *
    1326  * @since 3.0.0
    1327  * @link https://codex.wordpress.org/Function_Reference/get_user_meta
    1328  *
    1329  * @param int    $user_id User ID.
    1330  * @param string $key     Optional. The meta key to retrieve. By default, returns data for all keys.
    1331  * @param bool   $single  Whether to return a single value.
    1332  * @return mixed Will be an array if $single is false. Will be value of meta data field if $single is true.
    1333  */
    1334 function get_user_meta($user_id, $key = '', $single = false) {
    1335     return get_metadata('user', $user_id, $key, $single);
    1336 }
    1337 
    1338 /**
    1339  * Update user meta field based on user ID.
    1340  *
    1341  * Use the $prev_value parameter to differentiate between meta fields with the
    1342  * same key and user ID.
    1343  *
    1344  * If the meta field for the user does not exist, it will be added.
    1345  *
    1346  * @since 3.0.0
    1347  * @link https://codex.wordpress.org/Function_Reference/update_user_meta
    1348  *
    1349  * @param int    $user_id    User ID.
    1350  * @param string $meta_key   Metadata key.
    1351  * @param mixed  $meta_value Metadata value.
    1352  * @param mixed  $prev_value Optional. Previous value to check before removing.
    1353  * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
    1354  */
    1355 function update_user_meta($user_id, $meta_key, $meta_value, $prev_value = '') {
    1356     return update_metadata('user', $user_id, $meta_key, $meta_value, $prev_value);
    1357 }
    1358 
    1359 /**
    1360  * Count number of users who have each of the user roles.
    1361  *
    1362  * Assumes there are neither duplicated nor orphaned capabilities meta_values.
    1363  * Assumes role names are unique phrases. Same assumption made by WP_User_Query::prepare_query()
    1364  * Using $strategy = 'time' this is CPU-intensive and should handle around 10^7 users.
    1365  * Using $strategy = 'memory' this is memory-intensive and should handle around 10^5 users, but see WP Bug #12257.
    1366  *
    1367  * @since 3.0.0
    1368  *
    1369  * @global wpdb $wpdb
    1370  *
    1371  * @param string $strategy 'time' or 'memory'
    1372  * @return array Includes a grand total and an array of counts indexed by role strings.
    1373  */
    1374 function count_users($strategy = 'time') {
    1375     global $wpdb;
    1376 
    1377     // Initialize
    1378     $id = get_current_blog_id();
    1379     $blog_prefix = $wpdb->get_blog_prefix($id);
    1380     $result = array();
    1381 
    1382     if ( 'time' == $strategy ) {
    1383         $avail_roles = wp_roles()->get_names();
    1384 
    1385         // Build a CPU-intensive query that will return concise information.
    1386         $select_count = array();
    1387         foreach ( $avail_roles as $this_role => $name ) {
    1388             $select_count[] = $wpdb->prepare( "COUNT(NULLIF(`meta_value` LIKE %s, false))", '%' . $wpdb->esc_like( '"' . $this_role . '"' ) . '%');
    1389         }
    1390         $select_count = implode(', ', $select_count);
    1391 
    1392         // Add the meta_value index to the selection list, then run the query.
    1393         $row = $wpdb->get_row( "SELECT $select_count, COUNT(*) FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'", ARRAY_N );
    1394 
    1395         // Run the previous loop again to associate results with role names.
    1396         $col = 0;
    1397         $role_counts = array();
    1398         foreach ( $avail_roles as $this_role => $name ) {
    1399             $count = (int) $row[$col++];
    1400             if ($count > 0) {
    1401                 $role_counts[$this_role] = $count;
    1402             }
    1403         }
    1404 
    1405         // Get the meta_value index from the end of the result set.
    1406         $total_users = (int) $row[$col];
    1407 
    1408         $result['total_users'] = $total_users;
    1409         $result['avail_roles'] =& $role_counts;
    1410     } else {
    1411         $avail_roles = array();
    1412 
    1413         $users_of_blog = $wpdb->get_col( "SELECT meta_value FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'" );
    1414 
    1415         foreach ( $users_of_blog as $caps_meta ) {
    1416             $b_roles = maybe_unserialize($caps_meta);
    1417             if ( ! is_array( $b_roles ) )
    1418                 continue;
    1419             foreach ( $b_roles as $b_role => $val ) {
    1420                 if ( isset($avail_roles[$b_role]) ) {
    1421                     $avail_roles[$b_role]++;
    1422                 } else {
    1423                     $avail_roles[$b_role] = 1;
    1424                 }
    1425             }
    1426         }
    1427 
    1428         $result['total_users'] = count( $users_of_blog );
    1429         $result['avail_roles'] =& $avail_roles;
    1430     }
    1431 
    1432     return $result;
    1433 }
    1434 
    1435 //
    1436 // Private helper functions
    1437 //
    1438 
    1439 /**
    1440  * Set up global user vars.
    1441  *
    1442  * Used by wp_set_current_user() for back compat. Might be deprecated in the future.
    1443  *
    1444  * @since 2.0.4
    1445  *
    1446  * @global string $user_login    The user username for logging in
    1447  * @global object $userdata      User data.
    1448  * @global int    $user_level    The level of the user
    1449  * @global int    $user_ID       The ID of the user
    1450  * @global string $user_email    The email address of the user
    1451  * @global string $user_url      The url in the user's profile
    1452  * @global string $user_identity The display name of the user
    1453  *
    1454  * @param int $for_user_id Optional. User ID to set up global data.
    1455  */
    1456 function setup_userdata($for_user_id = '') {
    1457     global $user_login, $userdata, $user_level, $user_ID, $user_email, $user_url, $user_identity;
    1458 
    1459     if ( '' == $for_user_id )
    1460         $for_user_id = get_current_user_id();
    1461     $user = get_userdata( $for_user_id );
    1462 
    1463     if ( ! $user ) {
    1464         $user_ID = 0;
    1465         $user_level = 0;
    1466         $userdata = null;
    1467         $user_login = $user_email = $user_url = $user_identity = '';
    1468         return;
    1469     }
    1470 
    1471     $user_ID    = (int) $user->ID;
    1472     $user_level = (int) $user->user_level;
    1473     $userdata   = $user;
    1474     $user_login = $user->user_login;
    1475     $user_email = $user->user_email;
    1476     $user_url   = $user->user_url;
    1477     $user_identity = $user->display_name;
    1478 }
    1479 
    1480 /**
    1481  * Create dropdown HTML content of users.
    1482  *
    1483  * The content can either be displayed, which it is by default or retrieved by
    1484  * setting the 'echo' argument. The 'include' and 'exclude' arguments do not
    1485  * need to be used; all users will be displayed in that case. Only one can be
    1486  * used, either 'include' or 'exclude', but not both.
    1487  *
    1488  * The available arguments are as follows:
    1489  *
    1490  * @since 2.3.0
    1491  *
    1492  * @global wpdb $wpdb WordPress database object for queries.
    1493  * @global int  $blog_id
    1494  *
    1495  * @param array|string $args {
    1496  *     Optional. Array or string of arguments to generate a drop-down of users.
    1497  *     {@see WP_User_Query::prepare_query() for additional available arguments.
    1498  *
    1499  *     @type string       $show_option_all         Text to show as the drop-down default (all).
    1500  *                                                 Default empty.
    1501  *     @type string       $show_option_none        Text to show as the drop-down default when no
    1502  *                                                 users were found. Default empty.
    1503  *     @type int|string   $option_none_value       Value to use for $show_option_non when no users
    1504  *                                                 were found. Default -1.
    1505  *     @type string       $hide_if_only_one_author Whether to skip generating the drop-down
    1506  *                                                 if only one user was found. Default empty.
    1507  *     @type string       $orderby                 Field to order found users by. Accepts user fields.
    1508  *                                                 Default 'display_name'.
    1509  *     @type string       $order                   Whether to order users in ascending or descending
    1510  *                                                 order. Accepts 'ASC' (ascending) or 'DESC' (descending).
    1511  *                                                 Default 'ASC'.
    1512  *     @type array|string $include                 Array or comma-separated list of user IDs to include.
    1513  *                                                 Default empty.
    1514  *     @type array|string $exclude                 Array or comma-separated list of user IDs to exclude.
    1515  *                                                 Default empty.
    1516  *     @type bool|int     $multi                   Whether to skip the ID attribute on the 'select' element.
    1517  *                                                 Accepts 1|true or 0|false. Default 0|false.
    1518  *     @type string       $show                    User table column to display. If the selected item is empty
    1519  *                                                 then the 'user_login' will be displayed in parentheses.
    1520  *                                                 Accepts user fields. Default 'display_name'.
    1521  *     @type int|bool     $echo                    Whether to echo or return the drop-down. Accepts 1|true (echo)
    1522  *                                                 or 0|false (return). Default 1|true.
    1523  *     @type int          $selected                Which user ID should be selected. Default 0.
    1524  *     @type bool         $include_selected        Whether to always include the selected user ID in the drop-
    1525  *                                                 down. Default false.
    1526  *     @type string       $name                    Name attribute of select element. Default 'user'.
    1527  *     @type string       $id                      ID attribute of the select element. Default is the value of $name.
    1528  *     @type string       $class                   Class attribute of the select element. Default empty.
    1529  *     @type int          $blog_id                 ID of blog (Multisite only). Default is ID of the current blog.
    1530  *     @type string       $who                     Which type of users to query. Accepts only an empty string or
    1531  *                                                 'authors'. Default empty.
    1532  * }
    1533  * @return string String of HTML content.
    1534  */
    1535 function wp_dropdown_users( $args = '' ) {
    1536     $defaults = array(
    1537         'show_option_all' => '', 'show_option_none' => '', 'hide_if_only_one_author' => '',
    1538         'orderby' => 'display_name', 'order' => 'ASC',
    1539         'include' => '', 'exclude' => '', 'multi' => 0,
    1540         'show' => 'display_name', 'echo' => 1,
    1541         'selected' => 0, 'name' => 'user', 'class' => '', 'id' => '',
    1542         'blog_id' => $GLOBALS['blog_id'], 'who' => '', 'include_selected' => false,
    1543         'option_none_value' => -1
    1544     );
    1545 
    1546     $defaults['selected'] = is_author() ? get_query_var( 'author' ) : 0;
    1547 
    1548     $r = wp_parse_args( $args, $defaults );
    1549     $show = $r['show'];
    1550     $show_option_all = $r['show_option_all'];
    1551     $show_option_none = $r['show_option_none'];
    1552     $option_none_value = $r['option_none_value'];
    1553 
    1554     $query_args = wp_array_slice_assoc( $r, array( 'blog_id', 'include', 'exclude', 'orderby', 'order', 'who' ) );
    1555     $query_args['fields'] = array( 'ID', 'user_login', $show );
    1556     $users = get_users( $query_args );
    1557 
    1558     $output = '';
    1559     if ( ! empty( $users ) && ( empty( $r['hide_if_only_one_author'] ) || count( $users ) > 1 ) ) {
    1560         $name = esc_attr( $r['name'] );
    1561         if ( $r['multi'] && ! $r['id'] ) {
    1562             $id = '';
    1563         } else {
    1564             $id = $r['id'] ? " id='" . esc_attr( $r['id'] ) . "'" : " id='$name'";
    1565         }
    1566         $output = "<select name='{$name}'{$id} class='" . $r['class'] . "'>\n";
    1567 
    1568         if ( $show_option_all ) {
    1569             $output .= "\t<option value='0'>$show_option_all</option>\n";
    1570         }
    1571 
    1572         if ( $show_option_none ) {
    1573             $_selected = selected( $option_none_value, $r['selected'], false );
    1574             $output .= "\t<option value='" . esc_attr( $option_none_value ) . "'$_selected>$show_option_none</option>\n";
    1575         }
    1576 
    1577         $found_selected = false;
    1578         foreach ( (array) $users as $user ) {
    1579             $user->ID = (int) $user->ID;
    1580             $_selected = selected( $user->ID, $r['selected'], false );
    1581             if ( $_selected ) {
    1582                 $found_selected = true;
    1583             }
    1584             $display = ! empty( $user->$show ) ? $user->$show : '('. $user->user_login . ')';
    1585             $output .= "\t<option value='$user->ID'$_selected>" . esc_html( $display ) . "</option>\n";
    1586         }
    1587 
    1588         if ( $r['include_selected'] && ! $found_selected && ( $r['selected'] > 0 ) ) {
    1589             $user = get_userdata( $r['selected'] );
    1590             $_selected = selected( $user->ID, $r['selected'], false );
    1591             $display = ! empty( $user->$show ) ? $user->$show : '('. $user->user_login . ')';
    1592             $output .= "\t<option value='$user->ID'$_selected>" . esc_html( $display ) . "</option>\n";
    1593         }
    1594 
    1595         $output .= "</select>";
    1596     }
    1597 
    1598     /**
    1599      * Filter the wp_dropdown_users() HTML output.
    1600      *
    1601      * @since 2.3.0
    1602      *
    1603      * @param string $output HTML output generated by wp_dropdown_users().
    1604      */
    1605     $html = apply_filters( 'wp_dropdown_users', $output );
    1606 
    1607     if ( $r['echo'] ) {
    1608         echo $html;
    1609     }
    1610     return $html;
    1611 }
    1612 
    1613 /**
    1614  * Sanitize user field based on context.
    1615  *
    1616  * Possible context values are:  'raw', 'edit', 'db', 'display', 'attribute' and 'js'. The
    1617  * 'display' context is used by default. 'attribute' and 'js' contexts are treated like 'display'
    1618  * when calling filters.
    1619  *
    1620  * @since 2.3.0
    1621  *
    1622  * @param string $field   The user Object field name.
    1623  * @param mixed  $value   The user Object value.
    1624  * @param int    $user_id User ID.
    1625  * @param string $context How to sanitize user fields. Looks for 'raw', 'edit', 'db', 'display',
    1626  *                        'attribute' and 'js'.
    1627  * @return mixed Sanitized value.
    1628  */
    1629 function sanitize_user_field($field, $value, $user_id, $context) {
    1630     $int_fields = array('ID');
    1631     if ( in_array($field, $int_fields) )
    1632         $value = (int) $value;
    1633 
    1634     if ( 'raw' == $context )
    1635         return $value;
    1636 
    1637     if ( !is_string($value) && !is_numeric($value) )
    1638         return $value;
    1639 
    1640     $prefixed = false !== strpos( $field, 'user_' );
    1641 
    1642     if ( 'edit' == $context ) {
    1643         if ( $prefixed ) {
    1644 
    1645             /** This filter is documented in wp-includes/post.php */
    1646             $value = apply_filters( "edit_{$field}", $value, $user_id );
    1647         } else {
    1648 
    1649             /**
    1650              * Filter a user field value in the 'edit' context.
    1651              *
    1652              * The dynamic portion of the hook name, `$field`, refers to the prefixed user
    1653              * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.
    1654              *
    1655              * @since 2.9.0
    1656              *
    1657              * @param mixed $value   Value of the prefixed user field.
    1658              * @param int   $user_id User ID.
    1659              */
    1660             $value = apply_filters( "edit_user_{$field}", $value, $user_id );
    1661         }
    1662 
    1663         if ( 'description' == $field )
    1664             $value = esc_html( $value ); // textarea_escaped?
    1665         else
    1666             $value = esc_attr($value);
    1667     } elseif ( 'db' == $context ) {
    1668         if ( $prefixed ) {
    1669             /** This filter is documented in wp-includes/post.php */
    1670             $value = apply_filters( "pre_{$field}", $value );
    1671         } else {
    1672 
    1673             /**
    1674              * Filter the value of a user field in the 'db' context.
    1675              *
    1676              * The dynamic portion of the hook name, `$field`, refers to the prefixed user
    1677              * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.
    1678              *
    1679              * @since 2.9.0
    1680              *
    1681              * @param mixed $value Value of the prefixed user field.
    1682              */
    1683             $value = apply_filters( "pre_user_{$field}", $value );
    1684         }
    1685     } else {
    1686         // Use display filters by default.
    1687         if ( $prefixed ) {
    1688 
    1689             /** This filter is documented in wp-includes/post.php */
    1690             $value = apply_filters( $field, $value, $user_id, $context );
    1691         } else {
    1692 
    1693             /**
    1694              * Filter the value of a user field in a standard context.
    1695              *
    1696              * The dynamic portion of the hook name, `$field`, refers to the prefixed user
    1697              * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.
    1698              *
    1699              * @since 2.9.0
    1700              *
    1701              * @param mixed  $value   The user object value to sanitize.
    1702              * @param int    $user_id User ID.
    1703              * @param string $context The context to filter within.
    1704              */
    1705             $value = apply_filters( "user_{$field}", $value, $user_id, $context );
    1706         }
    1707     }
    1708 
    1709     if ( 'user_url' == $field )
    1710         $value = esc_url($value);
    1711 
    1712     if ( 'attribute' == $context ) {
    1713         $value = esc_attr( $value );
    1714     } elseif ( 'js' == $context ) {
    1715         $value = esc_js( $value );
    1716     }
    1717     return $value;
    1718 }
    1719 
    1720 /**
    1721  * Update all user caches
    1722  *
    1723  * @since 3.0.0
    1724  *
    1725  * @param object $user User object to be cached
    1726  */
    1727 function update_user_caches($user) {
    1728     wp_cache_add($user->ID, $user, 'users');
    1729     wp_cache_add($user->user_login, $user->ID, 'userlogins');
    1730     wp_cache_add($user->user_email, $user->ID, 'useremail');
    1731     wp_cache_add($user->user_nicename, $user->ID, 'userslugs');
    1732 }
    1733 
    1734 /**
    1735  * Clean all user caches
    1736  *
    1737  * @since 3.0.0
    1738  *
    1739  * @param WP_User|int $user User object or ID to be cleaned from the cache
    1740  */
    1741 function clean_user_cache( $user ) {
    1742     if ( is_numeric( $user ) )
    1743         $user = new WP_User( $user );
    1744 
    1745     if ( ! $user->exists() )
    1746         return;
    1747 
    1748     wp_cache_delete( $user->ID, 'users' );
    1749     wp_cache_delete( $user->user_login, 'userlogins' );
    1750     wp_cache_delete( $user->user_email, 'useremail' );
    1751     wp_cache_delete( $user->user_nicename, 'userslugs' );
    1752 }
    1753 
    1754 /**
    1755  * Checks whether the given username exists.
    1756  *
    1757  * @since 2.0.0
    1758  *
    1759  * @param string $username Username.
    1760  * @return int|false The user's ID on success, and false on failure.
    1761  */
    1762 function username_exists( $username ) {
    1763     if ( $user = get_user_by( 'login', $username ) ) {
    1764         return $user->ID;
    1765     }
    1766     return false;
    1767 }
    1768 
    1769 /**
    1770  * Checks whether the given email exists.
    1771  *
    1772  * @since 2.1.0
    1773  *
    1774  * @param string $email Email.
    1775  * @return int|false The user's ID on success, and false on failure.
    1776  */
    1777 function email_exists( $email ) {
    1778     if ( $user = get_user_by( 'email', $email) ) {
    1779         return $user->ID;
    1780     }
    1781     return false;
    1782 }
    1783 
    1784 /**
    1785  * Checks whether a username is valid.
    1786  *
    1787  * @since 2.0.1
    1788  *
    1789  * @param string $username Username.
    1790  * @return bool Whether username given is valid
    1791  */
    1792 function validate_username( $username ) {
    1793     $sanitized = sanitize_user( $username, true );
    1794     $valid = ( $sanitized == $username );
    1795     /**
    1796      * Filter whether the provided username is valid or not.
    1797      *
    1798      * @since 2.0.1
    1799      *
    1800      * @param bool   $valid    Whether given username is valid.
    1801      * @param string $username Username to check.
    1802      */
    1803     return apply_filters( 'validate_username', $valid, $username );
    1804 }
    1805 
    1806 /**
    1807  * Insert a user into the database.
    1808  *
    1809  * Most of the `$userdata` array fields have filters associated with the values. Exceptions are
    1810  * 'ID', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl',
    1811  * 'user_registered', and 'role'. The filters have the prefix 'pre_user_' followed by the field
    1812  * name. An example using 'description' would have the filter called, 'pre_user_description' that
    1813  * can be hooked into.
    1814  *
    1815  * @since 2.0.0
    1816  * @since 3.6.0 The `aim`, `jabber`, and `yim` fields were removed as default user contact
    1817  *              methods for new installs. See wp_get_user_contact_methods().
    1818  *
    1819  * @global wpdb $wpdb WordPress database object for queries.
    1820  *
    1821  * @param array|object|WP_User $userdata {
    1822  *     An array, object, or WP_User object of user data arguments.
    1823  *
    1824  *     @type int         $ID                   User ID. If supplied, the user will be updated.
    1825  *     @type string      $user_pass            The plain-text user password.
    1826  *     @type string      $user_login           The user's login username.
    1827  *     @type string      $user_nicename        The URL-friendly user name.
    1828  *     @type string      $user_url             The user URL.
    1829  *     @type string      $user_email           The user email address.
    1830  *     @type string      $display_name         The user's display name.
    1831  *                                             Default is the the user's username.
    1832  *     @type string      $nickname             The user's nickname.
    1833  *                                             Default is the the user's username.
    1834  *     @type string      $first_name           The user's first name. For new users, will be used
    1835  *                                             to build the first part of the user's display name
    1836  *                                             if `$display_name` is not specified.
    1837  *     @type string      $last_name            The user's last name. For new users, will be used
    1838  *                                             to build the second part of the user's display name
    1839  *                                             if `$display_name` is not specified.
    1840  *     @type string      $description          The user's biographical description.
    1841  *     @type string|bool $rich_editing         Whether to enable the rich-editor for the user.
    1842  *                                             False if not empty.
    1843  *     @type string|bool $comment_shortcuts    Whether to enable comment moderation keyboard
    1844  *                                             shortcuts for the user. Default false.
    1845  *     @type string      $admin_color          Admin color scheme for the user. Default 'fresh'.
    1846  *     @type bool        $use_ssl              Whether the user should always access the admin over
    1847  *                                             https. Default false.
    1848  *     @type string      $user_registered      Date the user registered. Format is 'Y-m-d H:i:s'.
    1849  *     @type string|bool $show_admin_bar_front Whether to display the Admin Bar for the user on the
    1850  *                                             site's frontend. Default true.
    1851  *     @type string      $role                 User's role.
    1852  * }
    1853  * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not
    1854  *                      be created.
    1855  */
    1856 function wp_insert_user( $userdata ) {
    1857     global $wpdb;
    1858 
    1859     if ( $userdata instanceof stdClass ) {
    1860         $userdata = get_object_vars( $userdata );
    1861     } elseif ( $userdata instanceof WP_User ) {
    1862         $userdata = $userdata->to_array();
    1863     }
    1864     // Are we updating or creating?
    1865     if ( ! empty( $userdata['ID'] ) ) {
    1866         $ID = (int) $userdata['ID'];
    1867         $update = true;
    1868         $old_user_data = WP_User::get_data_by( 'id', $ID );
    1869         // hashed in wp_update_user(), plaintext if called directly
    1870         $user_pass = $userdata['user_pass'];
    1871     } else {
    1872         $update = false;
    1873         // Hash the password
    1874         $user_pass = wp_hash_password( $userdata['user_pass'] );
    1875     }
    1876 
    1877     $sanitized_user_login = sanitize_user( $userdata['user_login'], true );
    1878 
    1879     /**
    1880      * Filter a username after it has been sanitized.
    1881      *
    1882      * This filter is called before the user is created or updated.
    1883      *
    1884      * @since 2.0.3
    1885      *
    1886      * @param string $sanitized_user_login Username after it has been sanitized.
    1887      */
    1888     $pre_user_login = apply_filters( 'pre_user_login', $sanitized_user_login );
    1889 
    1890     //Remove any non-printable chars from the login string to see if we have ended up with an empty username
    1891     $user_login = trim( $pre_user_login );
    1892 
    1893     if ( empty( $user_login ) ) {
    1894         return new WP_Error('empty_user_login', __('Cannot create a user with an empty login name.') );
    1895     }
    1896     if ( ! $update && username_exists( $user_login ) ) {
    1897         return new WP_Error( 'existing_user_login', __( 'Sorry, that username already exists!' ) );
    1898     }
    1899 
    1900     // If a nicename is provided, remove unsafe user characters before
    1901     // using it. Otherwise build a nicename from the user_login.
    1902     if ( ! empty( $userdata['user_nicename'] ) ) {
    1903         $user_nicename = sanitize_user( $userdata['user_nicename'], true );
    1904     } else {
    1905         $user_nicename = $user_login;
    1906     }
    1907 
    1908     $user_nicename = sanitize_title( $user_nicename );
    1909 
    1910     // Store values to save in user meta.
    1911     $meta = array();
    1912 
    1913     /**
    1914      * Filter a user's nicename before the user is created or updated.
    1915      *
    1916      * @since 2.0.3
    1917      *
    1918      * @param string $user_nicename The user's nicename.
    1919      */
    1920     $user_nicename = apply_filters( 'pre_user_nicename', $user_nicename );
    1921 
    1922     $raw_user_url = empty( $userdata['user_url'] ) ? '' : $userdata['user_url'];
    1923 
    1924     /**
    1925      * Filter a user's URL before the user is created or updated.
    1926      *
    1927      * @since 2.0.3
    1928      *
    1929      * @param string $raw_user_url The user's URL.
    1930      */
    1931     $user_url = apply_filters( 'pre_user_url', $raw_user_url );
    1932 
    1933     $raw_user_email = empty( $userdata['user_email'] ) ? '' : $userdata['user_email'];
    1934 
    1935     /**
    1936      * Filter a user's email before the user is created or updated.
    1937      *
    1938      * @since 2.0.3
    1939      *
    1940      * @param string $raw_user_email The user's email.
    1941      */
    1942     $user_email = apply_filters( 'pre_user_email', $raw_user_email );
    1943 
    1944     /*
    1945      * If there is no update, just check for `email_exists`. If there is an update,
    1946      * check if current email and new email are the same, or not, and check `email_exists`
    1947      * accordingly.
    1948      */
    1949     if ( ( ! $update || ( ! empty( $old_user_data ) && 0 !== strcasecmp( $user_email, $old_user_data->user_email ) ) )
    1950         && ! defined( 'WP_IMPORTING' )
    1951         && email_exists( $user_email )
    1952     ) {
    1953         return new WP_Error( 'existing_user_email', __( 'Sorry, that email address is already used!' ) );
    1954     }
    1955     $nickname = empty( $userdata['nickname'] ) ? $user_login : $userdata['nickname'];
    1956 
    1957     /**
    1958      * Filter a user's nickname before the user is created or updated.
    1959      *
    1960      * @since 2.0.3
    1961      *
    1962      * @param string $nickname The user's nickname.
    1963      */
    1964     $meta['nickname'] = apply_filters( 'pre_user_nickname', $nickname );
    1965 
    1966     $first_name = empty( $userdata['first_name'] ) ? '' : $userdata['first_name'];
    1967 
    1968     /**
    1969      * Filter a user's first name before the user is created or updated.
    1970      *
    1971      * @since 2.0.3
    1972      *
    1973      * @param string $first_name The user's first name.
    1974      */
    1975     $meta['first_name'] = apply_filters( 'pre_user_first_name', $first_name );
    1976 
    1977     $last_name = empty( $userdata['last_name'] ) ? '' : $userdata['last_name'];
    1978 
    1979     /**
    1980      * Filter a user's last name before the user is created or updated.
    1981      *
    1982      * @since 2.0.3
    1983      *
    1984      * @param string $last_name The user's last name.
    1985      */
    1986     $meta['last_name'] = apply_filters( 'pre_user_last_name', $last_name );
    1987 
    1988     if ( empty( $userdata['display_name'] ) ) {
    1989         if ( $update ) {
    1990             $display_name = $user_login;
    1991         } elseif ( $meta['first_name'] && $meta['last_name'] ) {
    1992             /* translators: 1: first name, 2: last name */
    1993             $display_name = sprintf( _x( '%1$s %2$s', 'Display name based on first name and last name' ), $meta['first_name'], $meta['last_name'] );
    1994         } elseif ( $meta['first_name'] ) {
    1995             $display_name = $meta['first_name'];
    1996         } elseif ( $meta['last_name'] ) {
    1997             $display_name = $meta['last_name'];
    1998         } else {
    1999             $display_name = $user_login;
    2000         }
    2001     } else {
    2002         $display_name = $userdata['display_name'];
    2003     }
    2004 
    2005     /**
    2006      * Filter a user's display name before the user is created or updated.
    2007      *
    2008      * @since 2.0.3
    2009      *
    2010      * @param string $display_name The user's display name.
    2011      */
    2012     $display_name = apply_filters( 'pre_user_display_name', $display_name );
    2013 
    2014     $description = empty( $userdata['description'] ) ? '' : $userdata['description'];
    2015 
    2016     /**
    2017      * Filter a user's description before the user is created or updated.
    2018      *
    2019      * @since 2.0.3
    2020      *
    2021      * @param string $description The user's description.
    2022      */
    2023     $meta['description'] = apply_filters( 'pre_user_description', $description );
    2024 
    2025     $meta['rich_editing'] = empty( $userdata['rich_editing'] ) ? 'true' : $userdata['rich_editing'];
    2026 
    2027     $meta['comment_shortcuts'] = empty( $userdata['comment_shortcuts'] ) || 'false' === $userdata['comment_shortcuts'] ? 'false' : 'true';
    2028 
    2029     $admin_color = empty( $userdata['admin_color'] ) ? 'fresh' : $userdata['admin_color'];
    2030     $meta['admin_color'] = preg_replace( '|[^a-z0-9 _.\-@]|i', '', $admin_color );
    2031 
    2032     $meta['use_ssl'] = empty( $userdata['use_ssl'] ) ? 0 : $userdata['use_ssl'];
    2033 
    2034     $user_registered = empty( $userdata['user_registered'] ) ? gmdate( 'Y-m-d H:i:s' ) : $userdata['user_registered'];
    2035 
    2036     $meta['show_admin_bar_front'] = empty( $userdata['show_admin_bar_front'] ) ? 'true' : $userdata['show_admin_bar_front'];
    2037 
    2038     $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $user_nicename, $user_login));
    2039 
    2040     if ( $user_nicename_check ) {
    2041         $suffix = 2;
    2042         while ($user_nicename_check) {
    2043             $alt_user_nicename = $user_nicename . "-$suffix";
    2044             $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $alt_user_nicename, $user_login));
    2045             $suffix++;
    2046         }
    2047         $user_nicename = $alt_user_nicename;
    2048     }
    2049 
    2050     $compacted = compact( 'user_pass', 'user_email', 'user_url', 'user_nicename', 'display_name', 'user_registered' );
    2051     $data = wp_unslash( $compacted );
    2052 
    2053     if ( $update ) {
    2054         if ( $user_email !== $old_user_data->user_email ) {
    2055             $data['user_activation_key'] = '';
    2056         }
    2057         $wpdb->update( $wpdb->users, $data, compact( 'ID' ) );
    2058         $user_id = (int) $ID;
    2059     } else {
    2060         $wpdb->insert( $wpdb->users, $data + compact( 'user_login' ) );
    2061         $user_id = (int) $wpdb->insert_id;
    2062     }
    2063 
    2064     $user = new WP_User( $user_id );
    2065 
    2066     /**
    2067      * Filter a user's meta values and keys before the user is created or updated.
    2068      *
    2069      * Does not include contact methods. These are added using `wp_get_user_contact_methods( $user )`.
    2070      *
    2071      * @since 4.4.0
    2072      *
    2073      * @param array $meta {
    2074      *     Default meta values and keys for the user.
    2075      *
    2076      *     @type string   $nickname             The user's nickname. Default is the the user's username.
    2077      *     @type string   $first_name           The user's first name.
    2078      *     @type string   $last_name            The user's last name.
    2079      *     @type string   $description          The user's description.
    2080      *     @type bool     $rich_editing         Whether to enable the rich-editor for the user. False if not empty.
    2081      *     @type bool     $comment_shortcuts    Whether to enable keyboard shortcuts for the user. Default false.
    2082      *     @type string   $admin_color          The color scheme for a user's admin screen. Default 'fresh'.
    2083      *     @type int|bool $use_ssl              Whether to force SSL on the user's admin area. 0|false if SSL is
    2084      *                                          not forced.
    2085      *     @type bool     $show_admin_bar_front Whether to show the admin bar on the front end for the user.
    2086      *                                          Default true.
    2087      * }
    2088      * @param WP_User $user User object.
    2089      */
    2090     $meta = apply_filters( 'insert_user_meta', $meta, $user );
    2091 
    2092     // Update user meta.
    2093     foreach ( $meta as $key => $value ) {
    2094         update_user_meta( $user_id, $key, $value );
    2095     }
    2096 
    2097     foreach ( wp_get_user_contact_methods( $user ) as $key => $value ) {
    2098         if ( isset( $userdata[ $key ] ) ) {
    2099             update_user_meta( $user_id, $key, $userdata[ $key ] );
    2100         }
    2101     }
    2102 
    2103     if ( isset( $userdata['role'] ) ) {
    2104         $user->set_role( $userdata['role'] );
    2105     } elseif ( ! $update ) {
    2106         $user->set_role(get_option('default_role'));
    2107     }
    2108     wp_cache_delete( $user_id, 'users' );
    2109     wp_cache_delete( $user_login, 'userlogins' );
    2110 
    2111     if ( $update ) {
    2112         /**
    2113          * Fires immediately after an existing user is updated.
    2114          *
    2115          * @since 2.0.0
    2116          *
    2117          * @param int    $user_id       User ID.
    2118          * @param object $old_user_data Object containing user's data prior to update.
    2119          */
    2120         do_action( 'profile_update', $user_id, $old_user_data );
    2121     } else {
    2122         /**
    2123          * Fires immediately after a new user is registered.
    2124          *
    2125          * @since 1.5.0
    2126          *
    2127          * @param int $user_id User ID.
    2128          */
    2129         do_action( 'user_register', $user_id );
    2130     }
    2131 
    2132     return $user_id;
    2133 }
    2134 
    2135 /**
    2136  * Update a user in the database.
    2137  *
    2138  * It is possible to update a user's password by specifying the 'user_pass'
    2139  * value in the $userdata parameter array.
    2140  *
    2141  * If current user's password is being updated, then the cookies will be
    2142  * cleared.
    2143  *
    2144  * @since 2.0.0
    2145  *
    2146  * @see wp_insert_user() For what fields can be set in $userdata.
    2147  *
    2148  * @param mixed $userdata An array of user data or a user object of type stdClass or WP_User.
    2149  * @return int|WP_Error The updated user's ID or a WP_Error object if the user could not be updated.
    2150  */
    2151 function wp_update_user($userdata) {
    2152     if ( $userdata instanceof stdClass ) {
    2153         $userdata = get_object_vars( $userdata );
    2154     } elseif ( $userdata instanceof WP_User ) {
    2155         $userdata = $userdata->to_array();
    2156     }
    2157 
    2158     $ID = isset( $userdata['ID'] ) ? (int) $userdata['ID'] : 0;
    2159     if ( ! $ID ) {
    2160         return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
    2161     }
    2162 
    2163     // First, get all of the original fields
    2164     $user_obj = get_userdata( $ID );
    2165     if ( ! $user_obj ) {
    2166         return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
    2167     }
    2168 
    2169     $user = $user_obj->to_array();
    2170 
    2171     // Add additional custom fields
    2172     foreach ( _get_additional_user_keys( $user_obj ) as $key ) {
    2173         $user[ $key ] = get_user_meta( $ID, $key, true );
    2174     }
    2175 
    2176     // Escape data pulled from DB.
    2177     $user = add_magic_quotes( $user );
    2178 
    2179     if ( ! empty($userdata['user_pass']) ) {
    2180         // If password is changing, hash it now
    2181         $plaintext_pass = $userdata['user_pass'];
    2182         $userdata['user_pass'] = wp_hash_password( $userdata['user_pass'] );
    2183 
    2184         /**
    2185          * Filter whether to send the password change email.
    2186          *
    2187          * @since 4.3.0
    2188          *
    2189          * @see wp_insert_user() For `$user` and `$userdata` fields.
    2190          *
    2191          * @param bool  $send     Whether to send the email.
    2192          * @param array $user     The original user array.
    2193          * @param array $userdata The updated user array.
    2194          *
    2195          */
    2196         $send_password_change_email = apply_filters( 'send_password_change_email', true, $user, $userdata );
    2197     }
    2198 
    2199     if ( isset( $userdata['user_email'] ) && $user['user_email'] !== $userdata['user_email'] ) {
    2200         /**
    2201          * Filter whether to send the email change email.
    2202          *
    2203          * @since 4.3.0
    2204          *
    2205          * @see wp_insert_user() For `$user` and `$userdata` fields.
    2206          *
    2207          * @param bool  $send     Whether to send the email.
    2208          * @param array $user     The original user array.
    2209          * @param array $userdata The updated user array.
    2210          *
    2211          */
    2212         $send_email_change_email = apply_filters( 'send_email_change_email', true, $user, $userdata );
    2213     }
    2214 
    2215     wp_cache_delete( $user['user_email'], 'useremail' );
    2216 
    2217     // Merge old and new fields with new fields overwriting old ones.
    2218     $userdata = array_merge( $user, $userdata );
    2219     $user_id = wp_insert_user( $userdata );
    2220 
    2221     if ( ! is_wp_error( $user_id ) ) {
    2222 
    2223         $blog_name = wp_specialchars_decode( get_option( 'blogname' ) );
    2224 
    2225         if ( ! empty( $send_password_change_email ) ) {
    2226 
    2227             /* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
    2228             $pass_change_text = __( 'Hi ###USERNAME###,
    2229 
    2230 This notice confirms that your password was changed on ###SITENAME###.
    2231 
    2232 If you did not change your password, please contact the Site Administrator at
    2233 ###ADMIN_EMAIL###
    2234 
    2235 This email has been sent to ###EMAIL###
    2236 
    2237 Regards,
    2238 All at ###SITENAME###
    2239 ###SITEURL###' );
    2240 
    2241             $pass_change_email = array(
    2242                 'to'      => $user['user_email'],
    2243                 'subject' => __( '[%s] Notice of Password Change' ),
    2244                 'message' => $pass_change_text,
    2245                 'headers' => '',
    2246             );
    2247 
    2248             /**
    2249              * Filter the contents of the email sent when the user's password is changed.
    2250              *
    2251              * @since 4.3.0
    2252              *
    2253              * @param array $pass_change_email {
    2254              *            Used to build wp_mail().
    2255              *            @type string $to      The intended recipients. Add emails in a comma separated string.
    2256              *            @type string $subject The subject of the email.
    2257              *            @type string $message The content of the email.
    2258              *                The following strings have a special meaning and will get replaced dynamically:
    2259              *                - ###USERNAME###    The current user's username.
    2260              *                - ###ADMIN_EMAIL### The admin email in case this was unexpected.
    2261              *                - ###EMAIL###       The old email.
    2262              *                - ###SITENAME###    The name of the site.
    2263              *                - ###SITEURL###     The URL to the site.
    2264              *            @type string $headers Headers. Add headers in a newline (\r\n) separated string.
    2265              *        }
    2266              * @param array $user     The original user array.
    2267              * @param array $userdata The updated user array.
    2268              *
    2269              */
    2270             $pass_change_email = apply_filters( 'password_change_email', $pass_change_email, $user, $userdata );
    2271 
    2272             $pass_change_email['message'] = str_replace( '###USERNAME###', $user['user_login'], $pass_change_email['message'] );
    2273             $pass_change_email['message'] = str_replace( '###ADMIN_EMAIL###', get_option( 'admin_email' ), $pass_change_email['message'] );
    2274             $pass_change_email['message'] = str_replace( '###EMAIL###', $user['user_email'], $pass_change_email['message'] );
    2275             $pass_change_email['message'] = str_replace( '###SITENAME###', get_option( 'blogname' ), $pass_change_email['message'] );
    2276             $pass_change_email['message'] = str_replace( '###SITEURL###', get_option( 'siteurl' ), $pass_change_email['message'] );
    2277 
    2278             wp_mail( $pass_change_email['to'], sprintf( $pass_change_email['subject'], $blog_name ), $pass_change_email['message'], $pass_change_email['headers'] );
    2279         }
    2280 
    2281         if ( ! empty( $send_email_change_email ) ) {
    2282             /* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
    2283             $email_change_text = __( 'Hi ###USERNAME###,
    2284 
    2285 This notice confirms that your email was changed on ###SITENAME###.
    2286 
    2287 If you did not change your email, please contact the Site Administrator at
    2288 ###ADMIN_EMAIL###
    2289 
    2290 This email has been sent to ###EMAIL###
    2291 
    2292 Regards,
    2293 All at ###SITENAME###
    2294 ###SITEURL###' );
    2295 
    2296             $email_change_email = array(
    2297                 'to'      => $user['user_email'],
    2298                 'subject' => __( '[%s] Notice of Email Change' ),
    2299                 'message' => $email_change_text,
    2300                 'headers' => '',
    2301             );
    2302 
    2303             /**
    2304              * Filter the contents of the email sent when the user's email is changed.
    2305              *
    2306              * @since 4.3.0
    2307              *
    2308              * @param array $email_change_email {
    2309              *            Used to build wp_mail().
    2310              *            @type string $to      The intended recipients.
    2311              *            @type string $subject The subject of the email.
    2312              *            @type string $message The content of the email.
    2313              *                The following strings have a special meaning and will get replaced dynamically:
    2314              *                - ###USERNAME###    The current user's username.
    2315              *                - ###ADMIN_EMAIL### The admin email in case this was unexpected.
    2316              *                - ###EMAIL###       The old email.
    2317              *                - ###SITENAME###    The name of the site.
    2318              *                - ###SITEURL###     The URL to the site.
    2319              *            @type string $headers Headers.
    2320              *        }
    2321              * @param array $user The original user array.
    2322              * @param array $userdata The updated user array.
    2323              */
    2324             $email_change_email = apply_filters( 'email_change_email', $email_change_email, $user, $userdata );
    2325 
    2326             $email_change_email['message'] = str_replace( '###USERNAME###', $user['user_login'], $email_change_email['message'] );
    2327             $email_change_email['message'] = str_replace( '###ADMIN_EMAIL###', get_option( 'admin_email' ), $email_change_email['message'] );
    2328             $email_change_email['message'] = str_replace( '###EMAIL###', $user['user_email'], $email_change_email['message'] );
    2329             $email_change_email['message'] = str_replace( '###SITENAME###', get_option( 'blogname' ), $email_change_email['message'] );
    2330             $email_change_email['message'] = str_replace( '###SITEURL###', get_option( 'siteurl' ), $email_change_email['message'] );
    2331 
    2332             wp_mail( $email_change_email['to'], sprintf( $email_change_email['subject'], $blog_name ), $email_change_email['message'], $email_change_email['headers'] );
    2333         }
    2334     }
    2335 
    2336     // Update the cookies if the password changed.
    2337     $current_user = wp_get_current_user();
    2338     if ( $current_user->ID == $ID ) {
    2339         if ( isset($plaintext_pass) ) {
    2340             wp_clear_auth_cookie();
    2341 
    2342             // Here we calculate the expiration length of the current auth cookie and compare it to the default expiration.
    2343             // If it's greater than this, then we know the user checked 'Remember Me' when they logged in.
    2344             $logged_in_cookie    = wp_parse_auth_cookie( '', 'logged_in' );
    2345             /** This filter is documented in wp-includes/pluggable.php */
    2346             $default_cookie_life = apply_filters( 'auth_cookie_expiration', ( 2 * DAY_IN_SECONDS ), $ID, false );
    2347             $remember            = ( ( $logged_in_cookie['expiration'] - time() ) > $default_cookie_life );
    2348 
    2349             wp_set_auth_cookie( $ID, $remember );
    2350         }
    2351     }
    2352 
    2353     return $user_id;
    2354 }
    2355 
    2356 /**
    2357  * A simpler way of inserting a user into the database.
    2358  *
    2359  * Creates a new user with just the username, password, and email. For more
    2360  * complex user creation use {@see wp_insert_user()} to specify more information.
    2361  *
    2362  * @since 2.0.0
    2363  * @see wp_insert_user() More complete way to create a new user
    2364  *
    2365  * @param string $username The user's username.
    2366  * @param string $password The user's password.
    2367  * @param string $email    Optional. The user's email. Default empty.
    2368  * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not
    2369  *                      be created.
    2370  */
    2371 function wp_create_user($username, $password, $email = '') {
    2372     $user_login = wp_slash( $username );
    2373     $user_email = wp_slash( $email    );
    2374     $user_pass = $password;
    2375 
    2376     $userdata = compact('user_login', 'user_email', 'user_pass');
    2377     return wp_insert_user($userdata);
    2378 }
    2379 
    2380 /**
    2381  * Returns a list of meta keys to be (maybe) populated in wp_update_user().
    2382  *
    2383  * The list of keys returned via this function are dependent on the presence
    2384  * of those keys in the user meta data to be set.
    2385  *
    2386  * @since 3.3.0
    2387  * @access private
    2388  *
    2389  * @param WP_User $user WP_User instance.
    2390  * @return array List of user keys to be populated in wp_update_user().
    2391  */
    2392 function _get_additional_user_keys( $user ) {
    2393     $keys = array( 'first_name', 'last_name', 'nickname', 'description', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl', 'show_admin_bar_front' );
    2394     return array_merge( $keys, array_keys( wp_get_user_contact_methods( $user ) ) );
    2395 }
    2396 
    2397 /**
    2398  * Set up the user contact methods.
    2399  *
    2400  * Default contact methods were removed in 3.6. A filter dictates contact methods.
    2401  *
    2402  * @since 3.7.0
    2403  *
    2404  * @param WP_User $user Optional. WP_User object.
    2405  * @return array Array of contact methods and their labels.
    2406  */
    2407 function wp_get_user_contact_methods( $user = null ) {
    2408     $methods = array();
    2409     if ( get_site_option( 'initial_db_version' ) < 23588 ) {
    2410         $methods = array(
    2411             'aim'    => __( 'AIM' ),
    2412             'yim'    => __( 'Yahoo IM' ),
    2413             'jabber' => __( 'Jabber / Google Talk' )
    2414         );
    2415     }
    2416 
    2417     /**
    2418      * Filter the user contact methods.
    2419      *
    2420      * @since 2.9.0
    2421      *
    2422      * @param array   $methods Array of contact methods and their labels.
    2423      * @param WP_User $user    WP_User object.
    2424      */
    2425     return apply_filters( 'user_contactmethods', $methods, $user );
    2426 }
    2427 
    2428 /**
    2429  * The old private function for setting up user contact methods.
    2430  *
    2431  * @since 2.9.0
    2432  * @access private
    2433  */
    2434 function _wp_get_user_contactmethods( $user = null ) {
    2435     return wp_get_user_contact_methods( $user );
    2436 }
    2437 
    2438 /**
    2439  * Gets the text suggesting how to create strong passwords.
    2440  *
    2441  * @since 4.1.0
    2442  *
    2443  * @return string The password hint text.
    2444  */
    2445 function wp_get_password_hint() {
    2446     $hint = __( 'Hint: The password should be at least twelve characters long. To make it stronger, use upper and lower case letters, numbers, and symbols like ! " ? $ % ^ &amp; ).' );
    2447 
    2448     /**
    2449      * Filter the text describing the site's password complexity policy.
    2450      *
    2451      * @since 4.1.0
    2452      *
    2453      * @param string $hint The password hint text.
    2454      */
    2455     return apply_filters( 'password_hint', $hint );
    2456 }
    2457 
    2458 /**
    2459  * Retrieves a user row based on password reset key and login
    2460  *
    2461  * A key is considered 'expired' if it exactly matches the value of the
    2462  * user_activation_key field, rather than being matched after going through the
    2463  * hashing process. This field is now hashed; old values are no longer accepted
    2464  * but have a different WP_Error code so good user feedback can be provided.
    2465  *
    2466  * @since 3.1.0
    2467  *
    2468  * @global wpdb         $wpdb      WordPress database object for queries.
    2469  * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
    2470  *
    2471  * @param string $key       Hash to validate sending user's password.
    2472  * @param string $login     The user login.
    2473  * @return WP_User|WP_Error WP_User object on success, WP_Error object for invalid or expired keys.
    2474  */
    2475 function check_password_reset_key($key, $login) {
    2476     global $wpdb, $wp_hasher;
    2477 
    2478     $key = preg_replace('/[^a-z0-9]/i', '', $key);
    2479 
    2480     if ( empty( $key ) || !is_string( $key ) )
    2481         return new WP_Error('invalid_key', __('Invalid key'));
    2482 
    2483     if ( empty($login) || !is_string($login) )
    2484         return new WP_Error('invalid_key', __('Invalid key'));
    2485 
    2486     $row = $wpdb->get_row( $wpdb->prepare( "SELECT ID, user_activation_key FROM $wpdb->users WHERE user_login = %s", $login ) );
    2487     if ( ! $row )
    2488         return new WP_Error('invalid_key', __('Invalid key'));
    2489 
    2490     if ( empty( $wp_hasher ) ) {
    2491         require_once ABSPATH . WPINC . '/class-phpass.php';
    2492         $wp_hasher = new PasswordHash( 8, true );
    2493     }
    2494 
    2495     /**
    2496      * Filter the expiration time of password reset keys.
    2497      *
    2498      * @since 4.3.0
    2499      *
    2500      * @param int $expiration The expiration time in seconds.
    2501      */
    2502     $expiration_duration = apply_filters( 'password_reset_expiration', DAY_IN_SECONDS );
    2503 
    2504     if ( false !== strpos( $row->user_activation_key, ':' ) ) {
    2505         list( $pass_request_time, $pass_key ) = explode( ':', $row->user_activation_key, 2 );
    2506         $expiration_time = $pass_request_time + $expiration_duration;
    2507     } else {
    2508         $pass_key = $row->user_activation_key;
    2509         $expiration_time = false;
    2510     }
    2511 
    2512     $hash_is_correct = $wp_hasher->CheckPassword( $key, $pass_key );
    2513 
    2514     if ( $hash_is_correct && $expiration_time && time() < $expiration_time ) {
    2515         return get_userdata( $row->ID );
    2516     } elseif ( $hash_is_correct && $expiration_time ) {
    2517         // Key has an expiration time that's passed
    2518         return new WP_Error( 'expired_key', __( 'Invalid key' ) );
    2519     }
    2520 
    2521     if ( hash_equals( $row->user_activation_key, $key ) || ( $hash_is_correct && ! $expiration_time ) ) {
    2522         $return = new WP_Error( 'expired_key', __( 'Invalid key' ) );
    2523         $user_id = $row->ID;
    2524 
    2525         /**
    2526          * Filter the return value of check_password_reset_key() when an
    2527          * old-style key is used.
    2528          *
    2529          * @since 3.7.0 Previously plain-text keys were stored in the database.
    2530          * @since 4.3.0 Previously key hashes were stored without an expiration time.
    2531          *
    2532          * @param WP_Error $return  A WP_Error object denoting an expired key.
    2533          *                          Return a WP_User object to validate the key.
    2534          * @param int      $user_id The matched user ID.
    2535          */
    2536         return apply_filters( 'password_reset_key_expired', $return, $user_id );
    2537     }
    2538 
    2539     return new WP_Error( 'invalid_key', __( 'Invalid key' ) );
    2540 }
    2541 
    2542 /**
    2543  * Handles resetting the user's password.
    2544  *
    2545  * @since 2.5.0
    2546  *
    2547  * @param object $user     The user
    2548  * @param string $new_pass New password for the user in plaintext
    2549  */
    2550 function reset_password( $user, $new_pass ) {
    2551     /**
    2552      * Fires before the user's password is reset.
    2553      *
    2554      * @since 1.5.0
    2555      *
    2556      * @param object $user     The user.
    2557      * @param string $new_pass New user password.
    2558      */
    2559     do_action( 'password_reset', $user, $new_pass );
    2560 
    2561     wp_set_password( $new_pass, $user->ID );
    2562     update_user_option( $user->ID, 'default_password_nag', false, true );
    2563 
    2564     wp_password_change_notification( $user );
    2565 }
    2566 
    2567 /**
    2568  * Handles registering a new user.
    2569  *
    2570  * @since 2.5.0
    2571  *
    2572  * @param string $user_login User's username for logging in
    2573  * @param string $user_email User's email address to send password and add
    2574  * @return int|WP_Error Either user's ID or error on failure.
    2575  */
    2576 function register_new_user( $user_login, $user_email ) {
    2577     $errors = new WP_Error();
    2578 
    2579     $sanitized_user_login = sanitize_user( $user_login );
    2580     /**
    2581      * Filter the email address of a user being registered.
    2582      *
    2583      * @since 2.1.0
    2584      *
    2585      * @param string $user_email The email address of the new user.
    2586      */
    2587     $user_email = apply_filters( 'user_registration_email', $user_email );
    2588 
    2589     // Check the username
    2590     if ( $sanitized_user_login == '' ) {
    2591         $errors->add( 'empty_username', __( '<strong>ERROR</strong>: Please enter a username.' ) );
    2592     } elseif ( ! validate_username( $user_login ) ) {
    2593         $errors->add( 'invalid_username', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ) );
    2594         $sanitized_user_login = '';
    2595     } elseif ( username_exists( $sanitized_user_login ) ) {
    2596         $errors->add( 'username_exists', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ) );
    2597     }
    2598 
    2599     // Check the e-mail address
    2600     if ( $user_email == '' ) {
    2601         $errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please type your e-mail address.' ) );
    2602     } elseif ( ! is_email( $user_email ) ) {
    2603         $errors->add( 'invalid_email', __( '<strong>ERROR</strong>: The email address isn&#8217;t correct.' ) );
    2604         $user_email = '';
    2605     } elseif ( email_exists( $user_email ) ) {
    2606         $errors->add( 'email_exists', __( '<strong>ERROR</strong>: This email is already registered, please choose another one.' ) );
    2607     }
    2608 
    2609     /**
    2610      * Fires when submitting registration form data, before the user is created.
    2611      *
    2612      * @since 2.1.0
    2613      *
    2614      * @param string   $sanitized_user_login The submitted username after being sanitized.
    2615      * @param string   $user_email           The submitted email.
    2616      * @param WP_Error $errors               Contains any errors with submitted username and email,
    2617      *                                       e.g., an empty field, an invalid username or email,
    2618      *                                       or an existing username or email.
    2619      */
    2620     do_action( 'register_post', $sanitized_user_login, $user_email, $errors );
    2621 
    2622     /**
    2623      * Filter the errors encountered when a new user is being registered.
    2624      *
    2625      * The filtered WP_Error object may, for example, contain errors for an invalid
    2626      * or existing username or email address. A WP_Error object should always returned,
    2627      * but may or may not contain errors.
    2628      *
    2629      * If any errors are present in $errors, this will abort the user's registration.
    2630      *
    2631      * @since 2.1.0
    2632      *
    2633      * @param WP_Error $errors               A WP_Error object containing any errors encountered
    2634      *                                       during registration.
    2635      * @param string   $sanitized_user_login User's username after it has been sanitized.
    2636      * @param string   $user_email           User's email.
    2637      */
    2638     $errors = apply_filters( 'registration_errors', $errors, $sanitized_user_login, $user_email );
    2639 
    2640     if ( $errors->get_error_code() )
    2641         return $errors;
    2642 
    2643     $user_pass = wp_generate_password( 12, false );
    2644     $user_id = wp_create_user( $sanitized_user_login, $user_pass, $user_email );
    2645     if ( ! $user_id || is_wp_error( $user_id ) ) {
    2646         $errors->add( 'registerfail', sprintf( __( '<strong>ERROR</strong>: Couldn&#8217;t register you&hellip; please contact the <a href="mailto:%s">webmaster</a> !' ), get_option( 'admin_email' ) ) );
    2647         return $errors;
    2648     }
    2649 
    2650     update_user_option( $user_id, 'default_password_nag', true, true ); //Set up the Password change nag.
    2651 
    2652     wp_new_user_notification( $user_id, 'both' );
    2653 
    2654     return $user_id;
    2655 }
    2656 
    2657 /**
    2658  * Retrieve the current session token from the logged_in cookie.
    2659  *
    2660  * @since 4.0.0
    2661  *
    2662  * @return string Token.
    2663  */
    2664 function wp_get_session_token() {
    2665     $cookie = wp_parse_auth_cookie( '', 'logged_in' );
    2666     return ! empty( $cookie['token'] ) ? $cookie['token'] : '';
    2667 }
    2668 
    2669 /**
    2670  * Retrieve a list of sessions for the current user.
    2671  *
    2672  * @since 4.0.0
    2673  * @return array Array of sessions.
    2674  */
    2675 function wp_get_all_sessions() {
    2676     $manager = WP_Session_Tokens::get_instance( get_current_user_id() );
    2677     return $manager->get_all();
    2678 }
    2679 
    2680 /**
    2681  * Remove the current session token from the database.
    2682  *
    2683  * @since 4.0.0
    2684  */
    2685 function wp_destroy_current_session() {
    2686     $token = wp_get_session_token();
    2687     if ( $token ) {
    2688         $manager = WP_Session_Tokens::get_instance( get_current_user_id() );
    2689         $manager->destroy( $token );
    2690     }
    2691 }
    2692 
    2693 /**
    2694  * Remove all but the current session token for the current user for the database.
    2695  *
    2696  * @since 4.0.0
    2697  */
    2698 function wp_destroy_other_sessions() {
    2699     $token = wp_get_session_token();
    2700     if ( $token ) {
    2701         $manager = WP_Session_Tokens::get_instance( get_current_user_id() );
    2702         $manager->destroy_others( $token );
    2703     }
    2704 }
    2705 
    2706 /**
    2707  * Remove all session tokens for the current user from the database.
    2708  *
    2709  * @since 4.0.0
    2710  */
    2711 function wp_destroy_all_sessions() {
    2712     $manager = WP_Session_Tokens::get_instance( get_current_user_id() );
    2713     $manager->destroy_all();
    2714 }
     9require_once( ABSPATH . WPINC . '/user-functions.php' );
     10require_once( ABSPATH . WPINC . '/class-wp-user-query.php' );
Note: See TracChangeset for help on using the changeset viewer.