Changeset 33749
- Timestamp:
- 08/26/2015 04:19:32 AM (9 years ago)
- 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 1 1 <?php 2 /**3 * WordPress User API4 *5 * @package WordPress6 * @subpackage Users7 */8 9 /**10 * Authenticate user with remember capability.11 *12 * The credentials is an array that has 'user_login', 'user_password', and13 * 'remember' indices. If the credentials is not given, then the log in form14 * will be assumed and used if set.15 *16 * The various authentication cookies will be set by this function and will be17 * set for a longer period depending on if the 'remember' credential is set to18 * true.19 *20 * @since 2.5.021 *22 * @global string $auth_secure_cookie23 *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 else41 $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.150 *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.065 *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 time73 * 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_cookie79 $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.098 *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.0110 *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.0145 *146 * @param WP_User|WP_Error $user WP_User or WP_Error object if a previous147 * 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.0165 *166 * @global string $auth_secure_cookie167 *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 else188 $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 a201 * spammer, or if the user's primary blog has been marked as spam.202 *203 * @since 3.7.0204 *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.0214 *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 be230 * validated and parsed.231 *232 * This is a callback for the determine_current_user filter, rather than API.233 *234 * @since 3.9.0235 *236 * @param int|bool $user_id The user ID (or false) as received from the237 * determine_current_user filter.238 * @return int|false User ID if validated, false otherwise. If a user ID from239 * 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.0257 * @since 4.1.0 Added `$post_type` argument.258 * @since 4.3.0 Added `$public_only` argument. Added the ability to pass an array259 * 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.0279 * @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.0294 *295 * @global wpdb $wpdb296 *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 functions327 //328 329 /**330 * Get the current user's ID331 *332 * @since MU333 *334 * @return int The current user's ID335 */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. If347 * the user ID is given, then the user data will be retrieved. The filter for348 * the result, will also pass the original option name and finally the user data349 * 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.0354 *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 specific376 $result = $user->get( $prefix . $option );377 elseif ( $user->has_prop( $option ) ) // User specific and cross-blog378 $result = $user->get( $option );379 else380 $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.0388 *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 for400 * global blog options. If the 'global' parameter is false, which it is by default401 * 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.0406 *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 for430 * global blog options. If the 'global' parameter is false, which it is by default431 * it will prepend the WordPress table prefix to the option name.432 *433 * @since 3.0.0434 *435 * @global wpdb $wpdb WordPress database object for queries.436 *437 * @param int $user_id User ID438 * @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 2 /** 452 3 * WordPress User Query class. 453 4 * 454 5 * @since 3.1.0 6 * @package WordPress 7 * @subpackage Users 455 8 * 456 9 * @see WP_User_Query::prepare_query() for information on accepted arguments. … … 1135 688 } 1136 689 } 1137 1138 /**1139 * Retrieve list of users matching criteria.1140 *1141 * @since 3.1.01142 *1143 * @see WP_User_Query1144 *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.01163 *1164 * @global wpdb $wpdb WordPress database object for queries.1165 *1166 * @param int $user_id User ID1167 * @param bool $all Whether to retrieve all blogs, or only blogs that are not1168 * marked as deleted, archived, or spam.1169 * @return array A list of the user's blogs. An empty array if the user doesn't exist1170 * 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 blogs1178 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 MU1254 *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, including1258 * 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.11267 *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 bool1271 */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.01292 * @link https://codex.wordpress.org/Function_Reference/add_user_meta1293 *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 and1308 * value, will keep from removing duplicate metadata with the same key. It also1309 * allows removing all metadata matching key, if needed.1310 *1311 * @since 3.0.01312 * @link https://codex.wordpress.org/Function_Reference/delete_user_meta1313 *1314 * @param int $user_id User ID1315 * @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.01327 * @link https://codex.wordpress.org/Function_Reference/get_user_meta1328 *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 the1342 * 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.01347 * @link https://codex.wordpress.org/Function_Reference/update_user_meta1348 *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.01368 *1369 * @global wpdb $wpdb1370 *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 // Initialize1378 $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 functions1437 //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.41445 *1446 * @global string $user_login The user username for logging in1447 * @global object $userdata User data.1448 * @global int $user_level The level of the user1449 * @global int $user_ID The ID of the user1450 * @global string $user_email The email address of the user1451 * @global string $user_url The url in the user's profile1452 * @global string $user_identity The display name of the user1453 *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 by1484 * setting the 'echo' argument. The 'include' and 'exclude' arguments do not1485 * need to be used; all users will be displayed in that case. Only one can be1486 * used, either 'include' or 'exclude', but not both.1487 *1488 * The available arguments are as follows:1489 *1490 * @since 2.3.01491 *1492 * @global wpdb $wpdb WordPress database object for queries.1493 * @global int $blog_id1494 *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 no1502 * users were found. Default empty.1503 * @type int|string $option_none_value Value to use for $show_option_non when no users1504 * were found. Default -1.1505 * @type string $hide_if_only_one_author Whether to skip generating the drop-down1506 * 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 descending1510 * 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 empty1519 * 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 or1531 * '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' => -11544 );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.01602 *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'. The1617 * 'display' context is used by default. 'attribute' and 'js' contexts are treated like 'display'1618 * when calling filters.1619 *1620 * @since 2.3.01621 *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 user1653 * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.1654 *1655 * @since 2.9.01656 *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 else1666 $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 user1677 * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.1678 *1679 * @since 2.9.01680 *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 user1697 * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.1698 *1699 * @since 2.9.01700 *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 caches1722 *1723 * @since 3.0.01724 *1725 * @param object $user User object to be cached1726 */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 caches1736 *1737 * @since 3.0.01738 *1739 * @param WP_User|int $user User object or ID to be cleaned from the cache1740 */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.01758 *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.01773 *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.11788 *1789 * @param string $username Username.1790 * @return bool Whether username given is valid1791 */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.11799 *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 are1810 * 'ID', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl',1811 * 'user_registered', and 'role'. The filters have the prefix 'pre_user_' followed by the field1812 * name. An example using 'description' would have the filter called, 'pre_user_description' that1813 * can be hooked into.1814 *1815 * @since 2.0.01816 * @since 3.6.0 The `aim`, `jabber`, and `yim` fields were removed as default user contact1817 * 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 used1835 * to build the first part of the user's display name1836 * if `$display_name` is not specified.1837 * @type string $last_name The user's last name. For new users, will be used1838 * to build the second part of the user's display name1839 * 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 keyboard1844 * 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 over1847 * 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 the1850 * 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 not1854 * 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 directly1870 $user_pass = $userdata['user_pass'];1871 } else {1872 $update = false;1873 // Hash the password1874 $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.31885 *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 username1891 $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 before1901 // 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.31917 *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.31928 *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.31939 *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.31961 *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.31972 *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.31983 *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.32009 *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.32020 *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.02072 *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 is2084 * 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.02116 *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.02126 *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 be2142 * cleared.2143 *2144 * @since 2.0.02145 *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 fields2164 $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 fields2172 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 now2181 $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.02188 *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.02204 *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 at2233 ###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.02252 *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 at2288 ###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.02307 *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 more2360 * complex user creation use {@see wp_insert_user()} to specify more information.2361 *2362 * @since 2.0.02363 * @see wp_insert_user() More complete way to create a new user2364 *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 not2369 * 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 presence2384 * of those keys in the user meta data to be set.2385 *2386 * @since 3.3.02387 * @access private2388 *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.02403 *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.02421 *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.02432 * @access private2433 */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.02442 *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 ! " ? $ % ^ & ).' );2447 2448 /**2449 * Filter the text describing the site's password complexity policy.2450 *2451 * @since 4.1.02452 *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 login2460 *2461 * A key is considered 'expired' if it exactly matches the value of the2462 * user_activation_key field, rather than being matched after going through the2463 * hashing process. This field is now hashed; old values are no longer accepted2464 * but have a different WP_Error code so good user feedback can be provided.2465 *2466 * @since 3.1.02467 *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.02499 *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 passed2518 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 an2527 * 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.02546 *2547 * @param object $user The user2548 * @param string $new_pass New password for the user in plaintext2549 */2550 function reset_password( $user, $new_pass ) {2551 /**2552 * Fires before the user's password is reset.2553 *2554 * @since 1.5.02555 *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.02571 *2572 * @param string $user_login User's username for logging in2573 * @param string $user_email User's email address to send password and add2574 * @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.02584 *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 username2590 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 address2600 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’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.02613 *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 invalid2626 * 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.02632 *2633 * @param WP_Error $errors A WP_Error object containing any errors encountered2634 * 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’t register you… 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.02661 *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.02673 * @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.02684 */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.02697 */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.02710 */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 447 447 $option_name = $wpdb->get_blog_prefix() . $option_name; 448 448 return delete_user_meta( $user_id, $option_name ); 449 }450 451 /**452 * WordPress User Query class.453 *454 * @since 3.1.0455 *456 * @see WP_User_Query::prepare_query() for information on accepted arguments.457 */458 class WP_User_Query {459 460 /**461 * Query vars, after parsing462 *463 * @since 3.5.0464 * @access public465 * @var array466 */467 public $query_vars = array();468 469 /**470 * List of found user ids471 *472 * @since 3.1.0473 * @access private474 * @var array475 */476 private $results;477 478 /**479 * Total number of found users for the current query480 *481 * @since 3.1.0482 * @access private483 * @var int484 */485 private $total_users = 0;486 487 /**488 * Metadata query container.489 *490 * @since 4.2.0491 * @access public492 * @var object WP_Meta_Query493 */494 public $meta_query = false;495 496 private $compat_fields = array( 'results', 'total_users' );497 498 // SQL clauses499 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.0509 *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.0523 * @since 4.2.0 Added 'meta_value_num' support for `$orderby` parameter. Added multi-dimensional array syntax524 * for `$orderby` parameter.525 * @since 4.3.0 Added 'has_published_posts' parameter.526 * @access public527 *528 * @global wpdb $wpdb529 * @global int $blog_id530 *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 which546 * 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 as551 * keys and orders ('ASC' or 'DESC') as values. Accepted values are552 * '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 of556 * `$meta_key`, or an array key of `$meta_query`. To use557 * 'meta_value' or 'meta_value_num', `$meta_key` must be also be558 * defined. Default 'user_login'.559 * @type string $order Designates ascending or descending order of users. Order values560 * passed as part of an `$orderby` array take precedence over this561 * parameter. Accepts 'ASC', 'DESC'. Default 'ASC'.562 * @type int $offset Number of users to offset in retrieved results. Can be used in563 * conjunction with pagination. Default 0.564 * @type int $number Number of users to limit the query for. Can be used in565 * 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 pagination568 * 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 array571 * of fields. Accepts 'ID', 'display_name', 'login', 'nicename',572 * 'email', 'url', 'registered'. Use 'all' for all fields and573 * '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 have577 * published posts in those post types. `true` is an alias for all578 * 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, not611 * yet passed into SQL.612 *613 * @since 4.0.0614 *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 query660 }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 // sorting719 $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 // limit765 if ( isset( $qv['number'] ) && $qv['number'] ) {766 if ( $qv['offset'] )767 $this->query_limit = $wpdb->prepare("LIMIT %d, %d", $qv['offset'], $qv['number']);768 else769 $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 else786 $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 else801 $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.0811 *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 before838 * the query is executed.839 *840 * The passed WP_User_Query object contains SQL parts formed841 * from parsing the given query.842 *843 * @since 3.1.0844 *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.0855 *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.0875 *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.0905 * @access public906 *907 * @param string $query_var Query variable key.908 * @return mixed909 */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.0921 * @access public922 *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 columns932 *933 * @access protected934 * @since 3.1.0935 *936 * @global wpdb $wpdb937 *938 * @param string $string939 * @param array $cols940 * @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 string943 */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.0967 * @access public968 *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.0979 * @access public980 *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.0991 * @access protected992 *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 JOIN1012 $where = get_posts_by_author_sql( 'post' );1013 $this->query_from .= " LEFT OUTER JOIN (1014 SELECT post_author, COUNT(*) as post_count1015 FROM $wpdb->posts1016 $where1017 GROUP BY post_author1018 ) 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.01043 * @access protected1044 *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.01064 * @access public1065 *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.01079 * @access public1080 *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.01095 * @access public1096 *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.01110 * @access public1111 *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.01124 * @access public1125 *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 449 } 1137 450 -
trunk/src/wp-includes/user.php
r33725 r33749 7 7 */ 8 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 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 ! " ? $ % ^ & ).' ); 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’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’t register you… 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 } 9 require_once( ABSPATH . WPINC . '/user-functions.php' ); 10 require_once( ABSPATH . WPINC . '/class-wp-user-query.php' );
Note: See TracChangeset
for help on using the changeset viewer.