wp/wp-includes/user.php
changeset 9 177826044cd9
parent 7 cf61fcea0001
child 16 a86126ab1dd4
equal deleted inserted replaced
8:c7c34916027a 9:177826044cd9
    29  * @param array       $credentials   Optional. User info in order to sign on.
    29  * @param array       $credentials   Optional. User info in order to sign on.
    30  * @param string|bool $secure_cookie Optional. Whether to use secure cookie.
    30  * @param string|bool $secure_cookie Optional. Whether to use secure cookie.
    31  * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
    31  * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
    32  */
    32  */
    33 function wp_signon( $credentials = array(), $secure_cookie = '' ) {
    33 function wp_signon( $credentials = array(), $secure_cookie = '' ) {
    34 	if ( empty($credentials) ) {
    34 	if ( empty( $credentials ) ) {
    35 		$credentials = array(); // Back-compat for plugins passing an empty string.
    35 		$credentials = array(); // Back-compat for plugins passing an empty string.
    36 
    36 
    37 		if ( ! empty($_POST['log']) )
    37 		if ( ! empty( $_POST['log'] ) ) {
    38 			$credentials['user_login'] = $_POST['log'];
    38 			$credentials['user_login'] = $_POST['log'];
    39 		if ( ! empty($_POST['pwd']) )
    39 		}
       
    40 		if ( ! empty( $_POST['pwd'] ) ) {
    40 			$credentials['user_password'] = $_POST['pwd'];
    41 			$credentials['user_password'] = $_POST['pwd'];
    41 		if ( ! empty($_POST['rememberme']) )
    42 		}
       
    43 		if ( ! empty( $_POST['rememberme'] ) ) {
    42 			$credentials['remember'] = $_POST['rememberme'];
    44 			$credentials['remember'] = $_POST['rememberme'];
    43 	}
    45 		}
    44 
    46 	}
    45 	if ( !empty($credentials['remember']) )
    47 
       
    48 	if ( ! empty( $credentials['remember'] ) ) {
    46 		$credentials['remember'] = true;
    49 		$credentials['remember'] = true;
    47 	else
    50 	} else {
    48 		$credentials['remember'] = false;
    51 		$credentials['remember'] = false;
       
    52 	}
    49 
    53 
    50 	/**
    54 	/**
    51 	 * Fires before the user is authenticated.
    55 	 * Fires before the user is authenticated.
    52 	 *
    56 	 *
    53 	 * The variables passed to the callbacks are passed by reference,
    57 	 * The variables passed to the callbacks are passed by reference,
    60 	 * @param string $user_login    Username (passed by reference).
    64 	 * @param string $user_login    Username (passed by reference).
    61 	 * @param string $user_password User password (passed by reference).
    65 	 * @param string $user_password User password (passed by reference).
    62 	 */
    66 	 */
    63 	do_action_ref_array( 'wp_authenticate', array( &$credentials['user_login'], &$credentials['user_password'] ) );
    67 	do_action_ref_array( 'wp_authenticate', array( &$credentials['user_login'], &$credentials['user_password'] ) );
    64 
    68 
    65 	if ( '' === $secure_cookie )
    69 	if ( '' === $secure_cookie ) {
    66 		$secure_cookie = is_ssl();
    70 		$secure_cookie = is_ssl();
       
    71 	}
    67 
    72 
    68 	/**
    73 	/**
    69 	 * Filters whether to use a secure sign-on cookie.
    74 	 * Filters whether to use a secure sign-on cookie.
    70 	 *
    75 	 *
    71 	 * @since 3.1.0
    76 	 * @since 3.1.0
    72 	 *
    77 	 *
    73 	 * @param bool  $secure_cookie Whether to use a secure sign-on cookie.
    78 	 * @param bool  $secure_cookie Whether to use a secure sign-on cookie.
    74 	 * @param array $credentials {
    79 	 * @param array $credentials {
    75  	 *     Array of entered sign-on data.
    80 	 *     Array of entered sign-on data.
    76  	 *
    81 	 *
    77  	 *     @type string $user_login    Username.
    82 	 *     @type string $user_login    Username.
    78  	 *     @type string $user_password Password entered.
    83 	 *     @type string $user_password Password entered.
    79 	 *     @type bool   $remember      Whether to 'remember' the user. Increases the time
    84 	 *     @type bool   $remember      Whether to 'remember' the user. Increases the time
    80 	 *                                 that the cookie will be kept. Default false.
    85 	 *                                 that the cookie will be kept. Default false.
    81  	 * }
    86 	 * }
    82 	 */
    87 	 */
    83 	$secure_cookie = apply_filters( 'secure_signon_cookie', $secure_cookie, $credentials );
    88 	$secure_cookie = apply_filters( 'secure_signon_cookie', $secure_cookie, $credentials );
    84 
    89 
    85 	global $auth_secure_cookie; // XXX ugly hack to pass this to wp_authenticate_cookie
    90 	global $auth_secure_cookie; // XXX ugly hack to pass this to wp_authenticate_cookie
    86 	$auth_secure_cookie = $secure_cookie;
    91 	$auth_secure_cookie = $secure_cookie;
    87 
    92 
    88 	add_filter('authenticate', 'wp_authenticate_cookie', 30, 3);
    93 	add_filter( 'authenticate', 'wp_authenticate_cookie', 30, 3 );
    89 
    94 
    90 	$user = wp_authenticate($credentials['user_login'], $credentials['user_password']);
    95 	$user = wp_authenticate( $credentials['user_login'], $credentials['user_password'] );
    91 
    96 
    92 	if ( is_wp_error($user) ) {
    97 	if ( is_wp_error( $user ) ) {
    93 		if ( $user->get_error_codes() == array('empty_username', 'empty_password') ) {
       
    94 			$user = new WP_Error('', '');
       
    95 		}
       
    96 
       
    97 		return $user;
    98 		return $user;
    98 	}
    99 	}
    99 
   100 
   100 	wp_set_auth_cookie($user->ID, $credentials['remember'], $secure_cookie);
   101 	wp_set_auth_cookie( $user->ID, $credentials['remember'], $secure_cookie );
   101 	/**
   102 	/**
   102 	 * Fires after the user has successfully logged in.
   103 	 * Fires after the user has successfully logged in.
   103 	 *
   104 	 *
   104 	 * @since 1.5.0
   105 	 * @since 1.5.0
   105 	 *
   106 	 *
   118  * @param WP_User|WP_Error|null $user     WP_User or WP_Error object from a previous callback. Default null.
   119  * @param WP_User|WP_Error|null $user     WP_User or WP_Error object from a previous callback. Default null.
   119  * @param string                $username Username for authentication.
   120  * @param string                $username Username for authentication.
   120  * @param string                $password Password for authentication.
   121  * @param string                $password Password for authentication.
   121  * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
   122  * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
   122  */
   123  */
   123 function wp_authenticate_username_password($user, $username, $password) {
   124 function wp_authenticate_username_password( $user, $username, $password ) {
   124 	if ( $user instanceof WP_User ) {
   125 	if ( $user instanceof WP_User ) {
   125 		return $user;
   126 		return $user;
   126 	}
   127 	}
   127 
   128 
   128 	if ( empty($username) || empty($password) ) {
   129 	if ( empty( $username ) || empty( $password ) ) {
   129 		if ( is_wp_error( $user ) )
   130 		if ( is_wp_error( $user ) ) {
   130 			return $user;
   131 			return $user;
       
   132 		}
   131 
   133 
   132 		$error = new WP_Error();
   134 		$error = new WP_Error();
   133 
   135 
   134 		if ( empty($username) )
   136 		if ( empty( $username ) ) {
   135 			$error->add('empty_username', __('<strong>ERROR</strong>: The username field is empty.'));
   137 			$error->add( 'empty_username', __( '<strong>ERROR</strong>: The username field is empty.' ) );
   136 
   138 		}
   137 		if ( empty($password) )
   139 
   138 			$error->add('empty_password', __('<strong>ERROR</strong>: The password field is empty.'));
   140 		if ( empty( $password ) ) {
       
   141 			$error->add( 'empty_password', __( '<strong>ERROR</strong>: The password field is empty.' ) );
       
   142 		}
   139 
   143 
   140 		return $error;
   144 		return $error;
   141 	}
   145 	}
   142 
   146 
   143 	$user = get_user_by('login', $username);
   147 	$user = get_user_by( 'login', $username );
   144 
   148 
   145 	if ( !$user ) {
   149 	if ( ! $user ) {
   146 		return new WP_Error( 'invalid_username',
   150 		return new WP_Error(
       
   151 			'invalid_username',
   147 			__( '<strong>ERROR</strong>: Invalid username.' ) .
   152 			__( '<strong>ERROR</strong>: Invalid username.' ) .
   148 			' <a href="' . wp_lostpassword_url() . '">' .
   153 			' <a href="' . wp_lostpassword_url() . '">' .
   149 			__( 'Lost your password?' ) .
   154 			__( 'Lost your password?' ) .
   150 			'</a>'
   155 			'</a>'
   151 		);
   156 		);
   159 	 * @param WP_User|WP_Error $user     WP_User or WP_Error object if a previous
   164 	 * @param WP_User|WP_Error $user     WP_User or WP_Error object if a previous
   160 	 *                                   callback failed authentication.
   165 	 *                                   callback failed authentication.
   161 	 * @param string           $password Password to check against the user.
   166 	 * @param string           $password Password to check against the user.
   162 	 */
   167 	 */
   163 	$user = apply_filters( 'wp_authenticate_user', $user, $password );
   168 	$user = apply_filters( 'wp_authenticate_user', $user, $password );
   164 	if ( is_wp_error($user) )
   169 	if ( is_wp_error( $user ) ) {
   165 		return $user;
   170 		return $user;
       
   171 	}
   166 
   172 
   167 	if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
   173 	if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
   168 		return new WP_Error( 'incorrect_password',
   174 		return new WP_Error(
       
   175 			'incorrect_password',
   169 			sprintf(
   176 			sprintf(
   170 				/* translators: %s: user name */
   177 				/* translators: %s: user name */
   171 				__( '<strong>ERROR</strong>: The password you entered for the username %s is incorrect.' ),
   178 				__( '<strong>ERROR</strong>: The password you entered for the username %s is incorrect.' ),
   172 				'<strong>' . $username . '</strong>'
   179 				'<strong>' . $username . '</strong>'
   173 			) .
   180 			) .
   219 	}
   226 	}
   220 
   227 
   221 	$user = get_user_by( 'email', $email );
   228 	$user = get_user_by( 'email', $email );
   222 
   229 
   223 	if ( ! $user ) {
   230 	if ( ! $user ) {
   224 		return new WP_Error( 'invalid_email',
   231 		return new WP_Error(
       
   232 			'invalid_email',
   225 			__( '<strong>ERROR</strong>: Invalid email address.' ) .
   233 			__( '<strong>ERROR</strong>: Invalid email address.' ) .
   226 			' <a href="' . wp_lostpassword_url() . '">' .
   234 			' <a href="' . wp_lostpassword_url() . '">' .
   227 			__( 'Lost your password?' ) .
   235 			__( 'Lost your password?' ) .
   228 			'</a>'
   236 			'</a>'
   229 		);
   237 		);
   235 	if ( is_wp_error( $user ) ) {
   243 	if ( is_wp_error( $user ) ) {
   236 		return $user;
   244 		return $user;
   237 	}
   245 	}
   238 
   246 
   239 	if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
   247 	if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
   240 		return new WP_Error( 'incorrect_password',
   248 		return new WP_Error(
       
   249 			'incorrect_password',
   241 			sprintf(
   250 			sprintf(
   242 				/* translators: %s: email address */
   251 				/* translators: %s: email address */
   243 				__( '<strong>ERROR</strong>: The password you entered for the email address %s is incorrect.' ),
   252 				__( '<strong>ERROR</strong>: The password you entered for the email address %s is incorrect.' ),
   244 				'<strong>' . $email . '</strong>'
   253 				'<strong>' . $email . '</strong>'
   245 			) .
   254 			) .
   262  * @param WP_User|WP_Error|null $user     WP_User or WP_Error object from a previous callback. Default null.
   271  * @param WP_User|WP_Error|null $user     WP_User or WP_Error object from a previous callback. Default null.
   263  * @param string                $username Username. If not empty, cancels the cookie authentication.
   272  * @param string                $username Username. If not empty, cancels the cookie authentication.
   264  * @param string                $password Password. If not empty, cancels the cookie authentication.
   273  * @param string                $password Password. If not empty, cancels the cookie authentication.
   265  * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
   274  * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
   266  */
   275  */
   267 function wp_authenticate_cookie($user, $username, $password) {
   276 function wp_authenticate_cookie( $user, $username, $password ) {
   268 	if ( $user instanceof WP_User ) {
   277 	if ( $user instanceof WP_User ) {
   269 		return $user;
   278 		return $user;
   270 	}
   279 	}
   271 
   280 
   272 	if ( empty($username) && empty($password) ) {
   281 	if ( empty( $username ) && empty( $password ) ) {
   273 		$user_id = wp_validate_auth_cookie();
   282 		$user_id = wp_validate_auth_cookie();
   274 		if ( $user_id )
   283 		if ( $user_id ) {
   275 			return new WP_User($user_id);
   284 			return new WP_User( $user_id );
       
   285 		}
   276 
   286 
   277 		global $auth_secure_cookie;
   287 		global $auth_secure_cookie;
   278 
   288 
   279 		if ( $auth_secure_cookie )
   289 		if ( $auth_secure_cookie ) {
   280 			$auth_cookie = SECURE_AUTH_COOKIE;
   290 			$auth_cookie = SECURE_AUTH_COOKIE;
   281 		else
   291 		} else {
   282 			$auth_cookie = AUTH_COOKIE;
   292 			$auth_cookie = AUTH_COOKIE;
   283 
   293 		}
   284 		if ( !empty($_COOKIE[$auth_cookie]) )
   294 
   285 			return new WP_Error('expired_session', __('Please log in again.'));
   295 		if ( ! empty( $_COOKIE[ $auth_cookie ] ) ) {
       
   296 			return new WP_Error( 'expired_session', __( 'Please log in again.' ) );
       
   297 		}
   286 
   298 
   287 		// If the cookie is not set, be silent.
   299 		// If the cookie is not set, be silent.
   288 	}
   300 	}
   289 
   301 
   290 	return $user;
   302 	return $user;
   309 		 * @param bool    $spammed Whether the user is considered a spammer.
   321 		 * @param bool    $spammed Whether the user is considered a spammer.
   310 		 * @param WP_User $user    User to check against.
   322 		 * @param WP_User $user    User to check against.
   311 		 */
   323 		 */
   312 		$spammed = apply_filters( 'check_is_user_spammed', is_user_spammy( $user ), $user );
   324 		$spammed = apply_filters( 'check_is_user_spammed', is_user_spammy( $user ), $user );
   313 
   325 
   314 		if ( $spammed )
   326 		if ( $spammed ) {
   315 			return new WP_Error( 'spammer_account', __( '<strong>ERROR</strong>: Your account has been marked as a spammer.' ) );
   327 			return new WP_Error( 'spammer_account', __( '<strong>ERROR</strong>: Your account has been marked as a spammer.' ) );
       
   328 		}
   316 	}
   329 	}
   317 	return $user;
   330 	return $user;
   318 }
   331 }
   319 
   332 
   320 /**
   333 /**
   335 function wp_validate_logged_in_cookie( $user_id ) {
   348 function wp_validate_logged_in_cookie( $user_id ) {
   336 	if ( $user_id ) {
   349 	if ( $user_id ) {
   337 		return $user_id;
   350 		return $user_id;
   338 	}
   351 	}
   339 
   352 
   340 	if ( is_blog_admin() || is_network_admin() || empty( $_COOKIE[LOGGED_IN_COOKIE] ) ) {
   353 	if ( is_blog_admin() || is_network_admin() || empty( $_COOKIE[ LOGGED_IN_COOKIE ] ) ) {
   341 		return false;
   354 		return false;
   342 	}
   355 	}
   343 
   356 
   344 	return wp_validate_auth_cookie( $_COOKIE[LOGGED_IN_COOKIE], 'logged_in' );
   357 	return wp_validate_auth_cookie( $_COOKIE[ LOGGED_IN_COOKIE ], 'logged_in' );
   345 }
   358 }
   346 
   359 
   347 /**
   360 /**
   348  * Number of posts user has written.
   361  * Number of posts user has written.
   349  *
   362  *
   395  */
   408  */
   396 function count_many_users_posts( $users, $post_type = 'post', $public_only = false ) {
   409 function count_many_users_posts( $users, $post_type = 'post', $public_only = false ) {
   397 	global $wpdb;
   410 	global $wpdb;
   398 
   411 
   399 	$count = array();
   412 	$count = array();
   400 	if ( empty( $users ) || ! is_array( $users ) )
   413 	if ( empty( $users ) || ! is_array( $users ) ) {
   401 		return $count;
   414 		return $count;
       
   415 	}
   402 
   416 
   403 	$userlist = implode( ',', array_map( 'absint', $users ) );
   417 	$userlist = implode( ',', array_map( 'absint', $users ) );
   404 	$where = get_posts_by_author_sql( $post_type, true, null, $public_only );
   418 	$where    = get_posts_by_author_sql( $post_type, true, null, $public_only );
   405 
   419 
   406 	$result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author", ARRAY_N );
   420 	$result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author", ARRAY_N );
   407 	foreach ( $result as $row ) {
   421 	foreach ( $result as $row ) {
   408 		$count[ $row[0] ] = $row[1];
   422 		$count[ $row[0] ] = $row[1];
   409 	}
   423 	}
   410 
   424 
   411 	foreach ( $users as $id ) {
   425 	foreach ( $users as $id ) {
   412 		if ( ! isset( $count[ $id ] ) )
   426 		if ( ! isset( $count[ $id ] ) ) {
   413 			$count[ $id ] = 0;
   427 			$count[ $id ] = 0;
       
   428 		}
   414 	}
   429 	}
   415 
   430 
   416 	return $count;
   431 	return $count;
   417 }
   432 }
   418 
   433 
   426  * @since MU (3.0.0)
   441  * @since MU (3.0.0)
   427  *
   442  *
   428  * @return int The current user's ID, or 0 if no user is logged in.
   443  * @return int The current user's ID, or 0 if no user is logged in.
   429  */
   444  */
   430 function get_current_user_id() {
   445 function get_current_user_id() {
   431 	if ( ! function_exists( 'wp_get_current_user' ) )
   446 	if ( ! function_exists( 'wp_get_current_user' ) ) {
   432 		return 0;
   447 		return 0;
       
   448 	}
   433 	$user = wp_get_current_user();
   449 	$user = wp_get_current_user();
   434 	return ( isset( $user->ID ) ? (int) $user->ID : 0 );
   450 	return ( isset( $user->ID ) ? (int) $user->ID : 0 );
   435 }
   451 }
   436 
   452 
   437 /**
   453 /**
   454  * @return mixed User option value on success, false on failure.
   470  * @return mixed User option value on success, false on failure.
   455  */
   471  */
   456 function get_user_option( $option, $user = 0, $deprecated = '' ) {
   472 function get_user_option( $option, $user = 0, $deprecated = '' ) {
   457 	global $wpdb;
   473 	global $wpdb;
   458 
   474 
   459 	if ( !empty( $deprecated ) )
   475 	if ( ! empty( $deprecated ) ) {
   460 		_deprecated_argument( __FUNCTION__, '3.0.0' );
   476 		_deprecated_argument( __FUNCTION__, '3.0.0' );
   461 
   477 	}
   462 	if ( empty( $user ) )
   478 
       
   479 	if ( empty( $user ) ) {
   463 		$user = get_current_user_id();
   480 		$user = get_current_user_id();
   464 
   481 	}
   465 	if ( ! $user = get_userdata( $user ) )
   482 
       
   483 	if ( ! $user = get_userdata( $user ) ) {
   466 		return false;
   484 		return false;
       
   485 	}
   467 
   486 
   468 	$prefix = $wpdb->get_blog_prefix();
   487 	$prefix = $wpdb->get_blog_prefix();
   469 	if ( $user->has_prop( $prefix . $option ) ) // Blog specific
   488 	if ( $user->has_prop( $prefix . $option ) ) { // Blog specific
   470 		$result = $user->get( $prefix . $option );
   489 		$result = $user->get( $prefix . $option );
   471 	elseif ( $user->has_prop( $option ) ) // User specific and cross-blog
   490 	} elseif ( $user->has_prop( $option ) ) { // User specific and cross-blog
   472 		$result = $user->get( $option );
   491 		$result = $user->get( $option );
   473 	else
   492 	} else {
   474 		$result = false;
   493 		$result = false;
       
   494 	}
   475 
   495 
   476 	/**
   496 	/**
   477 	 * Filters a specific user option value.
   497 	 * Filters a specific user option value.
   478 	 *
   498 	 *
   479 	 * The dynamic portion of the hook name, `$option`, refers to the user option name.
   499 	 * The dynamic portion of the hook name, `$option`, refers to the user option name.
   509  *                  false on failure.
   529  *                  false on failure.
   510  */
   530  */
   511 function update_user_option( $user_id, $option_name, $newvalue, $global = false ) {
   531 function update_user_option( $user_id, $option_name, $newvalue, $global = false ) {
   512 	global $wpdb;
   532 	global $wpdb;
   513 
   533 
   514 	if ( !$global )
   534 	if ( ! $global ) {
   515 		$option_name = $wpdb->get_blog_prefix() . $option_name;
   535 		$option_name = $wpdb->get_blog_prefix() . $option_name;
       
   536 	}
   516 
   537 
   517 	return update_user_meta( $user_id, $option_name, $newvalue );
   538 	return update_user_meta( $user_id, $option_name, $newvalue );
   518 }
   539 }
   519 
   540 
   520 /**
   541 /**
   535  * @return bool True on success, false on failure.
   556  * @return bool True on success, false on failure.
   536  */
   557  */
   537 function delete_user_option( $user_id, $option_name, $global = false ) {
   558 function delete_user_option( $user_id, $option_name, $global = false ) {
   538 	global $wpdb;
   559 	global $wpdb;
   539 
   560 
   540 	if ( !$global )
   561 	if ( ! $global ) {
   541 		$option_name = $wpdb->get_blog_prefix() . $option_name;
   562 		$option_name = $wpdb->get_blog_prefix() . $option_name;
       
   563 	}
   542 	return delete_user_meta( $user_id, $option_name );
   564 	return delete_user_meta( $user_id, $option_name );
   543 }
   565 }
   544 
   566 
   545 /**
   567 /**
   546  * Retrieve list of users matching criteria.
   568  * Retrieve list of users matching criteria.
   553  *                    for more information on accepted arguments.
   575  *                    for more information on accepted arguments.
   554  * @return array List of users.
   576  * @return array List of users.
   555  */
   577  */
   556 function get_users( $args = array() ) {
   578 function get_users( $args = array() ) {
   557 
   579 
   558 	$args = wp_parse_args( $args );
   580 	$args                = wp_parse_args( $args );
   559 	$args['count_total'] = false;
   581 	$args['count_total'] = false;
   560 
   582 
   561 	$user_search = new WP_User_Query($args);
   583 	$user_search = new WP_User_Query( $args );
   562 
   584 
   563 	return (array) $user_search->get_results();
   585 	return (array) $user_search->get_results();
   564 }
   586 }
   565 
   587 
   566 /**
   588 /**
   567  * Get the sites a user belongs to.
   589  * Get the sites a user belongs to.
   568  *
   590  *
   569  * @since 3.0.0
   591  * @since 3.0.0
   570  * @since 4.7.0 Converted to use get_sites().
   592  * @since 4.7.0 Converted to use `get_sites()`.
   571  *
   593  *
   572  * @global wpdb $wpdb WordPress database abstraction object.
   594  * @global wpdb $wpdb WordPress database abstraction object.
   573  *
   595  *
   574  * @param int  $user_id User ID
   596  * @param int  $user_id User ID
   575  * @param bool $all     Whether to retrieve all sites, or only sites that are not
   597  * @param bool $all     Whether to retrieve all sites, or only sites that are not
   581 	global $wpdb;
   603 	global $wpdb;
   582 
   604 
   583 	$user_id = (int) $user_id;
   605 	$user_id = (int) $user_id;
   584 
   606 
   585 	// Logged out users can't have sites
   607 	// Logged out users can't have sites
   586 	if ( empty( $user_id ) )
   608 	if ( empty( $user_id ) ) {
   587 		return array();
   609 		return array();
       
   610 	}
   588 
   611 
   589 	/**
   612 	/**
   590 	 * Filters the list of a user's sites before it is populated.
   613 	 * Filters the list of a user's sites before it is populated.
   591 	 *
   614 	 *
   592 	 * Passing a non-null value to the filter will effectively short circuit
   615 	 * Passing a non-null value to the filter will effectively short circuit
   604 	if ( null !== $sites ) {
   627 	if ( null !== $sites ) {
   605 		return $sites;
   628 		return $sites;
   606 	}
   629 	}
   607 
   630 
   608 	$keys = get_user_meta( $user_id );
   631 	$keys = get_user_meta( $user_id );
   609 	if ( empty( $keys ) )
   632 	if ( empty( $keys ) ) {
   610 		return array();
   633 		return array();
       
   634 	}
   611 
   635 
   612 	if ( ! is_multisite() ) {
   636 	if ( ! is_multisite() ) {
   613 		$site_id = get_current_blog_id();
   637 		$site_id                        = get_current_blog_id();
   614 		$sites = array( $site_id => new stdClass );
   638 		$sites                          = array( $site_id => new stdClass );
   615 		$sites[ $site_id ]->userblog_id = $site_id;
   639 		$sites[ $site_id ]->userblog_id = $site_id;
   616 		$sites[ $site_id ]->blogname = get_option('blogname');
   640 		$sites[ $site_id ]->blogname    = get_option( 'blogname' );
   617 		$sites[ $site_id ]->domain = '';
   641 		$sites[ $site_id ]->domain      = '';
   618 		$sites[ $site_id ]->path = '';
   642 		$sites[ $site_id ]->path        = '';
   619 		$sites[ $site_id ]->site_id = 1;
   643 		$sites[ $site_id ]->site_id     = 1;
   620 		$sites[ $site_id ]->siteurl = get_option('siteurl');
   644 		$sites[ $site_id ]->siteurl     = get_option( 'siteurl' );
   621 		$sites[ $site_id ]->archived = 0;
   645 		$sites[ $site_id ]->archived    = 0;
   622 		$sites[ $site_id ]->spam = 0;
   646 		$sites[ $site_id ]->spam        = 0;
   623 		$sites[ $site_id ]->deleted = 0;
   647 		$sites[ $site_id ]->deleted     = 0;
   624 		return $sites;
   648 		return $sites;
   625 	}
   649 	}
   626 
   650 
   627 	$site_ids = array();
   651 	$site_ids = array();
   628 
   652 
   632 	}
   656 	}
   633 
   657 
   634 	$keys = array_keys( $keys );
   658 	$keys = array_keys( $keys );
   635 
   659 
   636 	foreach ( $keys as $key ) {
   660 	foreach ( $keys as $key ) {
   637 		if ( 'capabilities' !== substr( $key, -12 ) )
   661 		if ( 'capabilities' !== substr( $key, -12 ) ) {
   638 			continue;
   662 			continue;
   639 		if ( $wpdb->base_prefix && 0 !== strpos( $key, $wpdb->base_prefix ) )
   663 		}
       
   664 		if ( $wpdb->base_prefix && 0 !== strpos( $key, $wpdb->base_prefix ) ) {
   640 			continue;
   665 			continue;
       
   666 		}
   641 		$site_id = str_replace( array( $wpdb->base_prefix, '_capabilities' ), '', $key );
   667 		$site_id = str_replace( array( $wpdb->base_prefix, '_capabilities' ), '', $key );
   642 		if ( ! is_numeric( $site_id ) )
   668 		if ( ! is_numeric( $site_id ) ) {
   643 			continue;
   669 			continue;
       
   670 		}
   644 
   671 
   645 		$site_ids[] = (int) $site_id;
   672 		$site_ids[] = (int) $site_id;
   646 	}
   673 	}
   647 
   674 
   648 	$sites = array();
   675 	$sites = array();
   649 
   676 
   650 	if ( ! empty( $site_ids ) ) {
   677 	if ( ! empty( $site_ids ) ) {
   651 		$args = array(
   678 		$args = array(
   652 			'number'   => '',
   679 			'number'                 => '',
   653 			'site__in' => $site_ids,
   680 			'site__in'               => $site_ids,
       
   681 			'update_site_meta_cache' => false,
   654 		);
   682 		);
   655 		if ( ! $all ) {
   683 		if ( ! $all ) {
   656 			$args['archived'] = 0;
   684 			$args['archived'] = 0;
   657 			$args['spam']     = 0;
   685 			$args['spam']     = 0;
   658 			$args['deleted']  = 0;
   686 			$args['deleted']  = 0;
   764  * @param string $meta_key   Metadata name.
   792  * @param string $meta_key   Metadata name.
   765  * @param mixed  $meta_value Metadata value.
   793  * @param mixed  $meta_value Metadata value.
   766  * @param bool   $unique     Optional. Whether the same key should not be added. Default false.
   794  * @param bool   $unique     Optional. Whether the same key should not be added. Default false.
   767  * @return int|false Meta ID on success, false on failure.
   795  * @return int|false Meta ID on success, false on failure.
   768  */
   796  */
   769 function add_user_meta($user_id, $meta_key, $meta_value, $unique = false) {
   797 function add_user_meta( $user_id, $meta_key, $meta_value, $unique = false ) {
   770 	return add_metadata('user', $user_id, $meta_key, $meta_value, $unique);
   798 	return add_metadata( 'user', $user_id, $meta_key, $meta_value, $unique );
   771 }
   799 }
   772 
   800 
   773 /**
   801 /**
   774  * Remove metadata matching criteria from a user.
   802  * Remove metadata matching criteria from a user.
   775  *
   803  *
   783  * @param int    $user_id    User ID
   811  * @param int    $user_id    User ID
   784  * @param string $meta_key   Metadata name.
   812  * @param string $meta_key   Metadata name.
   785  * @param mixed  $meta_value Optional. Metadata value.
   813  * @param mixed  $meta_value Optional. Metadata value.
   786  * @return bool True on success, false on failure.
   814  * @return bool True on success, false on failure.
   787  */
   815  */
   788 function delete_user_meta($user_id, $meta_key, $meta_value = '') {
   816 function delete_user_meta( $user_id, $meta_key, $meta_value = '' ) {
   789 	return delete_metadata('user', $user_id, $meta_key, $meta_value);
   817 	return delete_metadata( 'user', $user_id, $meta_key, $meta_value );
   790 }
   818 }
   791 
   819 
   792 /**
   820 /**
   793  * Retrieve user meta field for a user.
   821  * Retrieve user meta field for a user.
   794  *
   822  *
   798  * @param int    $user_id User ID.
   826  * @param int    $user_id User ID.
   799  * @param string $key     Optional. The meta key to retrieve. By default, returns data for all keys.
   827  * @param string $key     Optional. The meta key to retrieve. By default, returns data for all keys.
   800  * @param bool   $single  Whether to return a single value.
   828  * @param bool   $single  Whether to return a single value.
   801  * @return mixed Will be an array if $single is false. Will be value of meta data field if $single is true.
   829  * @return mixed Will be an array if $single is false. Will be value of meta data field if $single is true.
   802  */
   830  */
   803 function get_user_meta($user_id, $key = '', $single = false) {
   831 function get_user_meta( $user_id, $key = '', $single = false ) {
   804 	return get_metadata('user', $user_id, $key, $single);
   832 	return get_metadata( 'user', $user_id, $key, $single );
   805 }
   833 }
   806 
   834 
   807 /**
   835 /**
   808  * Update user meta field based on user ID.
   836  * Update user meta field based on user ID.
   809  *
   837  *
   819  * @param string $meta_key   Metadata key.
   847  * @param string $meta_key   Metadata key.
   820  * @param mixed  $meta_value Metadata value.
   848  * @param mixed  $meta_value Metadata value.
   821  * @param mixed  $prev_value Optional. Previous value to check before removing.
   849  * @param mixed  $prev_value Optional. Previous value to check before removing.
   822  * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
   850  * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
   823  */
   851  */
   824 function update_user_meta($user_id, $meta_key, $meta_value, $prev_value = '') {
   852 function update_user_meta( $user_id, $meta_key, $meta_value, $prev_value = '' ) {
   825 	return update_metadata('user', $user_id, $meta_key, $meta_value, $prev_value);
   853 	return update_metadata( 'user', $user_id, $meta_key, $meta_value, $prev_value );
   826 }
   854 }
   827 
   855 
   828 /**
   856 /**
   829  * Count number of users who have each of the user roles.
   857  * Count number of users who have each of the user roles.
   830  *
   858  *
   849 
   877 
   850 	// Initialize
   878 	// Initialize
   851 	if ( ! $site_id ) {
   879 	if ( ! $site_id ) {
   852 		$site_id = get_current_blog_id();
   880 		$site_id = get_current_blog_id();
   853 	}
   881 	}
       
   882 
       
   883 	/**
       
   884 	 * Filter the user count before queries are run. Return a non-null value to cause count_users()
       
   885 	 * to return early.
       
   886 	 *
       
   887 	 * @since 5.1.0
       
   888 	 *
       
   889 	 * @param null|string $result   Default null.
       
   890 	 * @param string      $strategy Optional. The computational strategy to use when counting the users.
       
   891 	 *                              Accepts either 'time' or 'memory'. Default 'time'.
       
   892 	 * @param int|null    $site_id  Optional. The site ID to count users for. Defaults to the current site.
       
   893 	 */
       
   894 	$pre = apply_filters( 'pre_count_users', null, $strategy, $site_id );
       
   895 
       
   896 	if ( null !== $pre ) {
       
   897 		return $pre;
       
   898 	}
       
   899 
   854 	$blog_prefix = $wpdb->get_blog_prefix( $site_id );
   900 	$blog_prefix = $wpdb->get_blog_prefix( $site_id );
   855 	$result = array();
   901 	$result      = array();
   856 
   902 
   857 	if ( 'time' == $strategy ) {
   903 	if ( 'time' == $strategy ) {
   858 		if ( is_multisite() && $site_id != get_current_blog_id() ) {
   904 		if ( is_multisite() && $site_id != get_current_blog_id() ) {
   859 			switch_to_blog( $site_id );
   905 			switch_to_blog( $site_id );
   860 			$avail_roles = wp_roles()->get_names();
   906 			$avail_roles = wp_roles()->get_names();
   864 		}
   910 		}
   865 
   911 
   866 		// Build a CPU-intensive query that will return concise information.
   912 		// Build a CPU-intensive query that will return concise information.
   867 		$select_count = array();
   913 		$select_count = array();
   868 		foreach ( $avail_roles as $this_role => $name ) {
   914 		foreach ( $avail_roles as $this_role => $name ) {
   869 			$select_count[] = $wpdb->prepare( "COUNT(NULLIF(`meta_value` LIKE %s, false))", '%' . $wpdb->esc_like( '"' . $this_role . '"' ) . '%');
   915 			$select_count[] = $wpdb->prepare( 'COUNT(NULLIF(`meta_value` LIKE %s, false))', '%' . $wpdb->esc_like( '"' . $this_role . '"' ) . '%' );
   870 		}
   916 		}
   871 		$select_count[] = "COUNT(NULLIF(`meta_value` = 'a:0:{}', false))";
   917 		$select_count[] = "COUNT(NULLIF(`meta_value` = 'a:0:{}', false))";
   872 		$select_count = implode(', ', $select_count);
   918 		$select_count   = implode( ', ', $select_count );
   873 
   919 
   874 		// Add the meta_value index to the selection list, then run the query.
   920 		// Add the meta_value index to the selection list, then run the query.
   875 		$row = $wpdb->get_row( "
   921 		$row = $wpdb->get_row(
       
   922 			"
   876 			SELECT {$select_count}, COUNT(*)
   923 			SELECT {$select_count}, COUNT(*)
   877 			FROM {$wpdb->usermeta}
   924 			FROM {$wpdb->usermeta}
   878 			INNER JOIN {$wpdb->users} ON user_id = ID
   925 			INNER JOIN {$wpdb->users} ON user_id = ID
   879 			WHERE meta_key = '{$blog_prefix}capabilities'
   926 			WHERE meta_key = '{$blog_prefix}capabilities'
   880 		", ARRAY_N );
   927 		",
       
   928 			ARRAY_N
       
   929 		);
   881 
   930 
   882 		// Run the previous loop again to associate results with role names.
   931 		// Run the previous loop again to associate results with role names.
   883 		$col = 0;
   932 		$col         = 0;
   884 		$role_counts = array();
   933 		$role_counts = array();
   885 		foreach ( $avail_roles as $this_role => $name ) {
   934 		foreach ( $avail_roles as $this_role => $name ) {
   886 			$count = (int) $row[$col++];
   935 			$count = (int) $row[ $col++ ];
   887 			if ($count > 0) {
   936 			if ( $count > 0 ) {
   888 				$role_counts[$this_role] = $count;
   937 				$role_counts[ $this_role ] = $count;
   889 			}
   938 			}
   890 		}
   939 		}
   891 
   940 
   892 		$role_counts['none'] = (int) $row[$col++];
   941 		$role_counts['none'] = (int) $row[ $col++ ];
   893 
   942 
   894 		// Get the meta_value index from the end of the result set.
   943 		// Get the meta_value index from the end of the result set.
   895 		$total_users = (int) $row[$col];
   944 		$total_users = (int) $row[ $col ];
   896 
   945 
   897 		$result['total_users'] = $total_users;
   946 		$result['total_users'] = $total_users;
   898 		$result['avail_roles'] =& $role_counts;
   947 		$result['avail_roles'] =& $role_counts;
   899 	} else {
   948 	} else {
   900 		$avail_roles = array(
   949 		$avail_roles = array(
   901 			'none' => 0,
   950 			'none' => 0,
   902 		);
   951 		);
   903 
   952 
   904 		$users_of_blog = $wpdb->get_col( "
   953 		$users_of_blog = $wpdb->get_col(
       
   954 			"
   905 			SELECT meta_value
   955 			SELECT meta_value
   906 			FROM {$wpdb->usermeta}
   956 			FROM {$wpdb->usermeta}
   907 			INNER JOIN {$wpdb->users} ON user_id = ID
   957 			INNER JOIN {$wpdb->users} ON user_id = ID
   908 			WHERE meta_key = '{$blog_prefix}capabilities'
   958 			WHERE meta_key = '{$blog_prefix}capabilities'
   909 		" );
   959 		"
       
   960 		);
   910 
   961 
   911 		foreach ( $users_of_blog as $caps_meta ) {
   962 		foreach ( $users_of_blog as $caps_meta ) {
   912 			$b_roles = maybe_unserialize($caps_meta);
   963 			$b_roles = maybe_unserialize( $caps_meta );
   913 			if ( ! is_array( $b_roles ) )
   964 			if ( ! is_array( $b_roles ) ) {
   914 				continue;
   965 				continue;
       
   966 			}
   915 			if ( empty( $b_roles ) ) {
   967 			if ( empty( $b_roles ) ) {
   916 				$avail_roles['none']++;
   968 				$avail_roles['none']++;
   917 			}
   969 			}
   918 			foreach ( $b_roles as $b_role => $val ) {
   970 			foreach ( $b_roles as $b_role => $val ) {
   919 				if ( isset($avail_roles[$b_role]) ) {
   971 				if ( isset( $avail_roles[ $b_role ] ) ) {
   920 					$avail_roles[$b_role]++;
   972 					$avail_roles[ $b_role ]++;
   921 				} else {
   973 				} else {
   922 					$avail_roles[$b_role] = 1;
   974 					$avail_roles[ $b_role ] = 1;
   923 				}
   975 				}
   924 			}
   976 			}
   925 		}
   977 		}
   926 
   978 
   927 		$result['total_users'] = count( $users_of_blog );
   979 		$result['total_users'] = count( $users_of_blog );
   948  * @global int     $user_ID       The ID of the user
  1000  * @global int     $user_ID       The ID of the user
   949  * @global string  $user_email    The email address of the user
  1001  * @global string  $user_email    The email address of the user
   950  * @global string  $user_url      The url in the user's profile
  1002  * @global string  $user_url      The url in the user's profile
   951  * @global string  $user_identity The display name of the user
  1003  * @global string  $user_identity The display name of the user
   952  *
  1004  *
   953  * @param int $for_user_id Optional. User ID to set up global data.
  1005  * @param int $for_user_id Optional. User ID to set up global data. Default 0.
   954  */
  1006  */
   955 function setup_userdata($for_user_id = '') {
  1007 function setup_userdata( $for_user_id = 0 ) {
   956 	global $user_login, $userdata, $user_level, $user_ID, $user_email, $user_url, $user_identity;
  1008 	global $user_login, $userdata, $user_level, $user_ID, $user_email, $user_url, $user_identity;
   957 
  1009 
   958 	if ( '' == $for_user_id )
  1010 	if ( ! $for_user_id ) {
   959 		$for_user_id = get_current_user_id();
  1011 		$for_user_id = get_current_user_id();
       
  1012 	}
   960 	$user = get_userdata( $for_user_id );
  1013 	$user = get_userdata( $for_user_id );
   961 
  1014 
   962 	if ( ! $user ) {
  1015 	if ( ! $user ) {
   963 		$user_ID = 0;
  1016 		$user_ID    = 0;
   964 		$user_level = 0;
  1017 		$user_level = 0;
   965 		$userdata = null;
  1018 		$userdata   = null;
   966 		$user_login = $user_email = $user_url = $user_identity = '';
  1019 		$user_login = $user_email = $user_url = $user_identity = '';
   967 		return;
  1020 		return;
   968 	}
  1021 	}
   969 
  1022 
   970 	$user_ID    = (int) $user->ID;
  1023 	$user_ID       = (int) $user->ID;
   971 	$user_level = (int) $user->user_level;
  1024 	$user_level    = (int) $user->user_level;
   972 	$userdata   = $user;
  1025 	$userdata      = $user;
   973 	$user_login = $user->user_login;
  1026 	$user_login    = $user->user_login;
   974 	$user_email = $user->user_email;
  1027 	$user_email    = $user->user_email;
   975 	$user_url   = $user->user_url;
  1028 	$user_url      = $user->user_url;
   976 	$user_identity = $user->display_name;
  1029 	$user_identity = $user->display_name;
   977 }
  1030 }
   978 
  1031 
   979 /**
  1032 /**
   980  * Create dropdown HTML content of users.
  1033  * Create dropdown HTML content of users.
  1039  * }
  1092  * }
  1040  * @return string String of HTML content.
  1093  * @return string String of HTML content.
  1041  */
  1094  */
  1042 function wp_dropdown_users( $args = '' ) {
  1095 function wp_dropdown_users( $args = '' ) {
  1043 	$defaults = array(
  1096 	$defaults = array(
  1044 		'show_option_all' => '', 'show_option_none' => '', 'hide_if_only_one_author' => '',
  1097 		'show_option_all'         => '',
  1045 		'orderby' => 'display_name', 'order' => 'ASC',
  1098 		'show_option_none'        => '',
  1046 		'include' => '', 'exclude' => '', 'multi' => 0,
  1099 		'hide_if_only_one_author' => '',
  1047 		'show' => 'display_name', 'echo' => 1,
  1100 		'orderby'                 => 'display_name',
  1048 		'selected' => 0, 'name' => 'user', 'class' => '', 'id' => '',
  1101 		'order'                   => 'ASC',
  1049 		'blog_id' => get_current_blog_id(), 'who' => '', 'include_selected' => false,
  1102 		'include'                 => '',
  1050 		'option_none_value' => -1,
  1103 		'exclude'                 => '',
  1051 		'role' => '',
  1104 		'multi'                   => 0,
  1052 		'role__in' => array(),
  1105 		'show'                    => 'display_name',
  1053 		'role__not_in' => array(),
  1106 		'echo'                    => 1,
       
  1107 		'selected'                => 0,
       
  1108 		'name'                    => 'user',
       
  1109 		'class'                   => '',
       
  1110 		'id'                      => '',
       
  1111 		'blog_id'                 => get_current_blog_id(),
       
  1112 		'who'                     => '',
       
  1113 		'include_selected'        => false,
       
  1114 		'option_none_value'       => -1,
       
  1115 		'role'                    => '',
       
  1116 		'role__in'                => array(),
       
  1117 		'role__not_in'            => array(),
  1054 	);
  1118 	);
  1055 
  1119 
  1056 	$defaults['selected'] = is_author() ? get_query_var( 'author' ) : 0;
  1120 	$defaults['selected'] = is_author() ? get_query_var( 'author' ) : 0;
  1057 
  1121 
  1058 	$r = wp_parse_args( $args, $defaults );
  1122 	$r = wp_parse_args( $args, $defaults );
  1068 		$fields[] = $show;
  1132 		$fields[] = $show;
  1069 	}
  1133 	}
  1070 
  1134 
  1071 	$query_args['fields'] = $fields;
  1135 	$query_args['fields'] = $fields;
  1072 
  1136 
  1073 	$show_option_all = $r['show_option_all'];
  1137 	$show_option_all   = $r['show_option_all'];
  1074 	$show_option_none = $r['show_option_none'];
  1138 	$show_option_none  = $r['show_option_none'];
  1075 	$option_none_value = $r['option_none_value'];
  1139 	$option_none_value = $r['option_none_value'];
  1076 
  1140 
  1077 	/**
  1141 	/**
  1078 	 * Filters the query arguments for the list of users in the dropdown.
  1142 	 * Filters the query arguments for the list of users in the dropdown.
  1079 	 *
  1143 	 *
  1100 			$output .= "\t<option value='0'>$show_option_all</option>\n";
  1164 			$output .= "\t<option value='0'>$show_option_all</option>\n";
  1101 		}
  1165 		}
  1102 
  1166 
  1103 		if ( $show_option_none ) {
  1167 		if ( $show_option_none ) {
  1104 			$_selected = selected( $option_none_value, $r['selected'], false );
  1168 			$_selected = selected( $option_none_value, $r['selected'], false );
  1105 			$output .= "\t<option value='" . esc_attr( $option_none_value ) . "'$_selected>$show_option_none</option>\n";
  1169 			$output   .= "\t<option value='" . esc_attr( $option_none_value ) . "'$_selected>$show_option_none</option>\n";
  1106 		}
  1170 		}
  1107 
  1171 
  1108 		if ( $r['include_selected'] && ( $r['selected'] > 0 ) ) {
  1172 		if ( $r['include_selected'] && ( $r['selected'] > 0 ) ) {
  1109 			$found_selected = false;
  1173 			$found_selected = false;
  1110 			$r['selected'] = (int) $r['selected'];
  1174 			$r['selected']  = (int) $r['selected'];
  1111 			foreach ( (array) $users as $user ) {
  1175 			foreach ( (array) $users as $user ) {
  1112 				$user->ID = (int) $user->ID;
  1176 				$user->ID = (int) $user->ID;
  1113 				if ( $user->ID === $r['selected'] ) {
  1177 				if ( $user->ID === $r['selected'] ) {
  1114 					$found_selected = true;
  1178 					$found_selected = true;
  1115 				}
  1179 				}
  1129 			} else {
  1193 			} else {
  1130 				$display = '(' . $user->user_login . ')';
  1194 				$display = '(' . $user->user_login . ')';
  1131 			}
  1195 			}
  1132 
  1196 
  1133 			$_selected = selected( $user->ID, $r['selected'], false );
  1197 			$_selected = selected( $user->ID, $r['selected'], false );
  1134 			$output .= "\t<option value='$user->ID'$_selected>" . esc_html( $display ) . "</option>\n";
  1198 			$output   .= "\t<option value='$user->ID'$_selected>" . esc_html( $display ) . "</option>\n";
  1135 		}
  1199 		}
  1136 
  1200 
  1137 		$output .= "</select>";
  1201 		$output .= '</select>';
  1138 	}
  1202 	}
  1139 
  1203 
  1140 	/**
  1204 	/**
  1141 	 * Filters the wp_dropdown_users() HTML output.
  1205 	 * Filters the wp_dropdown_users() HTML output.
  1142 	 *
  1206 	 *
  1166  * @param int    $user_id User ID.
  1230  * @param int    $user_id User ID.
  1167  * @param string $context How to sanitize user fields. Looks for 'raw', 'edit', 'db', 'display',
  1231  * @param string $context How to sanitize user fields. Looks for 'raw', 'edit', 'db', 'display',
  1168  *                        'attribute' and 'js'.
  1232  *                        'attribute' and 'js'.
  1169  * @return mixed Sanitized value.
  1233  * @return mixed Sanitized value.
  1170  */
  1234  */
  1171 function sanitize_user_field($field, $value, $user_id, $context) {
  1235 function sanitize_user_field( $field, $value, $user_id, $context ) {
  1172 	$int_fields = array('ID');
  1236 	$int_fields = array( 'ID' );
  1173 	if ( in_array($field, $int_fields) )
  1237 	if ( in_array( $field, $int_fields ) ) {
  1174 		$value = (int) $value;
  1238 		$value = (int) $value;
  1175 
  1239 	}
  1176 	if ( 'raw' == $context )
  1240 
       
  1241 	if ( 'raw' == $context ) {
  1177 		return $value;
  1242 		return $value;
  1178 
  1243 	}
  1179 	if ( !is_string($value) && !is_numeric($value) )
  1244 
       
  1245 	if ( ! is_string( $value ) && ! is_numeric( $value ) ) {
  1180 		return $value;
  1246 		return $value;
       
  1247 	}
  1181 
  1248 
  1182 	$prefixed = false !== strpos( $field, 'user_' );
  1249 	$prefixed = false !== strpos( $field, 'user_' );
  1183 
  1250 
  1184 	if ( 'edit' == $context ) {
  1251 	if ( 'edit' == $context ) {
  1185 		if ( $prefixed ) {
  1252 		if ( $prefixed ) {
  1200 			 * @param int   $user_id User ID.
  1267 			 * @param int   $user_id User ID.
  1201 			 */
  1268 			 */
  1202 			$value = apply_filters( "edit_user_{$field}", $value, $user_id );
  1269 			$value = apply_filters( "edit_user_{$field}", $value, $user_id );
  1203 		}
  1270 		}
  1204 
  1271 
  1205 		if ( 'description' == $field )
  1272 		if ( 'description' == $field ) {
  1206 			$value = esc_html( $value ); // textarea_escaped?
  1273 			$value = esc_html( $value ); // textarea_escaped?
  1207 		else
  1274 		} else {
  1208 			$value = esc_attr($value);
  1275 			$value = esc_attr( $value );
       
  1276 		}
  1209 	} elseif ( 'db' == $context ) {
  1277 	} elseif ( 'db' == $context ) {
  1210 		if ( $prefixed ) {
  1278 		if ( $prefixed ) {
  1211 			/** This filter is documented in wp-includes/post.php */
  1279 			/** This filter is documented in wp-includes/post.php */
  1212 			$value = apply_filters( "pre_{$field}", $value );
  1280 			$value = apply_filters( "pre_{$field}", $value );
  1213 		} else {
  1281 		} else {
  1215 			/**
  1283 			/**
  1216 			 * Filters the value of a user field in the 'db' context.
  1284 			 * Filters the value of a user field in the 'db' context.
  1217 			 *
  1285 			 *
  1218 			 * The dynamic portion of the hook name, `$field`, refers to the prefixed user
  1286 			 * The dynamic portion of the hook name, `$field`, refers to the prefixed user
  1219 			 * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.
  1287 			 * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.
  1220  			 *
  1288 			 *
  1221 			 * @since 2.9.0
  1289 			 * @since 2.9.0
  1222 			 *
  1290 			 *
  1223 			 * @param mixed $value Value of the prefixed user field.
  1291 			 * @param mixed $value Value of the prefixed user field.
  1224 			 */
  1292 			 */
  1225 			$value = apply_filters( "pre_user_{$field}", $value );
  1293 			$value = apply_filters( "pre_user_{$field}", $value );
  1246 			 */
  1314 			 */
  1247 			$value = apply_filters( "user_{$field}", $value, $user_id, $context );
  1315 			$value = apply_filters( "user_{$field}", $value, $user_id, $context );
  1248 		}
  1316 		}
  1249 	}
  1317 	}
  1250 
  1318 
  1251 	if ( 'user_url' == $field )
  1319 	if ( 'user_url' == $field ) {
  1252 		$value = esc_url($value);
  1320 		$value = esc_url( $value );
       
  1321 	}
  1253 
  1322 
  1254 	if ( 'attribute' == $context ) {
  1323 	if ( 'attribute' == $context ) {
  1255 		$value = esc_attr( $value );
  1324 		$value = esc_attr( $value );
  1256 	} elseif ( 'js' == $context ) {
  1325 	} elseif ( 'js' == $context ) {
  1257 		$value = esc_js( $value );
  1326 		$value = esc_js( $value );
  1274 		}
  1343 		}
  1275 
  1344 
  1276 		$user = $user->data;
  1345 		$user = $user->data;
  1277 	}
  1346 	}
  1278 
  1347 
  1279 	wp_cache_add($user->ID, $user, 'users');
  1348 	wp_cache_add( $user->ID, $user, 'users' );
  1280 	wp_cache_add($user->user_login, $user->ID, 'userlogins');
  1349 	wp_cache_add( $user->user_login, $user->ID, 'userlogins' );
  1281 	wp_cache_add($user->user_email, $user->ID, 'useremail');
  1350 	wp_cache_add( $user->user_email, $user->ID, 'useremail' );
  1282 	wp_cache_add($user->user_nicename, $user->ID, 'userslugs');
  1351 	wp_cache_add( $user->user_nicename, $user->ID, 'userslugs' );
  1283 }
  1352 }
  1284 
  1353 
  1285 /**
  1354 /**
  1286  * Clean all user caches
  1355  * Clean all user caches
  1287  *
  1356  *
  1289  * @since 4.4.0 'clean_user_cache' action was added.
  1358  * @since 4.4.0 'clean_user_cache' action was added.
  1290  *
  1359  *
  1291  * @param WP_User|int $user User object or ID to be cleaned from the cache
  1360  * @param WP_User|int $user User object or ID to be cleaned from the cache
  1292  */
  1361  */
  1293 function clean_user_cache( $user ) {
  1362 function clean_user_cache( $user ) {
  1294 	if ( is_numeric( $user ) )
  1363 	if ( is_numeric( $user ) ) {
  1295 		$user = new WP_User( $user );
  1364 		$user = new WP_User( $user );
  1296 
  1365 	}
  1297 	if ( ! $user->exists() )
  1366 
       
  1367 	if ( ! $user->exists() ) {
  1298 		return;
  1368 		return;
       
  1369 	}
  1299 
  1370 
  1300 	wp_cache_delete( $user->ID, 'users' );
  1371 	wp_cache_delete( $user->ID, 'users' );
  1301 	wp_cache_delete( $user->user_login, 'userlogins' );
  1372 	wp_cache_delete( $user->user_login, 'userlogins' );
  1302 	wp_cache_delete( $user->user_email, 'useremail' );
  1373 	wp_cache_delete( $user->user_email, 'useremail' );
  1303 	wp_cache_delete( $user->user_nicename, 'userslugs' );
  1374 	wp_cache_delete( $user->user_nicename, 'userslugs' );
  1312 	 */
  1383 	 */
  1313 	do_action( 'clean_user_cache', $user->ID, $user );
  1384 	do_action( 'clean_user_cache', $user->ID, $user );
  1314 }
  1385 }
  1315 
  1386 
  1316 /**
  1387 /**
  1317  * Checks whether the given username exists.
  1388  * Determines whether the given username exists.
       
  1389  *
       
  1390  * For more information on this and similar theme functions, check out
       
  1391  * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
       
  1392  * Conditional Tags} article in the Theme Developer Handbook.
  1318  *
  1393  *
  1319  * @since 2.0.0
  1394  * @since 2.0.0
  1320  *
  1395  *
  1321  * @param string $username Username.
  1396  * @param string $username Username.
  1322  * @return int|false The user's ID on success, and false on failure.
  1397  * @return int|false The user's ID on success, and false on failure.
  1323  */
  1398  */
  1324 function username_exists( $username ) {
  1399 function username_exists( $username ) {
  1325 	if ( $user = get_user_by( 'login', $username ) ) {
  1400 	$user = get_user_by( 'login', $username );
       
  1401 	if ( $user ) {
  1326 		$user_id = $user->ID;
  1402 		$user_id = $user->ID;
  1327 	} else {
  1403 	} else {
  1328 		$user_id = false;
  1404 		$user_id = false;
  1329 	}
  1405 	}
  1330 
  1406 
  1338 	 */
  1414 	 */
  1339 	return apply_filters( 'username_exists', $user_id, $username );
  1415 	return apply_filters( 'username_exists', $user_id, $username );
  1340 }
  1416 }
  1341 
  1417 
  1342 /**
  1418 /**
  1343  * Checks whether the given email exists.
  1419  * Determines whether the given email exists.
       
  1420  *
       
  1421  * For more information on this and similar theme functions, check out
       
  1422  * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
       
  1423  * Conditional Tags} article in the Theme Developer Handbook.
  1344  *
  1424  *
  1345  * @since 2.1.0
  1425  * @since 2.1.0
  1346  *
  1426  *
  1347  * @param string $email Email.
  1427  * @param string $email Email.
  1348  * @return int|false The user's ID on success, and false on failure.
  1428  * @return int|false The user's ID on success, and false on failure.
  1349  */
  1429  */
  1350 function email_exists( $email ) {
  1430 function email_exists( $email ) {
  1351 	if ( $user = get_user_by( 'email', $email) ) {
  1431 	$user = get_user_by( 'email', $email );
       
  1432 	if ( $user ) {
  1352 		return $user->ID;
  1433 		return $user->ID;
  1353 	}
  1434 	}
  1354 	return false;
  1435 	return false;
  1355 }
  1436 }
  1356 
  1437 
  1363  * @param string $username Username.
  1444  * @param string $username Username.
  1364  * @return bool Whether username given is valid
  1445  * @return bool Whether username given is valid
  1365  */
  1446  */
  1366 function validate_username( $username ) {
  1447 function validate_username( $username ) {
  1367 	$sanitized = sanitize_user( $username, true );
  1448 	$sanitized = sanitize_user( $username, true );
  1368 	$valid = ( $sanitized == $username && ! empty( $sanitized ) );
  1449 	$valid     = ( $sanitized == $username && ! empty( $sanitized ) );
  1369 
  1450 
  1370 	/**
  1451 	/**
  1371 	 * Filters whether the provided username is valid or not.
  1452 	 * Filters whether the provided username is valid or not.
  1372 	 *
  1453 	 *
  1373 	 * @since 2.0.1
  1454 	 * @since 2.0.1
  1441 		$userdata = $userdata->to_array();
  1522 		$userdata = $userdata->to_array();
  1442 	}
  1523 	}
  1443 
  1524 
  1444 	// Are we updating or creating?
  1525 	// Are we updating or creating?
  1445 	if ( ! empty( $userdata['ID'] ) ) {
  1526 	if ( ! empty( $userdata['ID'] ) ) {
  1446 		$ID = (int) $userdata['ID'];
  1527 		$ID            = (int) $userdata['ID'];
  1447 		$update = true;
  1528 		$update        = true;
  1448 		$old_user_data = get_userdata( $ID );
  1529 		$old_user_data = get_userdata( $ID );
  1449 
  1530 
  1450 		if ( ! $old_user_data ) {
  1531 		if ( ! $old_user_data ) {
  1451 			return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
  1532 			return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
  1452 		}
  1533 		}
  1475 	//Remove any non-printable chars from the login string to see if we have ended up with an empty username
  1556 	//Remove any non-printable chars from the login string to see if we have ended up with an empty username
  1476 	$user_login = trim( $pre_user_login );
  1557 	$user_login = trim( $pre_user_login );
  1477 
  1558 
  1478 	// user_login must be between 0 and 60 characters.
  1559 	// user_login must be between 0 and 60 characters.
  1479 	if ( empty( $user_login ) ) {
  1560 	if ( empty( $user_login ) ) {
  1480 		return new WP_Error('empty_user_login', __('Cannot create a user with an empty login name.') );
  1561 		return new WP_Error( 'empty_user_login', __( 'Cannot create a user with an empty login name.' ) );
  1481 	} elseif ( mb_strlen( $user_login ) > 60 ) {
  1562 	} elseif ( mb_strlen( $user_login ) > 60 ) {
  1482 		return new WP_Error( 'user_login_too_long', __( 'Username may not be longer than 60 characters.' ) );
  1563 		return new WP_Error( 'user_login_too_long', __( 'Username may not be longer than 60 characters.' ) );
  1483 	}
  1564 	}
  1484 
  1565 
  1485 	if ( ! $update && username_exists( $user_login ) ) {
  1566 	if ( ! $update && username_exists( $user_login ) ) {
  1633 
  1714 
  1634 	$meta['syntax_highlighting'] = empty( $userdata['syntax_highlighting'] ) ? 'true' : $userdata['syntax_highlighting'];
  1715 	$meta['syntax_highlighting'] = empty( $userdata['syntax_highlighting'] ) ? 'true' : $userdata['syntax_highlighting'];
  1635 
  1716 
  1636 	$meta['comment_shortcuts'] = empty( $userdata['comment_shortcuts'] ) || 'false' === $userdata['comment_shortcuts'] ? 'false' : 'true';
  1717 	$meta['comment_shortcuts'] = empty( $userdata['comment_shortcuts'] ) || 'false' === $userdata['comment_shortcuts'] ? 'false' : 'true';
  1637 
  1718 
  1638 	$admin_color = empty( $userdata['admin_color'] ) ? 'fresh' : $userdata['admin_color'];
  1719 	$admin_color         = empty( $userdata['admin_color'] ) ? 'fresh' : $userdata['admin_color'];
  1639 	$meta['admin_color'] = preg_replace( '|[^a-z0-9 _.\-@]|i', '', $admin_color );
  1720 	$meta['admin_color'] = preg_replace( '|[^a-z0-9 _.\-@]|i', '', $admin_color );
  1640 
  1721 
  1641 	$meta['use_ssl'] = empty( $userdata['use_ssl'] ) ? 0 : $userdata['use_ssl'];
  1722 	$meta['use_ssl'] = empty( $userdata['use_ssl'] ) ? 0 : $userdata['use_ssl'];
  1642 
  1723 
  1643 	$user_registered = empty( $userdata['user_registered'] ) ? gmdate( 'Y-m-d H:i:s' ) : $userdata['user_registered'];
  1724 	$user_registered = empty( $userdata['user_registered'] ) ? gmdate( 'Y-m-d H:i:s' ) : $userdata['user_registered'];
  1644 
  1725 
  1645 	$meta['show_admin_bar_front'] = empty( $userdata['show_admin_bar_front'] ) ? 'true' : $userdata['show_admin_bar_front'];
  1726 	$meta['show_admin_bar_front'] = empty( $userdata['show_admin_bar_front'] ) ? 'true' : $userdata['show_admin_bar_front'];
  1646 
  1727 
  1647 	$meta['locale'] = isset( $userdata['locale'] ) ? $userdata['locale'] : '';
  1728 	$meta['locale'] = isset( $userdata['locale'] ) ? $userdata['locale'] : '';
  1648 
  1729 
  1649 	$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));
  1730 	$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 ) );
  1650 
  1731 
  1651 	if ( $user_nicename_check ) {
  1732 	if ( $user_nicename_check ) {
  1652 		$suffix = 2;
  1733 		$suffix = 2;
  1653 		while ($user_nicename_check) {
  1734 		while ( $user_nicename_check ) {
  1654 			// user_nicename allows 50 chars. Subtract one for a hyphen, plus the length of the suffix.
  1735 			// user_nicename allows 50 chars. Subtract one for a hyphen, plus the length of the suffix.
  1655 			$base_length = 49 - mb_strlen( $suffix );
  1736 			$base_length         = 49 - mb_strlen( $suffix );
  1656 			$alt_user_nicename = mb_substr( $user_nicename, 0, $base_length ) . "-$suffix";
  1737 			$alt_user_nicename   = mb_substr( $user_nicename, 0, $base_length ) . "-$suffix";
  1657 			$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));
  1738 			$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 ) );
  1658 			$suffix++;
  1739 			$suffix++;
  1659 		}
  1740 		}
  1660 		$user_nicename = $alt_user_nicename;
  1741 		$user_nicename = $alt_user_nicename;
  1661 	}
  1742 	}
  1662 
  1743 
  1663 	$compacted = compact( 'user_pass', 'user_email', 'user_url', 'user_nicename', 'display_name', 'user_registered' );
  1744 	$compacted = compact( 'user_pass', 'user_email', 'user_url', 'user_nicename', 'display_name', 'user_registered' );
  1664 	$data = wp_unslash( $compacted );
  1745 	$data      = wp_unslash( $compacted );
  1665 
  1746 
  1666 	if ( ! $update ) {
  1747 	if ( ! $update ) {
  1667 		$data = $data + compact( 'user_login' );
  1748 		$data = $data + compact( 'user_login' );
  1668 	}
  1749 	}
  1669 
  1750 
  1703 	}
  1784 	}
  1704 
  1785 
  1705 	$user = new WP_User( $user_id );
  1786 	$user = new WP_User( $user_id );
  1706 
  1787 
  1707 	/**
  1788 	/**
  1708  	 * Filters a user's meta values and keys immediately after the user is created or updated
  1789 	 * Filters a user's meta values and keys immediately after the user is created or updated
  1709  	 * and before any user meta is inserted or updated.
  1790 	 * and before any user meta is inserted or updated.
  1710  	 *
  1791 	 *
  1711  	 * Does not include contact methods. These are added using `wp_get_user_contact_methods( $user )`.
  1792 	 * Does not include contact methods. These are added using `wp_get_user_contact_methods( $user )`.
  1712  	 *
  1793 	 *
  1713  	 * @since 4.4.0
  1794 	 * @since 4.4.0
  1714  	 *
  1795 	 *
  1715  	 * @param array $meta {
  1796 	 * @param array $meta {
  1716  	 *     Default meta values and keys for the user.
  1797 	 *     Default meta values and keys for the user.
  1717  	 *
  1798 	 *
  1718  	 *     @type string   $nickname             The user's nickname. Default is the user's username.
  1799 	 *     @type string   $nickname             The user's nickname. Default is the user's username.
  1719 	 *     @type string   $first_name           The user's first name.
  1800 	 *     @type string   $first_name           The user's first name.
  1720 	 *     @type string   $last_name            The user's last name.
  1801 	 *     @type string   $last_name            The user's last name.
  1721 	 *     @type string   $description          The user's description.
  1802 	 *     @type string   $description          The user's description.
  1722 	 *     @type bool     $rich_editing         Whether to enable the rich-editor for the user. False if not empty.
  1803 	 *     @type bool     $rich_editing         Whether to enable the rich-editor for the user. False if not empty.
  1723 	 *     @type bool     $syntax_highlighting  Whether to enable the rich code editor for the user. False if not empty.
  1804 	 *     @type bool     $syntax_highlighting  Whether to enable the rich code editor for the user. False if not empty.
  1725 	 *     @type string   $admin_color          The color scheme for a user's admin screen. Default 'fresh'.
  1806 	 *     @type string   $admin_color          The color scheme for a user's admin screen. Default 'fresh'.
  1726 	 *     @type int|bool $use_ssl              Whether to force SSL on the user's admin area. 0|false if SSL is
  1807 	 *     @type int|bool $use_ssl              Whether to force SSL on the user's admin area. 0|false if SSL is
  1727 	 *                                          not forced.
  1808 	 *                                          not forced.
  1728 	 *     @type bool     $show_admin_bar_front Whether to show the admin bar on the front end for the user.
  1809 	 *     @type bool     $show_admin_bar_front Whether to show the admin bar on the front end for the user.
  1729 	 *                                          Default true.
  1810 	 *                                          Default true.
  1730  	 * }
  1811 	 * }
  1731 	 * @param WP_User $user   User object.
  1812 	 * @param WP_User $user   User object.
  1732 	 * @param bool    $update Whether the user is being updated rather than created.
  1813 	 * @param bool    $update Whether the user is being updated rather than created.
  1733  	 */
  1814 	 */
  1734 	$meta = apply_filters( 'insert_user_meta', $meta, $user, $update );
  1815 	$meta = apply_filters( 'insert_user_meta', $meta, $user, $update );
  1735 
  1816 
  1736 	// Update user meta.
  1817 	// Update user meta.
  1737 	foreach ( $meta as $key => $value ) {
  1818 	foreach ( $meta as $key => $value ) {
  1738 		update_user_meta( $user_id, $key, $value );
  1819 		update_user_meta( $user_id, $key, $value );
  1745 	}
  1826 	}
  1746 
  1827 
  1747 	if ( isset( $userdata['role'] ) ) {
  1828 	if ( isset( $userdata['role'] ) ) {
  1748 		$user->set_role( $userdata['role'] );
  1829 		$user->set_role( $userdata['role'] );
  1749 	} elseif ( ! $update ) {
  1830 	} elseif ( ! $update ) {
  1750 		$user->set_role(get_option('default_role'));
  1831 		$user->set_role( get_option( 'default_role' ) );
  1751 	}
  1832 	}
  1752 	wp_cache_delete( $user_id, 'users' );
  1833 	wp_cache_delete( $user_id, 'users' );
  1753 	wp_cache_delete( $user_login, 'userlogins' );
  1834 	wp_cache_delete( $user_login, 'userlogins' );
  1754 
  1835 
  1755 	if ( $update ) {
  1836 	if ( $update ) {
  1787  *
  1868  *
  1788  * @since 2.0.0
  1869  * @since 2.0.0
  1789  *
  1870  *
  1790  * @see wp_insert_user() For what fields can be set in $userdata.
  1871  * @see wp_insert_user() For what fields can be set in $userdata.
  1791  *
  1872  *
  1792  * @param object|WP_User $userdata An array of user data or a user object of type stdClass or WP_User.
  1873  * @param array|object|WP_User $userdata An array of user data or a user object of type stdClass or WP_User.
  1793  * @return int|WP_Error The updated user's ID or a WP_Error object if the user could not be updated.
  1874  * @return int|WP_Error The updated user's ID or a WP_Error object if the user could not be updated.
  1794  */
  1875  */
  1795 function wp_update_user($userdata) {
  1876 function wp_update_user( $userdata ) {
  1796 	if ( $userdata instanceof stdClass ) {
  1877 	if ( $userdata instanceof stdClass ) {
  1797 		$userdata = get_object_vars( $userdata );
  1878 		$userdata = get_object_vars( $userdata );
  1798 	} elseif ( $userdata instanceof WP_User ) {
  1879 	} elseif ( $userdata instanceof WP_User ) {
  1799 		$userdata = $userdata->to_array();
  1880 		$userdata = $userdata->to_array();
  1800 	}
  1881 	}
  1820 	// Escape data pulled from DB.
  1901 	// Escape data pulled from DB.
  1821 	$user = add_magic_quotes( $user );
  1902 	$user = add_magic_quotes( $user );
  1822 
  1903 
  1823 	if ( ! empty( $userdata['user_pass'] ) && $userdata['user_pass'] !== $user_obj->user_pass ) {
  1904 	if ( ! empty( $userdata['user_pass'] ) && $userdata['user_pass'] !== $user_obj->user_pass ) {
  1824 		// If password is changing, hash it now
  1905 		// If password is changing, hash it now
  1825 		$plaintext_pass = $userdata['user_pass'];
  1906 		$plaintext_pass        = $userdata['user_pass'];
  1826 		$userdata['user_pass'] = wp_hash_password( $userdata['user_pass'] );
  1907 		$userdata['user_pass'] = wp_hash_password( $userdata['user_pass'] );
  1827 
  1908 
  1828 		/**
  1909 		/**
  1829 		 * Filters whether to send the password change email.
  1910 		 * Filters whether to send the password change email.
  1830 		 *
  1911 		 *
  1833 		 * @see wp_insert_user() For `$user` and `$userdata` fields.
  1914 		 * @see wp_insert_user() For `$user` and `$userdata` fields.
  1834 		 *
  1915 		 *
  1835 		 * @param bool  $send     Whether to send the email.
  1916 		 * @param bool  $send     Whether to send the email.
  1836 		 * @param array $user     The original user array.
  1917 		 * @param array $user     The original user array.
  1837 		 * @param array $userdata The updated user array.
  1918 		 * @param array $userdata The updated user array.
  1838 		 *
       
  1839 		 */
  1919 		 */
  1840 		$send_password_change_email = apply_filters( 'send_password_change_email', true, $user, $userdata );
  1920 		$send_password_change_email = apply_filters( 'send_password_change_email', true, $user, $userdata );
  1841 	}
  1921 	}
  1842 
  1922 
  1843 	if ( isset( $userdata['user_email'] ) && $user['user_email'] !== $userdata['user_email'] ) {
  1923 	if ( isset( $userdata['user_email'] ) && $user['user_email'] !== $userdata['user_email'] ) {
  1849 		 * @see wp_insert_user() For `$user` and `$userdata` fields.
  1929 		 * @see wp_insert_user() For `$user` and `$userdata` fields.
  1850 		 *
  1930 		 *
  1851 		 * @param bool  $send     Whether to send the email.
  1931 		 * @param bool  $send     Whether to send the email.
  1852 		 * @param array $user     The original user array.
  1932 		 * @param array $user     The original user array.
  1853 		 * @param array $userdata The updated user array.
  1933 		 * @param array $userdata The updated user array.
  1854 		 *
       
  1855 		 */
  1934 		 */
  1856 		$send_email_change_email = apply_filters( 'send_email_change_email', true, $user, $userdata );
  1935 		$send_email_change_email = apply_filters( 'send_email_change_email', true, $user, $userdata );
  1857 	}
  1936 	}
  1858 
  1937 
  1859 	wp_cache_delete( $user['user_email'], 'useremail' );
  1938 	wp_cache_delete( $user['user_email'], 'useremail' );
  1860 	wp_cache_delete( $user['user_nicename'], 'userslugs' );
  1939 	wp_cache_delete( $user['user_nicename'], 'userslugs' );
  1861 
  1940 
  1862 	// Merge old and new fields with new fields overwriting old ones.
  1941 	// Merge old and new fields with new fields overwriting old ones.
  1863 	$userdata = array_merge( $user, $userdata );
  1942 	$userdata = array_merge( $user, $userdata );
  1864 	$user_id = wp_insert_user( $userdata );
  1943 	$user_id  = wp_insert_user( $userdata );
  1865 
  1944 
  1866 	if ( ! is_wp_error( $user_id ) ) {
  1945 	if ( ! is_wp_error( $user_id ) ) {
  1867 
  1946 
  1868 		$blog_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
  1947 		$blog_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
  1869 
  1948 
  1872 			$switched_locale = switch_to_locale( get_user_locale( $user_id ) );
  1951 			$switched_locale = switch_to_locale( get_user_locale( $user_id ) );
  1873 		}
  1952 		}
  1874 
  1953 
  1875 		if ( ! empty( $send_password_change_email ) ) {
  1954 		if ( ! empty( $send_password_change_email ) ) {
  1876 			/* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
  1955 			/* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
  1877 			$pass_change_text = __( 'Hi ###USERNAME###,
  1956 			$pass_change_text = __(
       
  1957 				'Hi ###USERNAME###,
  1878 
  1958 
  1879 This notice confirms that your password was changed on ###SITENAME###.
  1959 This notice confirms that your password was changed on ###SITENAME###.
  1880 
  1960 
  1881 If you did not change your password, please contact the Site Administrator at
  1961 If you did not change your password, please contact the Site Administrator at
  1882 ###ADMIN_EMAIL###
  1962 ###ADMIN_EMAIL###
  1883 
  1963 
  1884 This email has been sent to ###EMAIL###
  1964 This email has been sent to ###EMAIL###
  1885 
  1965 
  1886 Regards,
  1966 Regards,
  1887 All at ###SITENAME###
  1967 All at ###SITENAME###
  1888 ###SITEURL###' );
  1968 ###SITEURL###'
       
  1969 			);
  1889 
  1970 
  1890 			$pass_change_email = array(
  1971 			$pass_change_email = array(
  1891 				'to'      => $user['user_email'],
  1972 				'to'      => $user['user_email'],
  1892 				/* translators: User password change notification email subject. 1: Site name */
  1973 				/* translators: Password change notification email subject. %s: Site name */
  1893 				'subject' => __( '[%s] Notice of Password Change' ),
  1974 				'subject' => __( '[%s] Password Changed' ),
  1894 				'message' => $pass_change_text,
  1975 				'message' => $pass_change_text,
  1895 				'headers' => '',
  1976 				'headers' => '',
  1896 			);
  1977 			);
  1897 
  1978 
  1898 			/**
  1979 			/**
  1913 			 *                - ###SITEURL###     The URL to the site.
  1994 			 *                - ###SITEURL###     The URL to the site.
  1914 			 *            @type string $headers Headers. Add headers in a newline (\r\n) separated string.
  1995 			 *            @type string $headers Headers. Add headers in a newline (\r\n) separated string.
  1915 			 *        }
  1996 			 *        }
  1916 			 * @param array $user     The original user array.
  1997 			 * @param array $user     The original user array.
  1917 			 * @param array $userdata The updated user array.
  1998 			 * @param array $userdata The updated user array.
  1918 			 *
       
  1919 			 */
  1999 			 */
  1920 			$pass_change_email = apply_filters( 'password_change_email', $pass_change_email, $user, $userdata );
  2000 			$pass_change_email = apply_filters( 'password_change_email', $pass_change_email, $user, $userdata );
  1921 
  2001 
  1922 			$pass_change_email['message'] = str_replace( '###USERNAME###', $user['user_login'], $pass_change_email['message'] );
  2002 			$pass_change_email['message'] = str_replace( '###USERNAME###', $user['user_login'], $pass_change_email['message'] );
  1923 			$pass_change_email['message'] = str_replace( '###ADMIN_EMAIL###', get_option( 'admin_email' ), $pass_change_email['message'] );
  2003 			$pass_change_email['message'] = str_replace( '###ADMIN_EMAIL###', get_option( 'admin_email' ), $pass_change_email['message'] );
  1928 			wp_mail( $pass_change_email['to'], sprintf( $pass_change_email['subject'], $blog_name ), $pass_change_email['message'], $pass_change_email['headers'] );
  2008 			wp_mail( $pass_change_email['to'], sprintf( $pass_change_email['subject'], $blog_name ), $pass_change_email['message'], $pass_change_email['headers'] );
  1929 		}
  2009 		}
  1930 
  2010 
  1931 		if ( ! empty( $send_email_change_email ) ) {
  2011 		if ( ! empty( $send_email_change_email ) ) {
  1932 			/* translators: Do not translate USERNAME, ADMIN_EMAIL, NEW_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
  2012 			/* translators: Do not translate USERNAME, ADMIN_EMAIL, NEW_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
  1933 			$email_change_text = __( 'Hi ###USERNAME###,
  2013 			$email_change_text = __(
       
  2014 				'Hi ###USERNAME###,
  1934 
  2015 
  1935 This notice confirms that your email address on ###SITENAME### was changed to ###NEW_EMAIL###.
  2016 This notice confirms that your email address on ###SITENAME### was changed to ###NEW_EMAIL###.
  1936 
  2017 
  1937 If you did not change your email, please contact the Site Administrator at
  2018 If you did not change your email, please contact the Site Administrator at
  1938 ###ADMIN_EMAIL###
  2019 ###ADMIN_EMAIL###
  1939 
  2020 
  1940 This email has been sent to ###EMAIL###
  2021 This email has been sent to ###EMAIL###
  1941 
  2022 
  1942 Regards,
  2023 Regards,
  1943 All at ###SITENAME###
  2024 All at ###SITENAME###
  1944 ###SITEURL###' );
  2025 ###SITEURL###'
       
  2026 			);
  1945 
  2027 
  1946 			$email_change_email = array(
  2028 			$email_change_email = array(
  1947 				'to'      => $user['user_email'],
  2029 				'to'      => $user['user_email'],
  1948 				/* translators: User email change notification email subject. 1: Site name */
  2030 				/* translators: Email change notification email subject. %s: Site name */
  1949 				'subject' => __( '[%s] Notice of Email Change' ),
  2031 				'subject' => __( '[%s] Email Changed' ),
  1950 				'message' => $email_change_text,
  2032 				'message' => $email_change_text,
  1951 				'headers' => '',
  2033 				'headers' => '',
  1952 			);
  2034 			);
  1953 
  2035 
  1954 			/**
  2036 			/**
  1991 	}
  2073 	}
  1992 
  2074 
  1993 	// Update the cookies if the password changed.
  2075 	// Update the cookies if the password changed.
  1994 	$current_user = wp_get_current_user();
  2076 	$current_user = wp_get_current_user();
  1995 	if ( $current_user->ID == $ID ) {
  2077 	if ( $current_user->ID == $ID ) {
  1996 		if ( isset($plaintext_pass) ) {
  2078 		if ( isset( $plaintext_pass ) ) {
  1997 			wp_clear_auth_cookie();
  2079 			wp_clear_auth_cookie();
  1998 
  2080 
  1999 			// Here we calculate the expiration length of the current auth cookie and compare it to the default expiration.
  2081 			// Here we calculate the expiration length of the current auth cookie and compare it to the default expiration.
  2000 			// If it's greater than this, then we know the user checked 'Remember Me' when they logged in.
  2082 			// If it's greater than this, then we know the user checked 'Remember Me' when they logged in.
  2001 			$logged_in_cookie    = wp_parse_auth_cookie( '', 'logged_in' );
  2083 			$logged_in_cookie = wp_parse_auth_cookie( '', 'logged_in' );
  2002 			/** This filter is documented in wp-includes/pluggable.php */
  2084 			/** This filter is documented in wp-includes/pluggable.php */
  2003 			$default_cookie_life = apply_filters( 'auth_cookie_expiration', ( 2 * DAY_IN_SECONDS ), $ID, false );
  2085 			$default_cookie_life = apply_filters( 'auth_cookie_expiration', ( 2 * DAY_IN_SECONDS ), $ID, false );
  2004 			$remember            = ( ( $logged_in_cookie['expiration'] - time() ) > $default_cookie_life );
  2086 			$remember            = ( ( $logged_in_cookie['expiration'] - time() ) > $default_cookie_life );
  2005 
  2087 
  2006 			wp_set_auth_cookie( $ID, $remember );
  2088 			wp_set_auth_cookie( $ID, $remember );
  2023  * @param string $password The user's password.
  2105  * @param string $password The user's password.
  2024  * @param string $email    Optional. The user's email. Default empty.
  2106  * @param string $email    Optional. The user's email. Default empty.
  2025  * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not
  2107  * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not
  2026  *                      be created.
  2108  *                      be created.
  2027  */
  2109  */
  2028 function wp_create_user($username, $password, $email = '') {
  2110 function wp_create_user( $username, $password, $email = '' ) {
  2029 	$user_login = wp_slash( $username );
  2111 	$user_login = wp_slash( $username );
  2030 	$user_email = wp_slash( $email    );
  2112 	$user_email = wp_slash( $email );
  2031 	$user_pass = $password;
  2113 	$user_pass  = $password;
  2032 
  2114 
  2033 	$userdata = compact('user_login', 'user_email', 'user_pass');
  2115 	$userdata = compact( 'user_login', 'user_email', 'user_pass' );
  2034 	return wp_insert_user($userdata);
  2116 	return wp_insert_user( $userdata );
  2035 }
  2117 }
  2036 
  2118 
  2037 /**
  2119 /**
  2038  * Returns a list of meta keys to be (maybe) populated in wp_update_user().
  2120  * Returns a list of meta keys to be (maybe) populated in wp_update_user().
  2039  *
  2121  *
  2065 	$methods = array();
  2147 	$methods = array();
  2066 	if ( get_site_option( 'initial_db_version' ) < 23588 ) {
  2148 	if ( get_site_option( 'initial_db_version' ) < 23588 ) {
  2067 		$methods = array(
  2149 		$methods = array(
  2068 			'aim'    => __( 'AIM' ),
  2150 			'aim'    => __( 'AIM' ),
  2069 			'yim'    => __( 'Yahoo IM' ),
  2151 			'yim'    => __( 'Yahoo IM' ),
  2070 			'jabber' => __( 'Jabber / Google Talk' )
  2152 			'jabber' => __( 'Jabber / Google Talk' ),
  2071 		);
  2153 		);
  2072 	}
  2154 	}
  2073 
  2155 
  2074 	/**
  2156 	/**
  2075 	 * Filters the user contact methods.
  2157 	 * Filters the user contact methods.
  2076 	 *
  2158 	 *
  2077 	 * @since 2.9.0
  2159 	 * @since 2.9.0
  2078 	 *
  2160 	 *
  2079 	 * @param array   $methods Array of contact methods and their labels.
  2161 	 * @param array   $methods Array of contact methods and their labels.
  2080  	 * @param WP_User $user    WP_User object.
  2162 	 * @param WP_User $user    WP_User object.
  2081 	 */
  2163 	 */
  2082 	return apply_filters( 'user_contactmethods', $methods, $user );
  2164 	return apply_filters( 'user_contactmethods', $methods, $user );
  2083 }
  2165 }
  2084 
  2166 
  2085 /**
  2167 /**
  2129  *
  2211  *
  2130  * @return string|WP_Error Password reset key on success. WP_Error on error.
  2212  * @return string|WP_Error Password reset key on success. WP_Error on error.
  2131  */
  2213  */
  2132 function get_password_reset_key( $user ) {
  2214 function get_password_reset_key( $user ) {
  2133 	global $wpdb, $wp_hasher;
  2215 	global $wpdb, $wp_hasher;
       
  2216 
       
  2217 	if ( ! ( $user instanceof WP_User ) ) {
       
  2218 		return new WP_Error( 'invalidcombo', __( '<strong>ERROR</strong>: There is no account with that username or email address.' ) );
       
  2219 	}
  2134 
  2220 
  2135 	/**
  2221 	/**
  2136 	 * Fires before a new password is retrieved.
  2222 	 * Fires before a new password is retrieved.
  2137 	 *
  2223 	 *
  2138 	 * Use the {@see 'retrieve_password'} hook instead.
  2224 	 * Use the {@see 'retrieve_password'} hook instead.
  2190 	// Now insert the key, hashed, into the DB.
  2276 	// Now insert the key, hashed, into the DB.
  2191 	if ( empty( $wp_hasher ) ) {
  2277 	if ( empty( $wp_hasher ) ) {
  2192 		require_once ABSPATH . WPINC . '/class-phpass.php';
  2278 		require_once ABSPATH . WPINC . '/class-phpass.php';
  2193 		$wp_hasher = new PasswordHash( 8, true );
  2279 		$wp_hasher = new PasswordHash( 8, true );
  2194 	}
  2280 	}
  2195 	$hashed = time() . ':' . $wp_hasher->HashPassword( $key );
  2281 	$hashed    = time() . ':' . $wp_hasher->HashPassword( $key );
  2196 	$key_saved = $wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user->user_login ) );
  2282 	$key_saved = $wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user->user_login ) );
  2197 	if ( false === $key_saved ) {
  2283 	if ( false === $key_saved ) {
  2198 		return new WP_Error( 'no_password_key_update', __( 'Could not save password reset key to database.' ) );
  2284 		return new WP_Error( 'no_password_key_update', __( 'Could not save password reset key to database.' ) );
  2199 	}
  2285 	}
  2200 
  2286 
  2216  *
  2302  *
  2217  * @param string $key       Hash to validate sending user's password.
  2303  * @param string $key       Hash to validate sending user's password.
  2218  * @param string $login     The user login.
  2304  * @param string $login     The user login.
  2219  * @return WP_User|WP_Error WP_User object on success, WP_Error object for invalid or expired keys.
  2305  * @return WP_User|WP_Error WP_User object on success, WP_Error object for invalid or expired keys.
  2220  */
  2306  */
  2221 function check_password_reset_key($key, $login) {
  2307 function check_password_reset_key( $key, $login ) {
  2222 	global $wpdb, $wp_hasher;
  2308 	global $wpdb, $wp_hasher;
  2223 
  2309 
  2224 	$key = preg_replace('/[^a-z0-9]/i', '', $key);
  2310 	$key = preg_replace( '/[^a-z0-9]/i', '', $key );
  2225 
  2311 
  2226 	if ( empty( $key ) || !is_string( $key ) )
  2312 	if ( empty( $key ) || ! is_string( $key ) ) {
  2227 		return new WP_Error('invalid_key', __('Invalid key'));
  2313 		return new WP_Error( 'invalid_key', __( 'Invalid key.' ) );
  2228 
  2314 	}
  2229 	if ( empty($login) || !is_string($login) )
  2315 
  2230 		return new WP_Error('invalid_key', __('Invalid key'));
  2316 	if ( empty( $login ) || ! is_string( $login ) ) {
       
  2317 		return new WP_Error( 'invalid_key', __( 'Invalid key.' ) );
       
  2318 	}
  2231 
  2319 
  2232 	$row = $wpdb->get_row( $wpdb->prepare( "SELECT ID, user_activation_key FROM $wpdb->users WHERE user_login = %s", $login ) );
  2320 	$row = $wpdb->get_row( $wpdb->prepare( "SELECT ID, user_activation_key FROM $wpdb->users WHERE user_login = %s", $login ) );
  2233 	if ( ! $row )
  2321 	if ( ! $row ) {
  2234 		return new WP_Error('invalid_key', __('Invalid key'));
  2322 		return new WP_Error( 'invalid_key', __( 'Invalid key.' ) );
       
  2323 	}
  2235 
  2324 
  2236 	if ( empty( $wp_hasher ) ) {
  2325 	if ( empty( $wp_hasher ) ) {
  2237 		require_once ABSPATH . WPINC . '/class-phpass.php';
  2326 		require_once ABSPATH . WPINC . '/class-phpass.php';
  2238 		$wp_hasher = new PasswordHash( 8, true );
  2327 		$wp_hasher = new PasswordHash( 8, true );
  2239 	}
  2328 	}
  2247 	 */
  2336 	 */
  2248 	$expiration_duration = apply_filters( 'password_reset_expiration', DAY_IN_SECONDS );
  2337 	$expiration_duration = apply_filters( 'password_reset_expiration', DAY_IN_SECONDS );
  2249 
  2338 
  2250 	if ( false !== strpos( $row->user_activation_key, ':' ) ) {
  2339 	if ( false !== strpos( $row->user_activation_key, ':' ) ) {
  2251 		list( $pass_request_time, $pass_key ) = explode( ':', $row->user_activation_key, 2 );
  2340 		list( $pass_request_time, $pass_key ) = explode( ':', $row->user_activation_key, 2 );
  2252 		$expiration_time = $pass_request_time + $expiration_duration;
  2341 		$expiration_time                      = $pass_request_time + $expiration_duration;
  2253 	} else {
  2342 	} else {
  2254 		$pass_key = $row->user_activation_key;
  2343 		$pass_key        = $row->user_activation_key;
  2255 		$expiration_time = false;
  2344 		$expiration_time = false;
  2256 	}
  2345 	}
  2257 
  2346 
  2258 	if ( ! $pass_key ) {
  2347 	if ( ! $pass_key ) {
  2259 		return new WP_Error( 'invalid_key', __( 'Invalid key' ) );
  2348 		return new WP_Error( 'invalid_key', __( 'Invalid key.' ) );
  2260 	}
  2349 	}
  2261 
  2350 
  2262 	$hash_is_correct = $wp_hasher->CheckPassword( $key, $pass_key );
  2351 	$hash_is_correct = $wp_hasher->CheckPassword( $key, $pass_key );
  2263 
  2352 
  2264 	if ( $hash_is_correct && $expiration_time && time() < $expiration_time ) {
  2353 	if ( $hash_is_correct && $expiration_time && time() < $expiration_time ) {
  2265 		return get_userdata( $row->ID );
  2354 		return get_userdata( $row->ID );
  2266 	} elseif ( $hash_is_correct && $expiration_time ) {
  2355 	} elseif ( $hash_is_correct && $expiration_time ) {
  2267 		// Key has an expiration time that's passed
  2356 		// Key has an expiration time that's passed
  2268 		return new WP_Error( 'expired_key', __( 'Invalid key' ) );
  2357 		return new WP_Error( 'expired_key', __( 'Invalid key.' ) );
  2269 	}
  2358 	}
  2270 
  2359 
  2271 	if ( hash_equals( $row->user_activation_key, $key ) || ( $hash_is_correct && ! $expiration_time ) ) {
  2360 	if ( hash_equals( $row->user_activation_key, $key ) || ( $hash_is_correct && ! $expiration_time ) ) {
  2272 		$return = new WP_Error( 'expired_key', __( 'Invalid key' ) );
  2361 		$return  = new WP_Error( 'expired_key', __( 'Invalid key.' ) );
  2273 		$user_id = $row->ID;
  2362 		$user_id = $row->ID;
  2274 
  2363 
  2275 		/**
  2364 		/**
  2276 		 * Filters the return value of check_password_reset_key() when an
  2365 		 * Filters the return value of check_password_reset_key() when an
  2277 		 * old-style key is used.
  2366 		 * old-style key is used.
  2284 		 * @param int      $user_id The matched user ID.
  2373 		 * @param int      $user_id The matched user ID.
  2285 		 */
  2374 		 */
  2286 		return apply_filters( 'password_reset_key_expired', $return, $user_id );
  2375 		return apply_filters( 'password_reset_key_expired', $return, $user_id );
  2287 	}
  2376 	}
  2288 
  2377 
  2289 	return new WP_Error( 'invalid_key', __( 'Invalid key' ) );
  2378 	return new WP_Error( 'invalid_key', __( 'Invalid key.' ) );
  2290 }
  2379 }
  2291 
  2380 
  2292 /**
  2381 /**
  2293  * Handles resetting the user's password.
  2382  * Handles resetting the user's password.
  2294  *
  2383  *
  2400 	 * @param string   $sanitized_user_login User's username after it has been sanitized.
  2489 	 * @param string   $sanitized_user_login User's username after it has been sanitized.
  2401 	 * @param string   $user_email           User's email.
  2490 	 * @param string   $user_email           User's email.
  2402 	 */
  2491 	 */
  2403 	$errors = apply_filters( 'registration_errors', $errors, $sanitized_user_login, $user_email );
  2492 	$errors = apply_filters( 'registration_errors', $errors, $sanitized_user_login, $user_email );
  2404 
  2493 
  2405 	if ( $errors->get_error_code() )
  2494 	if ( $errors->has_errors() ) {
  2406 		return $errors;
  2495 		return $errors;
       
  2496 	}
  2407 
  2497 
  2408 	$user_pass = wp_generate_password( 12, false );
  2498 	$user_pass = wp_generate_password( 12, false );
  2409 	$user_id = wp_create_user( $sanitized_user_login, $user_pass, $user_email );
  2499 	$user_id   = wp_create_user( $sanitized_user_login, $user_pass, $user_email );
  2410 	if ( ! $user_id || is_wp_error( $user_id ) ) {
  2500 	if ( ! $user_id || is_wp_error( $user_id ) ) {
  2411 		$errors->add( 'registerfail', sprintf( __( '<strong>ERROR</strong>: Couldn&#8217;t register you&hellip; please contact the <a href="mailto:%s">webmaster</a> !' ), get_option( 'admin_email' ) ) );
  2501 		$errors->add( 'registerfail', sprintf( __( '<strong>ERROR</strong>: Couldn&#8217;t register you&hellip; please contact the <a href="mailto:%s">webmaster</a> !' ), get_option( 'admin_email' ) ) );
  2412 		return $errors;
  2502 		return $errors;
  2413 	}
  2503 	}
  2414 
  2504 
  2527 		restore_current_blog();
  2617 		restore_current_blog();
  2528 	} else {
  2618 	} else {
  2529 		$role_names = wp_roles()->get_names();
  2619 		$role_names = wp_roles()->get_names();
  2530 	}
  2620 	}
  2531 
  2621 
  2532 	$regex  = implode( '|', array_keys( $role_names ) );
  2622 	$regex = implode( '|', array_keys( $role_names ) );
  2533 	$regex  = preg_replace( '/[^a-zA-Z_\|-]/', '', $regex );
  2623 	$regex = preg_replace( '/[^a-zA-Z_\|-]/', '', $regex );
  2534 	$users  = $wpdb->get_col( $wpdb->prepare( "
  2624 	$users = $wpdb->get_col(
       
  2625 		$wpdb->prepare(
       
  2626 			"
  2535 		SELECT user_id
  2627 		SELECT user_id
  2536 		FROM $wpdb->usermeta
  2628 		FROM $wpdb->usermeta
  2537 		WHERE meta_key = '{$prefix}capabilities'
  2629 		WHERE meta_key = '{$prefix}capabilities'
  2538 		AND meta_value NOT REGEXP %s
  2630 		AND meta_value NOT REGEXP %s
  2539 	", $regex ) );
  2631 	",
       
  2632 			$regex
       
  2633 		)
       
  2634 	);
  2540 
  2635 
  2541 	return $users;
  2636 	return $users;
  2542 }
  2637 }
  2543 
  2638 
  2544 /**
  2639 /**
  2568 			return $current_user;
  2663 			return $current_user;
  2569 		}
  2664 		}
  2570 
  2665 
  2571 		// Upgrade stdClass to WP_User
  2666 		// Upgrade stdClass to WP_User
  2572 		if ( is_object( $current_user ) && isset( $current_user->ID ) ) {
  2667 		if ( is_object( $current_user ) && isset( $current_user->ID ) ) {
  2573 			$cur_id = $current_user->ID;
  2668 			$cur_id       = $current_user->ID;
  2574 			$current_user = null;
  2669 			$current_user = null;
  2575 			wp_set_current_user( $cur_id );
  2670 			wp_set_current_user( $cur_id );
  2576 			return $current_user;
  2671 			return $current_user;
  2577 		}
  2672 		}
  2578 
  2673 
  2580 		$current_user = null;
  2675 		$current_user = null;
  2581 		wp_set_current_user( 0 );
  2676 		wp_set_current_user( 0 );
  2582 		return $current_user;
  2677 		return $current_user;
  2583 	}
  2678 	}
  2584 
  2679 
  2585 	if ( defined('XMLRPC_REQUEST') && XMLRPC_REQUEST ) {
  2680 	if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
  2586 		wp_set_current_user( 0 );
  2681 		wp_set_current_user( 0 );
  2587 		return $current_user;
  2682 		return $current_user;
  2588 	}
  2683 	}
  2589 
  2684 
  2590 	/**
  2685 	/**
  2616  *
  2711  *
  2617  * @since 3.0.0
  2712  * @since 3.0.0
  2618  * @since 4.9.0 This function was moved from wp-admin/includes/ms.php so it's no longer Multisite specific.
  2713  * @since 4.9.0 This function was moved from wp-admin/includes/ms.php so it's no longer Multisite specific.
  2619  *
  2714  *
  2620  * @global WP_Error $errors WP_Error object.
  2715  * @global WP_Error $errors WP_Error object.
  2621  * @global wpdb     $wpdb   WordPress database object.
       
  2622  */
  2716  */
  2623 function send_confirmation_on_profile_email() {
  2717 function send_confirmation_on_profile_email() {
  2624 	global $errors, $wpdb;
  2718 	global $errors;
  2625 
  2719 
  2626 	$current_user = wp_get_current_user();
  2720 	$current_user = wp_get_current_user();
  2627 	if ( ! is_object( $errors ) ) {
  2721 	if ( ! is_object( $errors ) ) {
  2628 		$errors = new WP_Error();
  2722 		$errors = new WP_Error();
  2629 	}
  2723 	}
  2632 		return false;
  2726 		return false;
  2633 	}
  2727 	}
  2634 
  2728 
  2635 	if ( $current_user->user_email != $_POST['email'] ) {
  2729 	if ( $current_user->user_email != $_POST['email'] ) {
  2636 		if ( ! is_email( $_POST['email'] ) ) {
  2730 		if ( ! is_email( $_POST['email'] ) ) {
  2637 			$errors->add( 'user_email', __( "<strong>ERROR</strong>: The email address isn&#8217;t correct." ), array(
  2731 			$errors->add(
  2638 				'form-field' => 'email',
  2732 				'user_email',
  2639 			) );
  2733 				__( '<strong>ERROR</strong>: The email address isn&#8217;t correct.' ),
       
  2734 				array(
       
  2735 					'form-field' => 'email',
       
  2736 				)
       
  2737 			);
  2640 
  2738 
  2641 			return;
  2739 			return;
  2642 		}
  2740 		}
  2643 
  2741 
  2644 		if ( $wpdb->get_var( $wpdb->prepare( "SELECT user_email FROM {$wpdb->users} WHERE user_email=%s", $_POST['email'] ) ) ) {
  2742 		if ( email_exists( $_POST['email'] ) ) {
  2645 			$errors->add( 'user_email', __( "<strong>ERROR</strong>: The email address is already used." ), array(
  2743 			$errors->add(
  2646 				'form-field' => 'email',
  2744 				'user_email',
  2647 			) );
  2745 				__( '<strong>ERROR</strong>: The email address is already used.' ),
       
  2746 				array(
       
  2747 					'form-field' => 'email',
       
  2748 				)
       
  2749 			);
  2648 			delete_user_meta( $current_user->ID, '_new_email' );
  2750 			delete_user_meta( $current_user->ID, '_new_email' );
  2649 
  2751 
  2650 			return;
  2752 			return;
  2651 		}
  2753 		}
  2652 
  2754 
  2658 		update_user_meta( $current_user->ID, '_new_email', $new_user_email );
  2760 		update_user_meta( $current_user->ID, '_new_email', $new_user_email );
  2659 
  2761 
  2660 		$sitename = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
  2762 		$sitename = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
  2661 
  2763 
  2662 		/* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
  2764 		/* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
  2663 		$email_text = __( 'Howdy ###USERNAME###,
  2765 		$email_text = __(
       
  2766 			'Howdy ###USERNAME###,
  2664 
  2767 
  2665 You recently requested to have the email address on your account changed.
  2768 You recently requested to have the email address on your account changed.
  2666 
  2769 
  2667 If this is correct, please click on the following link to change it:
  2770 If this is correct, please click on the following link to change it:
  2668 ###ADMIN_URL###
  2771 ###ADMIN_URL###
  2672 
  2775 
  2673 This email has been sent to ###EMAIL###
  2776 This email has been sent to ###EMAIL###
  2674 
  2777 
  2675 Regards,
  2778 Regards,
  2676 All at ###SITENAME###
  2779 All at ###SITENAME###
  2677 ###SITEURL###' );
  2780 ###SITEURL###'
       
  2781 		);
  2678 
  2782 
  2679 		/**
  2783 		/**
  2680 		 * Filters the text of the email sent when a change of user email address is attempted.
  2784 		 * Filters the text of the email sent when a change of user email address is attempted.
  2681 		 *
  2785 		 *
  2682 		 * The following strings have a special meaning and will get replaced dynamically:
  2786 		 * The following strings have a special meaning and will get replaced dynamically:
  2703 		$content = str_replace( '###ADMIN_URL###', esc_url( admin_url( 'profile.php?newuseremail=' . $hash ) ), $content );
  2807 		$content = str_replace( '###ADMIN_URL###', esc_url( admin_url( 'profile.php?newuseremail=' . $hash ) ), $content );
  2704 		$content = str_replace( '###EMAIL###', $_POST['email'], $content );
  2808 		$content = str_replace( '###EMAIL###', $_POST['email'], $content );
  2705 		$content = str_replace( '###SITENAME###', $sitename, $content );
  2809 		$content = str_replace( '###SITENAME###', $sitename, $content );
  2706 		$content = str_replace( '###SITEURL###', home_url(), $content );
  2810 		$content = str_replace( '###SITEURL###', home_url(), $content );
  2707 
  2811 
  2708 		wp_mail( $_POST['email'], sprintf( __( '[%s] New Email Address' ), $sitename ), $content );
  2812 		/* translators: New email address notification email subject. %s: Site name */
       
  2813 		wp_mail( $_POST['email'], sprintf( __( '[%s] Email Change Request' ), $sitename ), $content );
  2709 
  2814 
  2710 		$_POST['email'] = $current_user->user_email;
  2815 		$_POST['email'] = $current_user->user_email;
  2711 	}
  2816 	}
  2712 }
  2817 }
  2713 
  2818 
  2720  *
  2825  *
  2721  * @global string $pagenow
  2826  * @global string $pagenow
  2722  */
  2827  */
  2723 function new_user_email_admin_notice() {
  2828 function new_user_email_admin_notice() {
  2724 	global $pagenow;
  2829 	global $pagenow;
  2725 	if ( 'profile.php' === $pagenow && isset( $_GET['updated'] ) && $email = get_user_meta( get_current_user_id(), '_new_email', true ) ) {
  2830 
  2726 		/* translators: %s: New email address */
  2831 	if ( 'profile.php' === $pagenow && isset( $_GET['updated'] ) ) {
  2727 		echo '<div class="notice notice-info"><p>' . sprintf( __( 'Your email address has not been updated yet. Please check your inbox at %s for a confirmation email.' ), '<code>' . esc_html( $email['newemail'] ) . '</code>' ) . '</p></div>';
  2832 		$email = get_user_meta( get_current_user_id(), '_new_email', true );
       
  2833 		if ( $email ) {
       
  2834 			/* translators: %s: New email address */
       
  2835 			echo '<div class="notice notice-info"><p>' . sprintf( __( 'Your email address has not been updated yet. Please check your inbox at %s for a confirmation email.' ), '<code>' . esc_html( $email['newemail'] ) . '</code>' ) . '</p></div>';
       
  2836 		}
  2728 	}
  2837 	}
  2729 }
  2838 }
  2730 
  2839 
  2731 /**
  2840 /**
  2732  * Get all user privacy request types.
  2841  * Get all user privacy request types.
  2849  * @access private
  2958  * @access private
  2850  *
  2959  *
  2851  * @param int $request_id ID of the request.
  2960  * @param int $request_id ID of the request.
  2852  */
  2961  */
  2853 function _wp_privacy_account_request_confirmed( $request_id ) {
  2962 function _wp_privacy_account_request_confirmed( $request_id ) {
  2854 	$request_data = wp_get_user_request_data( $request_id );
  2963 	$request = wp_get_user_request_data( $request_id );
  2855 
  2964 
  2856 	if ( ! $request_data ) {
  2965 	if ( ! $request ) {
  2857 		return;
  2966 		return;
  2858 	}
  2967 	}
  2859 
  2968 
  2860 	if ( ! in_array( $request_data->status, array( 'request-pending', 'request-failed' ), true ) ) {
  2969 	if ( ! in_array( $request->status, array( 'request-pending', 'request-failed' ), true ) ) {
  2861 		return;
  2970 		return;
  2862 	}
  2971 	}
  2863 
  2972 
  2864 	update_post_meta( $request_id, '_wp_user_request_confirmed_timestamp', time() );
  2973 	update_post_meta( $request_id, '_wp_user_request_confirmed_timestamp', time() );
  2865 	wp_update_post( array(
  2974 	wp_update_post(
  2866 		'ID'          => $request_id,
  2975 		array(
  2867 		'post_status' => 'request-confirmed',
  2976 			'ID'          => $request_id,
  2868 	) );
  2977 			'post_status' => 'request-confirmed',
       
  2978 		)
       
  2979 	);
  2869 }
  2980 }
  2870 
  2981 
  2871 /**
  2982 /**
  2872  * Notify the site administrator via email when a request is confirmed.
  2983  * Notify the site administrator via email when a request is confirmed.
  2873  *
  2984  *
  2877  * @since 4.9.6
  2988  * @since 4.9.6
  2878  *
  2989  *
  2879  * @param int $request_id The ID of the request.
  2990  * @param int $request_id The ID of the request.
  2880  */
  2991  */
  2881 function _wp_privacy_send_request_confirmation_notification( $request_id ) {
  2992 function _wp_privacy_send_request_confirmation_notification( $request_id ) {
  2882 	$request_data = wp_get_user_request_data( $request_id );
  2993 	$request = wp_get_user_request_data( $request_id );
  2883 
  2994 
  2884 	if ( ! is_a( $request_data, 'WP_User_Request' ) || 'request-confirmed' !== $request_data->status ) {
  2995 	if ( ! is_a( $request, 'WP_User_Request' ) || 'request-confirmed' !== $request->status ) {
  2885 		return;
  2996 		return;
  2886 	}
  2997 	}
  2887 
  2998 
  2888 	$already_notified = (bool) get_post_meta( $request_id, '_wp_admin_notified', true );
  2999 	$already_notified = (bool) get_post_meta( $request_id, '_wp_admin_notified', true );
  2889 
  3000 
  2890 	if ( $already_notified ) {
  3001 	if ( $already_notified ) {
  2891 		return;
  3002 		return;
  2892 	}
  3003 	}
  2893 
  3004 
  2894 	$manage_url         = add_query_arg( 'page', $request_data->action_name, admin_url( 'tools.php' ) );
  3005 	$manage_url         = add_query_arg( 'page', $request->action_name, admin_url( 'tools.php' ) );
  2895 	$action_description = wp_user_request_action_description( $request_data->action_name );
  3006 	$action_description = wp_user_request_action_description( $request->action_name );
  2896 
  3007 
  2897 	/**
  3008 	/**
  2898 	 * Filters the recipient of the data request confirmation notification.
  3009 	 * Filters the recipient of the data request confirmation notification.
  2899 	 *
  3010 	 *
  2900 	 * In a Multisite environment, this will default to the email address of the
  3011 	 * In a Multisite environment, this will default to the email address of the
  2903 	 * delegate those capabilities to a single-site admin, or a dedicated person
  3014 	 * delegate those capabilities to a single-site admin, or a dedicated person
  2904 	 * responsible for managing privacy requests.
  3015 	 * responsible for managing privacy requests.
  2905 	 *
  3016 	 *
  2906 	 * @since 4.9.6
  3017 	 * @since 4.9.6
  2907 	 *
  3018 	 *
  2908 	 * @param string          $admin_email  The email address of the notification recipient.
  3019 	 * @param string          $admin_email The email address of the notification recipient.
  2909 	 * @param WP_User_Request $request_data The request that is initiating the notification.
  3020 	 * @param WP_User_Request $request     The request that is initiating the notification.
  2910 	 */
  3021 	 */
  2911 	$admin_email = apply_filters( 'user_request_confirmed_email_to', get_site_option( 'admin_email' ), $request_data );
  3022 	$admin_email = apply_filters( 'user_request_confirmed_email_to', get_site_option( 'admin_email' ), $request );
  2912 
  3023 
  2913 	$email_data = array(
  3024 	$email_data = array(
  2914 		'request'     => $request_data,
  3025 		'request'     => $request,
  2915 		'user_email'  => $request_data->email,
  3026 		'user_email'  => $request->email,
  2916 		'description' => $action_description,
  3027 		'description' => $action_description,
  2917 		'manage_url'  => $manage_url,
  3028 		'manage_url'  => $manage_url,
  2918 		'sitename'    => wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ),
  3029 		'sitename'    => wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ),
  2919 		'siteurl'     => home_url(),
  3030 		'siteurl'     => home_url(),
  2920 		'admin_email' => $admin_email,
  3031 		'admin_email' => $admin_email,
  2972 	$content = str_replace( '###DESCRIPTION###', $email_data['description'], $content );
  3083 	$content = str_replace( '###DESCRIPTION###', $email_data['description'], $content );
  2973 	$content = str_replace( '###MANAGE_URL###', esc_url_raw( $email_data['manage_url'] ), $content );
  3084 	$content = str_replace( '###MANAGE_URL###', esc_url_raw( $email_data['manage_url'] ), $content );
  2974 	$content = str_replace( '###SITEURL###', esc_url_raw( $email_data['siteurl'] ), $content );
  3085 	$content = str_replace( '###SITEURL###', esc_url_raw( $email_data['siteurl'] ), $content );
  2975 
  3086 
  2976 	$subject = sprintf(
  3087 	$subject = sprintf(
  2977 		/* translators: 1: Site name. 2: Name of the confirmed action. */
  3088 		/* translators: Privacy data request confirmed notification email subject. 1: Site title, 2: Name of the confirmed action. */
  2978 		__( '[%1$s] Action Confirmed: %2$s' ),
  3089 		__( '[%1$s] Action Confirmed: %2$s' ),
  2979 		$email_data['sitename'],
  3090 		$email_data['sitename'],
  2980 		$action_description
  3091 		$action_description
  2981 	);
  3092 	);
  2982 
  3093 
  3016  * @since 4.9.6
  3127  * @since 4.9.6
  3017  *
  3128  *
  3018  * @param int $request_id The privacy request post ID associated with this request.
  3129  * @param int $request_id The privacy request post ID associated with this request.
  3019  */
  3130  */
  3020 function _wp_privacy_send_erasure_fulfillment_notification( $request_id ) {
  3131 function _wp_privacy_send_erasure_fulfillment_notification( $request_id ) {
  3021 	$request_data = wp_get_user_request_data( $request_id );
  3132 	$request = wp_get_user_request_data( $request_id );
  3022 
  3133 
  3023 	if ( ! is_a( $request_data, 'WP_User_Request' ) || 'request-completed' !== $request_data->status ) {
  3134 	if ( ! is_a( $request, 'WP_User_Request' ) || 'request-completed' !== $request->status ) {
  3024 		return;
  3135 		return;
  3025 	}
  3136 	}
  3026 
  3137 
  3027 	$already_notified = (bool) get_post_meta( $request_id, '_wp_user_notified', true );
  3138 	$already_notified = (bool) get_post_meta( $request_id, '_wp_user_notified', true );
  3028 
  3139 
  3029 	if ( $already_notified ) {
  3140 	if ( $already_notified ) {
  3030 		return;
  3141 		return;
  3031 	}
  3142 	}
  3032 
  3143 
       
  3144 	// Localize message content for user; fallback to site default for visitors.
       
  3145 	if ( ! empty( $request->user_id ) ) {
       
  3146 		$locale = get_user_locale( $request->user_id );
       
  3147 	} else {
       
  3148 		$locale = get_locale();
       
  3149 	}
       
  3150 
       
  3151 	$switched_locale = switch_to_locale( $locale );
       
  3152 
  3033 	/**
  3153 	/**
  3034 	 * Filters the recipient of the data erasure fulfillment notification.
  3154 	 * Filters the recipient of the data erasure fulfillment notification.
  3035 	 *
  3155 	 *
  3036 	 * @since 4.9.6
  3156 	 * @since 4.9.6
  3037 	 *
  3157 	 *
  3038 	 * @param string          $user_email   The email address of the notification recipient.
  3158 	 * @param string          $user_email The email address of the notification recipient.
  3039 	 * @param WP_User_Request $request_data The request that is initiating the notification.
  3159 	 * @param WP_User_Request $request    The request that is initiating the notification.
  3040 	 */
  3160 	 */
  3041 	$user_email = apply_filters( 'user_erasure_fulfillment_email_to', $request_data->email, $request_data );
  3161 	$user_email = apply_filters( 'user_erasure_fulfillment_email_to', $request->email, $request );
  3042 
  3162 
  3043 	$email_data = array(
  3163 	$email_data = array(
  3044 		'request'            => $request_data,
  3164 		'request'            => $request,
  3045 		'message_recipient'  => $user_email,
  3165 		'message_recipient'  => $user_email,
  3046 		'privacy_policy_url' => get_privacy_policy_url(),
  3166 		'privacy_policy_url' => get_privacy_policy_url(),
  3047 		'sitename'           => wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ),
  3167 		'sitename'           => wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ),
  3048 		'siteurl'            => home_url(),
  3168 		'siteurl'            => home_url(),
  3049 	);
  3169 	);
  3050 
  3170 
  3051 	$subject  = sprintf(
  3171 	$subject = sprintf(
  3052 		/* translators: %s: Site name. */
  3172 		/* translators: Erasure request fulfilled notification email subject. %s: Site name. */
  3053 		__( '[%s] Erasure Request Fulfilled' ),
  3173 		__( '[%s] Erasure Request Fulfilled' ),
  3054 		$email_data['sitename']
  3174 		$email_data['sitename']
  3055 	);
  3175 	);
  3056 
  3176 
  3057 	/**
  3177 	/**
  3138 	$content = str_replace( '###PRIVACY_POLICY_URL###', $email_data['privacy_policy_url'], $content );
  3258 	$content = str_replace( '###PRIVACY_POLICY_URL###', $email_data['privacy_policy_url'], $content );
  3139 	$content = str_replace( '###SITEURL###', esc_url_raw( $email_data['siteurl'] ), $content );
  3259 	$content = str_replace( '###SITEURL###', esc_url_raw( $email_data['siteurl'] ), $content );
  3140 
  3260 
  3141 	$email_sent = wp_mail( $user_email, $subject, $content );
  3261 	$email_sent = wp_mail( $user_email, $subject, $content );
  3142 
  3262 
       
  3263 	if ( $switched_locale ) {
       
  3264 		restore_previous_locale();
       
  3265 	}
       
  3266 
  3143 	if ( $email_sent ) {
  3267 	if ( $email_sent ) {
  3144 		update_post_meta( $request_id, '_wp_user_notified', true );
  3268 		update_post_meta( $request_id, '_wp_user_notified', true );
  3145 	}
  3269 	}
  3146 }
  3270 }
  3147 
  3271 
  3155  * @return string $message The confirmation message.
  3279  * @return string $message The confirmation message.
  3156  */
  3280  */
  3157 function _wp_privacy_account_request_confirmed_message( $request_id ) {
  3281 function _wp_privacy_account_request_confirmed_message( $request_id ) {
  3158 	$request = wp_get_user_request_data( $request_id );
  3282 	$request = wp_get_user_request_data( $request_id );
  3159 
  3283 
  3160 	$message = '<p class="success">' . __( 'Action has been confirmed.' ) . '</p>';
  3284 	$message  = '<p class="success">' . __( 'Action has been confirmed.' ) . '</p>';
  3161 	$message .= '<p>' . __( 'The site administrator has been notified and will fulfill your request as soon as possible.' ) . '</p>';
  3285 	$message .= '<p>' . __( 'The site administrator has been notified and will fulfill your request as soon as possible.' ) . '</p>';
  3162 
  3286 
  3163 	if ( $request && in_array( $request->action_name, _wp_privacy_action_request_types(), true ) ) {
  3287 	if ( $request && in_array( $request->action_name, _wp_privacy_action_request_types(), true ) ) {
  3164 		if ( 'export_personal_data' === $request->action_name ) {
  3288 		if ( 'export_personal_data' === $request->action_name ) {
  3165 			$message = '<p class="success">' . __( 'Thanks for confirming your export request.' ) . '</p>';
  3289 			$message  = '<p class="success">' . __( 'Thanks for confirming your export request.' ) . '</p>';
  3166 			$message .= '<p>' . __( 'The site administrator has been notified. You will receive a link to download your export via email when they fulfill your request.' ) . '</p>';
  3290 			$message .= '<p>' . __( 'The site administrator has been notified. You will receive a link to download your export via email when they fulfill your request.' ) . '</p>';
  3167 		} elseif ( 'remove_personal_data' === $request->action_name ) {
  3291 		} elseif ( 'remove_personal_data' === $request->action_name ) {
  3168 			$message = '<p class="success">' . __( 'Thanks for confirming your erasure request.' ) . '</p>';
  3292 			$message  = '<p class="success">' . __( 'Thanks for confirming your erasure request.' ) . '</p>';
  3169 			$message .= '<p>' . __( 'The site administrator has been notified. You will receive an email confirmation when they erase your data.' ) . '</p>';
  3293 			$message .= '<p>' . __( 'The site administrator has been notified. You will receive an email confirmation when they erase your data.' ) . '</p>';
  3170 		}
  3294 		}
  3171 	}
  3295 	}
  3172 
  3296 
  3173 	/**
  3297 	/**
  3210 
  3334 
  3211 	$user    = get_user_by( 'email', $email_address );
  3335 	$user    = get_user_by( 'email', $email_address );
  3212 	$user_id = $user && ! is_wp_error( $user ) ? $user->ID : 0;
  3336 	$user_id = $user && ! is_wp_error( $user ) ? $user->ID : 0;
  3213 
  3337 
  3214 	// Check for duplicates.
  3338 	// Check for duplicates.
  3215 	$requests_query = new WP_Query( array(
  3339 	$requests_query = new WP_Query(
  3216 		'post_type'     => 'user_request',
  3340 		array(
  3217 		'post_name__in' => array( $action_name ),  // Action name stored in post_name column.
  3341 			'post_type'     => 'user_request',
  3218 		'title'         => $email_address, // Email address stored in post_title column.
  3342 			'post_name__in' => array( $action_name ),  // Action name stored in post_name column.
  3219 		'post_status'   => 'any',
  3343 			'title'         => $email_address, // Email address stored in post_title column.
  3220 		'fields'        => 'ids',
  3344 			'post_status'   => array(
  3221 	) );
  3345 				'request-pending',
       
  3346 				'request-confirmed',
       
  3347 			),
       
  3348 			'fields'        => 'ids',
       
  3349 		)
       
  3350 	);
  3222 
  3351 
  3223 	if ( $requests_query->found_posts ) {
  3352 	if ( $requests_query->found_posts ) {
  3224 		return new WP_Error( 'duplicate_request', __( 'A request for this email address already exists.' ) );
  3353 		return new WP_Error( 'duplicate_request', __( 'An incomplete request for this email address already exists.' ) );
  3225 	}
  3354 	}
  3226 
  3355 
  3227 	$request_id = wp_insert_post( array(
  3356 	$request_id = wp_insert_post(
  3228 		'post_author'   => $user_id,
  3357 		array(
  3229 		'post_name'     => $action_name,
  3358 			'post_author'   => $user_id,
  3230 		'post_title'    => $email_address,
  3359 			'post_name'     => $action_name,
  3231 		'post_content'  => wp_json_encode( $request_data ),
  3360 			'post_title'    => $email_address,
  3232 		'post_status'   => 'request-pending',
  3361 			'post_content'  => wp_json_encode( $request_data ),
  3233 		'post_type'     => 'user_request',
  3362 			'post_status'   => 'request-pending',
  3234 		'post_date'     => current_time( 'mysql', false ),
  3363 			'post_type'     => 'user_request',
  3235 		'post_date_gmt' => current_time( 'mysql', true ),
  3364 			'post_date'     => current_time( 'mysql', false ),
  3236 	), true );
  3365 			'post_date_gmt' => current_time( 'mysql', true ),
       
  3366 		),
       
  3367 		true
       
  3368 	);
  3237 
  3369 
  3238 	return $request_id;
  3370 	return $request_id;
  3239 }
  3371 }
  3240 
  3372 
  3241 /**
  3373 /**
  3277  * If the request is not already pending, it will be updated.
  3409  * If the request is not already pending, it will be updated.
  3278  *
  3410  *
  3279  * @since 4.9.6
  3411  * @since 4.9.6
  3280  *
  3412  *
  3281  * @param string $request_id ID of the request created via wp_create_user_request().
  3413  * @param string $request_id ID of the request created via wp_create_user_request().
  3282  * @return WP_Error|bool Will return true/false based on the success of sending the email, or a WP_Error object.
  3414  * @return bool|WP_Error True on success, `WP_Error` on failure.
  3283  */
  3415  */
  3284 function wp_send_user_request( $request_id ) {
  3416 function wp_send_user_request( $request_id ) {
  3285 	$request_id = absint( $request_id );
  3417 	$request_id = absint( $request_id );
  3286 	$request    = wp_get_user_request_data( $request_id );
  3418 	$request    = wp_get_user_request_data( $request_id );
  3287 
  3419 
  3288 	if ( ! $request ) {
  3420 	if ( ! $request ) {
  3289 		return new WP_Error( 'user_request_error', __( 'Invalid request.' ) );
  3421 		return new WP_Error( 'invalid_request', __( 'Invalid user request.' ) );
  3290 	}
  3422 	}
       
  3423 
       
  3424 	// Localize message content for user; fallback to site default for visitors.
       
  3425 	if ( ! empty( $request->user_id ) ) {
       
  3426 		$locale = get_user_locale( $request->user_id );
       
  3427 	} else {
       
  3428 		$locale = get_locale();
       
  3429 	}
       
  3430 
       
  3431 	$switched_locale = switch_to_locale( $locale );
  3291 
  3432 
  3292 	$email_data = array(
  3433 	$email_data = array(
  3293 		'request'     => $request,
  3434 		'request'     => $request,
  3294 		'email'       => $request->email,
  3435 		'email'       => $request->email,
  3295 		'description' => wp_user_request_action_description( $request->action_name ),
  3436 		'description' => wp_user_request_action_description( $request->action_name ),
  3296 		'confirm_url' => add_query_arg( array(
  3437 		'confirm_url' => add_query_arg(
  3297 			'action'      => 'confirmaction',
  3438 			array(
  3298 			'request_id'  => $request_id,
  3439 				'action'      => 'confirmaction',
  3299 			'confirm_key' => wp_generate_user_request_key( $request_id ),
  3440 				'request_id'  => $request_id,
  3300 		), wp_login_url() ),
  3441 				'confirm_key' => wp_generate_user_request_key( $request_id ),
       
  3442 			),
       
  3443 			wp_login_url()
       
  3444 		),
  3301 		'sitename'    => wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ),
  3445 		'sitename'    => wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ),
  3302 		'siteurl'     => home_url(),
  3446 		'siteurl'     => home_url(),
  3303 	);
  3447 	);
  3304 
  3448 
  3305 	/* translators: Do not translate DESCRIPTION, CONFIRM_URL, SITENAME, SITEURL: those are placeholders. */
  3449 	/* translators: Do not translate DESCRIPTION, CONFIRM_URL, SITENAME, SITEURL: those are placeholders. */
  3351 	$content = str_replace( '###CONFIRM_URL###', esc_url_raw( $email_data['confirm_url'] ), $content );
  3495 	$content = str_replace( '###CONFIRM_URL###', esc_url_raw( $email_data['confirm_url'] ), $content );
  3352 	$content = str_replace( '###EMAIL###', $email_data['email'], $content );
  3496 	$content = str_replace( '###EMAIL###', $email_data['email'], $content );
  3353 	$content = str_replace( '###SITENAME###', $email_data['sitename'], $content );
  3497 	$content = str_replace( '###SITENAME###', $email_data['sitename'], $content );
  3354 	$content = str_replace( '###SITEURL###', esc_url_raw( $email_data['siteurl'] ), $content );
  3498 	$content = str_replace( '###SITEURL###', esc_url_raw( $email_data['siteurl'] ), $content );
  3355 
  3499 
  3356 	/* translators: Privacy data request subject. 1: Site name, 2: Name of the action */
  3500 	/* translators: Confirm privacy data request notification email subject. 1: Site title, 2: Name of the action */
  3357 	$subject = sprintf( __( '[%1$s] Confirm Action: %2$s' ), $email_data['sitename'], $email_data['description'] );
  3501 	$subject = sprintf( __( '[%1$s] Confirm Action: %2$s' ), $email_data['sitename'], $email_data['description'] );
  3358 
  3502 
  3359 	/**
  3503 	/**
  3360 	 * Filters the subject of the email sent when an account action is attempted.
  3504 	 * Filters the subject of the email sent when an account action is attempted.
  3361 	 *
  3505 	 *
  3374 	 *     @type string          $siteurl     The site URL sending the mail.
  3518 	 *     @type string          $siteurl     The site URL sending the mail.
  3375 	 * }
  3519 	 * }
  3376 	 */
  3520 	 */
  3377 	$subject = apply_filters( 'user_request_action_email_subject', $subject, $email_data['sitename'], $email_data );
  3521 	$subject = apply_filters( 'user_request_action_email_subject', $subject, $email_data['sitename'], $email_data );
  3378 
  3522 
  3379 	return wp_mail( $email_data['email'], $subject, $content );
  3523 	$email_sent = wp_mail( $email_data['email'], $subject, $content );
       
  3524 
       
  3525 	if ( $switched_locale ) {
       
  3526 		restore_previous_locale();
       
  3527 	}
       
  3528 
       
  3529 	if ( ! $email_sent ) {
       
  3530 		return new WP_Error( 'privacy_email_error', __( 'Unable to send personal data export confirmation email.' ) );
       
  3531 	}
       
  3532 
       
  3533 	return true;
  3380 }
  3534 }
  3381 
  3535 
  3382 /**
  3536 /**
  3383  * Returns a confirmation key for a user action and stores the hashed version for future comparison.
  3537  * Returns a confirmation key for a user action and stores the hashed version for future comparison.
  3384  *
  3538  *
  3397 	if ( empty( $wp_hasher ) ) {
  3551 	if ( empty( $wp_hasher ) ) {
  3398 		require_once ABSPATH . WPINC . '/class-phpass.php';
  3552 		require_once ABSPATH . WPINC . '/class-phpass.php';
  3399 		$wp_hasher = new PasswordHash( 8, true );
  3553 		$wp_hasher = new PasswordHash( 8, true );
  3400 	}
  3554 	}
  3401 
  3555 
  3402 	wp_update_post( array(
  3556 	wp_update_post(
  3403 		'ID'                => $request_id,
  3557 		array(
  3404 		'post_status'       => 'request-pending',
  3558 			'ID'            => $request_id,
  3405 		'post_password'     => $wp_hasher->HashPassword( $key ),
  3559 			'post_status'   => 'request-pending',
  3406 		'post_modified'     => current_time( 'mysql', false ),
  3560 			'post_password' => $wp_hasher->HashPassword( $key ),
  3407 		'post_modified_gmt' => current_time( 'mysql', true ),
  3561 		)
  3408 	) );
  3562 	);
  3409 
  3563 
  3410 	return $key;
  3564 	return $key;
  3411 }
  3565 }
  3412 
  3566 
  3413 /**
  3567 /**
  3424 
  3578 
  3425 	$request_id = absint( $request_id );
  3579 	$request_id = absint( $request_id );
  3426 	$request    = wp_get_user_request_data( $request_id );
  3580 	$request    = wp_get_user_request_data( $request_id );
  3427 
  3581 
  3428 	if ( ! $request ) {
  3582 	if ( ! $request ) {
  3429 		return new WP_Error( 'user_request_error', __( 'Invalid request.' ) );
  3583 		return new WP_Error( 'invalid_request', __( 'Invalid request.' ) );
  3430 	}
  3584 	}
  3431 
  3585 
  3432 	if ( ! in_array( $request->status, array( 'request-pending', 'request-failed' ), true ) ) {
  3586 	if ( ! in_array( $request->status, array( 'request-pending', 'request-failed' ), true ) ) {
  3433 		return __( 'This link has expired.' );
  3587 		return new WP_Error( 'expired_link', __( 'This link has expired.' ) );
  3434 	}
  3588 	}
  3435 
  3589 
  3436 	if ( empty( $key ) ) {
  3590 	if ( empty( $key ) ) {
  3437 		return new WP_Error( 'invalid_key', __( 'Invalid key' ) );
  3591 		return new WP_Error( 'missing_key', __( 'Missing confirm key.' ) );
  3438 	}
  3592 	}
  3439 
  3593 
  3440 	if ( empty( $wp_hasher ) ) {
  3594 	if ( empty( $wp_hasher ) ) {
  3441 		require_once ABSPATH . WPINC . '/class-phpass.php';
  3595 		require_once ABSPATH . WPINC . '/class-phpass.php';
  3442 		$wp_hasher = new PasswordHash( 8, true );
  3596 		$wp_hasher = new PasswordHash( 8, true );
  3444 
  3598 
  3445 	$key_request_time = $request->modified_timestamp;
  3599 	$key_request_time = $request->modified_timestamp;
  3446 	$saved_key        = $request->confirm_key;
  3600 	$saved_key        = $request->confirm_key;
  3447 
  3601 
  3448 	if ( ! $saved_key ) {
  3602 	if ( ! $saved_key ) {
  3449 		return new WP_Error( 'invalid_key', __( 'Invalid key' ) );
  3603 		return new WP_Error( 'invalid_key', __( 'Invalid key.' ) );
  3450 	}
  3604 	}
  3451 
  3605 
  3452 	if ( ! $key_request_time ) {
  3606 	if ( ! $key_request_time ) {
  3453 		return new WP_Error( 'invalid_key', __( 'Invalid action' ) );
  3607 		return new WP_Error( 'invalid_key', __( 'Invalid action.' ) );
  3454 	}
  3608 	}
  3455 
  3609 
  3456 	/**
  3610 	/**
  3457 	 * Filters the expiration time of confirm keys.
  3611 	 * Filters the expiration time of confirm keys.
  3458 	 *
  3612 	 *
  3462 	 */
  3616 	 */
  3463 	$expiration_duration = (int) apply_filters( 'user_request_key_expiration', DAY_IN_SECONDS );
  3617 	$expiration_duration = (int) apply_filters( 'user_request_key_expiration', DAY_IN_SECONDS );
  3464 	$expiration_time     = $key_request_time + $expiration_duration;
  3618 	$expiration_time     = $key_request_time + $expiration_duration;
  3465 
  3619 
  3466 	if ( ! $wp_hasher->CheckPassword( $key, $saved_key ) ) {
  3620 	if ( ! $wp_hasher->CheckPassword( $key, $saved_key ) ) {
  3467 		return new WP_Error( 'invalid_key', __( 'Invalid key' ) );
  3621 		return new WP_Error( 'invalid_key', __( 'Invalid key.' ) );
  3468 	}
  3622 	}
  3469 
  3623 
  3470 	if ( ! $expiration_time || time() > $expiration_time ) {
  3624 	if ( ! $expiration_time || time() > $expiration_time ) {
  3471 		return new WP_Error( 'expired_key', __( 'The confirmation email has expired.' ) );
  3625 		return new WP_Error( 'expired_key', __( 'The confirmation email has expired.' ) );
  3472 	}
  3626 	}
  3511 	/**
  3665 	/**
  3512 	 * User ID.
  3666 	 * User ID.
  3513 	 *
  3667 	 *
  3514 	 * @var int
  3668 	 * @var int
  3515 	 */
  3669 	 */
  3516 
       
  3517 	public $user_id = 0;
  3670 	public $user_id = 0;
  3518 
  3671 
  3519 	/**
  3672 	/**
  3520 	 * User email.
  3673 	 * User email.
  3521 	 *
  3674 	 *