wp/wp-includes/user.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
    23  * with wp_signon(), wp_set_current_user() should be called explicitly.
    23  * with wp_signon(), wp_set_current_user() should be called explicitly.
    24  *
    24  *
    25  * @since 2.5.0
    25  * @since 2.5.0
    26  *
    26  *
    27  * @global string $auth_secure_cookie
    27  * @global string $auth_secure_cookie
    28  *
    28  * @global wpdb   $wpdb               WordPress database abstraction object.
    29  * @param array       $credentials   Optional. User info in order to sign on.
    29  *
       
    30  * @param array       $credentials {
       
    31  *     Optional. User info in order to sign on.
       
    32  *
       
    33  *     @type string $user_login    Username.
       
    34  *     @type string $user_password User password.
       
    35  *     @type bool   $remember      Whether to 'remember' the user. Increases the time
       
    36  *                                 that the cookie will be kept. Default false.
       
    37  * }
    30  * @param string|bool $secure_cookie Optional. Whether to use secure cookie.
    38  * @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.
    39  * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
    32  */
    40  */
    33 function wp_signon( $credentials = array(), $secure_cookie = '' ) {
    41 function wp_signon( $credentials = array(), $secure_cookie = '' ) {
       
    42 	global $auth_secure_cookie, $wpdb;
       
    43 
    34 	if ( empty( $credentials ) ) {
    44 	if ( empty( $credentials ) ) {
    35 		$credentials = array(); // Back-compat for plugins passing an empty string.
    45 		$credentials = array(
       
    46 			'user_login'    => '',
       
    47 			'user_password' => '',
       
    48 			'remember'      => false,
       
    49 		);
    36 
    50 
    37 		if ( ! empty( $_POST['log'] ) ) {
    51 		if ( ! empty( $_POST['log'] ) ) {
    38 			$credentials['user_login'] = wp_unslash( $_POST['log'] );
    52 			$credentials['user_login'] = wp_unslash( $_POST['log'] );
    39 		}
    53 		}
    40 		if ( ! empty( $_POST['pwd'] ) ) {
    54 		if ( ! empty( $_POST['pwd'] ) ) {
    85 	 *                                 that the cookie will be kept. Default false.
    99 	 *                                 that the cookie will be kept. Default false.
    86 	 * }
   100 	 * }
    87 	 */
   101 	 */
    88 	$secure_cookie = apply_filters( 'secure_signon_cookie', $secure_cookie, $credentials );
   102 	$secure_cookie = apply_filters( 'secure_signon_cookie', $secure_cookie, $credentials );
    89 
   103 
    90 	global $auth_secure_cookie; // XXX ugly hack to pass this to wp_authenticate_cookie().
   104 	// XXX ugly hack to pass this to wp_authenticate_cookie().
    91 	$auth_secure_cookie = $secure_cookie;
   105 	$auth_secure_cookie = $secure_cookie;
    92 
   106 
    93 	add_filter( 'authenticate', 'wp_authenticate_cookie', 30, 3 );
   107 	add_filter( 'authenticate', 'wp_authenticate_cookie', 30, 3 );
    94 
   108 
    95 	$user = wp_authenticate( $credentials['user_login'], $credentials['user_password'] );
   109 	$user = wp_authenticate( $credentials['user_login'], $credentials['user_password'] );
    97 	if ( is_wp_error( $user ) ) {
   111 	if ( is_wp_error( $user ) ) {
    98 		return $user;
   112 		return $user;
    99 	}
   113 	}
   100 
   114 
   101 	wp_set_auth_cookie( $user->ID, $credentials['remember'], $secure_cookie );
   115 	wp_set_auth_cookie( $user->ID, $credentials['remember'], $secure_cookie );
       
   116 
       
   117 	// Clear `user_activation_key` after a successful login.
       
   118 	if ( ! empty( $user->user_activation_key ) ) {
       
   119 		$wpdb->update(
       
   120 			$wpdb->users,
       
   121 			array(
       
   122 				'user_activation_key' => '',
       
   123 			),
       
   124 			array( 'ID' => $user->ID )
       
   125 		);
       
   126 
       
   127 		$user->user_activation_key = '';
       
   128 	}
       
   129 
   102 	/**
   130 	/**
   103 	 * Fires after the user has successfully logged in.
   131 	 * Fires after the user has successfully logged in.
   104 	 *
   132 	 *
   105 	 * @since 1.5.0
   133 	 * @since 1.5.0
   106 	 *
   134 	 *
   107 	 * @param string  $user_login Username.
   135 	 * @param string  $user_login Username.
   108 	 * @param WP_User $user       WP_User object of the logged-in user.
   136 	 * @param WP_User $user       WP_User object of the logged-in user.
   109 	 */
   137 	 */
   110 	do_action( 'wp_login', $user->user_login, $user );
   138 	do_action( 'wp_login', $user->user_login, $user );
       
   139 
   111 	return $user;
   140 	return $user;
   112 }
   141 }
   113 
   142 
   114 /**
   143 /**
   115  * Authenticates a user, confirming the username and password are valid.
   144  * Authenticates a user, confirming the username and password are valid.
   132 		}
   161 		}
   133 
   162 
   134 		$error = new WP_Error();
   163 		$error = new WP_Error();
   135 
   164 
   136 		if ( empty( $username ) ) {
   165 		if ( empty( $username ) ) {
   137 			$error->add( 'empty_username', __( '<strong>Error</strong>: The username field is empty.' ) );
   166 			$error->add( 'empty_username', __( '<strong>Error:</strong> The username field is empty.' ) );
   138 		}
   167 		}
   139 
   168 
   140 		if ( empty( $password ) ) {
   169 		if ( empty( $password ) ) {
   141 			$error->add( 'empty_password', __( '<strong>Error</strong>: The password field is empty.' ) );
   170 			$error->add( 'empty_password', __( '<strong>Error:</strong> The password field is empty.' ) );
   142 		}
   171 		}
   143 
   172 
   144 		return $error;
   173 		return $error;
   145 	}
   174 	}
   146 
   175 
   149 	if ( ! $user ) {
   178 	if ( ! $user ) {
   150 		return new WP_Error(
   179 		return new WP_Error(
   151 			'invalid_username',
   180 			'invalid_username',
   152 			sprintf(
   181 			sprintf(
   153 				/* translators: %s: User name. */
   182 				/* translators: %s: User name. */
   154 				__( '<strong>Error</strong>: The username <strong>%s</strong> is not registered on this site. If you are unsure of your username, try your email address instead.' ),
   183 				__( '<strong>Error:</strong> The username <strong>%s</strong> is not registered on this site. If you are unsure of your username, try your email address instead.' ),
   155 				$username
   184 				$username
   156 			)
   185 			)
   157 		);
   186 		);
   158 	}
   187 	}
   159 
   188 
   174 	if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
   203 	if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
   175 		return new WP_Error(
   204 		return new WP_Error(
   176 			'incorrect_password',
   205 			'incorrect_password',
   177 			sprintf(
   206 			sprintf(
   178 				/* translators: %s: User name. */
   207 				/* translators: %s: User name. */
   179 				__( '<strong>Error</strong>: The password you entered for the username %s is incorrect.' ),
   208 				__( '<strong>Error:</strong> The password you entered for the username %s is incorrect.' ),
   180 				'<strong>' . $username . '</strong>'
   209 				'<strong>' . $username . '</strong>'
   181 			) .
   210 			) .
   182 			' <a href="' . wp_lostpassword_url() . '">' .
   211 			' <a href="' . wp_lostpassword_url() . '">' .
   183 			__( 'Lost your password?' ) .
   212 			__( 'Lost your password?' ) .
   184 			'</a>'
   213 			'</a>'
   211 
   240 
   212 		$error = new WP_Error();
   241 		$error = new WP_Error();
   213 
   242 
   214 		if ( empty( $email ) ) {
   243 		if ( empty( $email ) ) {
   215 			// Uses 'empty_username' for back-compat with wp_signon().
   244 			// Uses 'empty_username' for back-compat with wp_signon().
   216 			$error->add( 'empty_username', __( '<strong>Error</strong>: The email field is empty.' ) );
   245 			$error->add( 'empty_username', __( '<strong>Error:</strong> The email field is empty.' ) );
   217 		}
   246 		}
   218 
   247 
   219 		if ( empty( $password ) ) {
   248 		if ( empty( $password ) ) {
   220 			$error->add( 'empty_password', __( '<strong>Error</strong>: The password field is empty.' ) );
   249 			$error->add( 'empty_password', __( '<strong>Error:</strong> The password field is empty.' ) );
   221 		}
   250 		}
   222 
   251 
   223 		return $error;
   252 		return $error;
   224 	}
   253 	}
   225 
   254 
   246 	if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
   275 	if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
   247 		return new WP_Error(
   276 		return new WP_Error(
   248 			'incorrect_password',
   277 			'incorrect_password',
   249 			sprintf(
   278 			sprintf(
   250 				/* translators: %s: Email address. */
   279 				/* translators: %s: Email address. */
   251 				__( '<strong>Error</strong>: The password you entered for the email address %s is incorrect.' ),
   280 				__( '<strong>Error:</strong> The password you entered for the email address %s is incorrect.' ),
   252 				'<strong>' . $email . '</strong>'
   281 				'<strong>' . $email . '</strong>'
   253 			) .
   282 			) .
   254 			' <a href="' . wp_lostpassword_url() . '">' .
   283 			' <a href="' . wp_lostpassword_url() . '">' .
   255 			__( 'Lost your password?' ) .
   284 			__( 'Lost your password?' ) .
   256 			'</a>'
   285 			'</a>'
   271  * @param string                $username Username. If not empty, cancels the cookie authentication.
   300  * @param string                $username Username. If not empty, cancels the cookie authentication.
   272  * @param string                $password Password. If not empty, cancels the cookie authentication.
   301  * @param string                $password Password. If not empty, cancels the cookie authentication.
   273  * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
   302  * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
   274  */
   303  */
   275 function wp_authenticate_cookie( $user, $username, $password ) {
   304 function wp_authenticate_cookie( $user, $username, $password ) {
       
   305 	global $auth_secure_cookie;
       
   306 
   276 	if ( $user instanceof WP_User ) {
   307 	if ( $user instanceof WP_User ) {
   277 		return $user;
   308 		return $user;
   278 	}
   309 	}
   279 
   310 
   280 	if ( empty( $username ) && empty( $password ) ) {
   311 	if ( empty( $username ) && empty( $password ) ) {
   281 		$user_id = wp_validate_auth_cookie();
   312 		$user_id = wp_validate_auth_cookie();
   282 		if ( $user_id ) {
   313 		if ( $user_id ) {
   283 			return new WP_User( $user_id );
   314 			return new WP_User( $user_id );
   284 		}
   315 		}
   285 
       
   286 		global $auth_secure_cookie;
       
   287 
   316 
   288 		if ( $auth_secure_cookie ) {
   317 		if ( $auth_secure_cookie ) {
   289 			$auth_cookie = SECURE_AUTH_COOKIE;
   318 			$auth_cookie = SECURE_AUTH_COOKIE;
   290 		} else {
   319 		} else {
   291 			$auth_cookie = AUTH_COOKIE;
   320 			$auth_cookie = AUTH_COOKIE;
   320 
   349 
   321 	if ( ! WP_Application_Passwords::is_in_use() ) {
   350 	if ( ! WP_Application_Passwords::is_in_use() ) {
   322 		return $input_user;
   351 		return $input_user;
   323 	}
   352 	}
   324 
   353 
       
   354 	// The 'REST_REQUEST' check here may happen too early for the constant to be available.
   325 	$is_api_request = ( ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) );
   355 	$is_api_request = ( ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) );
   326 
   356 
   327 	/**
   357 	/**
   328 	 * Filters whether this is an API request that Application Passwords can be used on.
   358 	 * Filters whether this is an API request that Application Passwords can be used on.
   329 	 *
   359 	 *
   349 	// If the login name is invalid, short circuit.
   379 	// If the login name is invalid, short circuit.
   350 	if ( ! $user ) {
   380 	if ( ! $user ) {
   351 		if ( is_email( $username ) ) {
   381 		if ( is_email( $username ) ) {
   352 			$error = new WP_Error(
   382 			$error = new WP_Error(
   353 				'invalid_email',
   383 				'invalid_email',
   354 				__( '<strong>Error</strong>: Unknown email address. Check again or try your username.' )
   384 				__( '<strong>Error:</strong> Unknown email address. Check again or try your username.' )
   355 			);
   385 			);
   356 		} else {
   386 		} else {
   357 			$error = new WP_Error(
   387 			$error = new WP_Error(
   358 				'invalid_username',
   388 				'invalid_username',
   359 				__( '<strong>Error</strong>: Unknown username. Check again or try your email address.' )
   389 				__( '<strong>Error:</strong> Unknown username. Check again or try your email address.' )
   360 			);
   390 			);
   361 		}
   391 		}
   362 	} elseif ( ! wp_is_application_passwords_available() ) {
   392 	} elseif ( ! wp_is_application_passwords_available() ) {
   363 		$error = new WP_Error(
   393 		$error = new WP_Error(
   364 			'application_passwords_disabled',
   394 			'application_passwords_disabled',
   501 		 * @param WP_User $user    User to check against.
   531 		 * @param WP_User $user    User to check against.
   502 		 */
   532 		 */
   503 		$spammed = apply_filters( 'check_is_user_spammed', is_user_spammy( $user ), $user );
   533 		$spammed = apply_filters( 'check_is_user_spammed', is_user_spammy( $user ), $user );
   504 
   534 
   505 		if ( $spammed ) {
   535 		if ( $spammed ) {
   506 			return new WP_Error( 'spammer_account', __( '<strong>Error</strong>: Your account has been marked as a spammer.' ) );
   536 			return new WP_Error( 'spammer_account', __( '<strong>Error:</strong> Your account has been marked as a spammer.' ) );
   507 		}
   537 		}
   508 	}
   538 	}
   509 	return $user;
   539 	return $user;
   510 }
   540 }
   511 
   541 
   689 
   719 
   690 /**
   720 /**
   691  * Updates user option with global blog capability.
   721  * Updates user option with global blog capability.
   692  *
   722  *
   693  * User options are just like user metadata except that they have support for
   723  * User options are just like user metadata except that they have support for
   694  * global blog options. If the 'global' parameter is false, which it is by default
   724  * global blog options. If the 'is_global' parameter is false, which it is by default,
   695  * it will prepend the WordPress table prefix to the option name.
   725  * it will prepend the WordPress table prefix to the option name.
   696  *
   726  *
   697  * Deletes the user option if $newvalue is empty.
   727  * Deletes the user option if $newvalue is empty.
   698  *
   728  *
   699  * @since 2.0.0
   729  * @since 2.0.0
   701  * @global wpdb $wpdb WordPress database abstraction object.
   731  * @global wpdb $wpdb WordPress database abstraction object.
   702  *
   732  *
   703  * @param int    $user_id     User ID.
   733  * @param int    $user_id     User ID.
   704  * @param string $option_name User option name.
   734  * @param string $option_name User option name.
   705  * @param mixed  $newvalue    User option value.
   735  * @param mixed  $newvalue    User option value.
   706  * @param bool   $global      Optional. Whether option name is global or blog specific.
   736  * @param bool   $is_global   Optional. Whether option name is global or blog specific.
   707  *                            Default false (blog specific).
   737  *                            Default false (blog specific).
   708  * @return int|bool User meta ID if the option didn't exist, true on successful update,
   738  * @return int|bool User meta ID if the option didn't exist, true on successful update,
   709  *                  false on failure.
   739  *                  false on failure.
   710  */
   740  */
   711 function update_user_option( $user_id, $option_name, $newvalue, $global = false ) {
   741 function update_user_option( $user_id, $option_name, $newvalue, $is_global = false ) {
   712 	global $wpdb;
   742 	global $wpdb;
   713 
   743 
   714 	if ( ! $global ) {
   744 	if ( ! $is_global ) {
   715 		$option_name = $wpdb->get_blog_prefix() . $option_name;
   745 		$option_name = $wpdb->get_blog_prefix() . $option_name;
   716 	}
   746 	}
   717 
   747 
   718 	return update_user_meta( $user_id, $option_name, $newvalue );
   748 	return update_user_meta( $user_id, $option_name, $newvalue );
   719 }
   749 }
   720 
   750 
   721 /**
   751 /**
   722  * Deletes user option with global blog capability.
   752  * Deletes user option with global blog capability.
   723  *
   753  *
   724  * User options are just like user metadata except that they have support for
   754  * User options are just like user metadata except that they have support for
   725  * global blog options. If the 'global' parameter is false, which it is by default
   755  * global blog options. If the 'is_global' parameter is false, which it is by default,
   726  * it will prepend the WordPress table prefix to the option name.
   756  * it will prepend the WordPress table prefix to the option name.
   727  *
   757  *
   728  * @since 3.0.0
   758  * @since 3.0.0
   729  *
   759  *
   730  * @global wpdb $wpdb WordPress database abstraction object.
   760  * @global wpdb $wpdb WordPress database abstraction object.
   731  *
   761  *
   732  * @param int    $user_id     User ID
   762  * @param int    $user_id     User ID
   733  * @param string $option_name User option name.
   763  * @param string $option_name User option name.
   734  * @param bool   $global      Optional. Whether option name is global or blog specific.
   764  * @param bool   $is_global   Optional. Whether option name is global or blog specific.
   735  *                            Default false (blog specific).
   765  *                            Default false (blog specific).
   736  * @return bool True on success, false on failure.
   766  * @return bool True on success, false on failure.
   737  */
   767  */
   738 function delete_user_option( $user_id, $option_name, $global = false ) {
   768 function delete_user_option( $user_id, $option_name, $is_global = false ) {
   739 	global $wpdb;
   769 	global $wpdb;
   740 
   770 
   741 	if ( ! $global ) {
   771 	if ( ! $is_global ) {
   742 		$option_name = $wpdb->get_blog_prefix() . $option_name;
   772 		$option_name = $wpdb->get_blog_prefix() . $option_name;
   743 	}
   773 	}
       
   774 
   744 	return delete_user_meta( $user_id, $option_name );
   775 	return delete_user_meta( $user_id, $option_name );
   745 }
   776 }
   746 
   777 
   747 /**
   778 /**
   748  * Retrieves list of users matching criteria.
   779  * Retrieves list of users matching criteria.
   809 		'html'          => true,
   840 		'html'          => true,
   810 		'exclude'       => '',
   841 		'exclude'       => '',
   811 		'include'       => '',
   842 		'include'       => '',
   812 	);
   843 	);
   813 
   844 
   814 	$args = wp_parse_args( $args, $defaults );
   845 	$parsed_args = wp_parse_args( $args, $defaults );
   815 
   846 
   816 	$return = '';
   847 	$return = '';
   817 
   848 
   818 	$query_args           = wp_array_slice_assoc( $args, array( 'orderby', 'order', 'number', 'exclude', 'include' ) );
   849 	$query_args           = wp_array_slice_assoc( $parsed_args, array( 'orderby', 'order', 'number', 'exclude', 'include' ) );
   819 	$query_args['fields'] = 'ids';
   850 	$query_args['fields'] = 'ids';
   820 	$users                = get_users( $query_args );
   851 
       
   852 	/**
       
   853 	 * Filters the query arguments for the list of all users of the site.
       
   854 	 *
       
   855 	 * @since 6.1.0
       
   856 	 *
       
   857 	 * @param array $query_args  The query arguments for get_users().
       
   858 	 * @param array $parsed_args The arguments passed to wp_list_users() combined with the defaults.
       
   859 	 */
       
   860 	$query_args = apply_filters( 'wp_list_users_args', $query_args, $parsed_args );
       
   861 
       
   862 	$users = get_users( $query_args );
   821 
   863 
   822 	foreach ( $users as $user_id ) {
   864 	foreach ( $users as $user_id ) {
   823 		$user = get_userdata( $user_id );
   865 		$user = get_userdata( $user_id );
   824 
   866 
   825 		if ( $args['exclude_admin'] && 'admin' === $user->display_name ) {
   867 		if ( $parsed_args['exclude_admin'] && 'admin' === $user->display_name ) {
   826 			continue;
   868 			continue;
   827 		}
   869 		}
   828 
   870 
   829 		if ( $args['show_fullname'] && '' !== $user->first_name && '' !== $user->last_name ) {
   871 		if ( $parsed_args['show_fullname'] && '' !== $user->first_name && '' !== $user->last_name ) {
   830 			$name = "$user->first_name $user->last_name";
   872 			$name = sprintf(
       
   873 				/* translators: 1: User's first name, 2: Last name. */
       
   874 				_x( '%1$s %2$s', 'Display name based on first name and last name' ),
       
   875 				$user->first_name,
       
   876 				$user->last_name
       
   877 			);
   831 		} else {
   878 		} else {
   832 			$name = $user->display_name;
   879 			$name = $user->display_name;
   833 		}
   880 		}
   834 
   881 
   835 		if ( ! $args['html'] ) {
   882 		if ( ! $parsed_args['html'] ) {
   836 			$return .= $name . ', ';
   883 			$return .= $name . ', ';
   837 
   884 
   838 			continue; // No need to go further to process HTML.
   885 			continue; // No need to go further to process HTML.
   839 		}
   886 		}
   840 
   887 
   841 		if ( 'list' === $args['style'] ) {
   888 		if ( 'list' === $parsed_args['style'] ) {
   842 			$return .= '<li>';
   889 			$return .= '<li>';
   843 		}
   890 		}
   844 
   891 
   845 		$row = $name;
   892 		$row = $name;
   846 
   893 
   847 		if ( ! empty( $args['feed_image'] ) || ! empty( $args['feed'] ) ) {
   894 		if ( ! empty( $parsed_args['feed_image'] ) || ! empty( $parsed_args['feed'] ) ) {
   848 			$row .= ' ';
   895 			$row .= ' ';
   849 			if ( empty( $args['feed_image'] ) ) {
   896 			if ( empty( $parsed_args['feed_image'] ) ) {
   850 				$row .= '(';
   897 				$row .= '(';
   851 			}
   898 			}
   852 
   899 
   853 			$row .= '<a href="' . get_author_feed_link( $user->ID, $args['feed_type'] ) . '"';
   900 			$row .= '<a href="' . get_author_feed_link( $user->ID, $parsed_args['feed_type'] ) . '"';
   854 
   901 
   855 			$alt = '';
   902 			$alt = '';
   856 			if ( ! empty( $args['feed'] ) ) {
   903 			if ( ! empty( $parsed_args['feed'] ) ) {
   857 				$alt  = ' alt="' . esc_attr( $args['feed'] ) . '"';
   904 				$alt  = ' alt="' . esc_attr( $parsed_args['feed'] ) . '"';
   858 				$name = $args['feed'];
   905 				$name = $parsed_args['feed'];
   859 			}
   906 			}
   860 
   907 
   861 			$row .= '>';
   908 			$row .= '>';
   862 
   909 
   863 			if ( ! empty( $args['feed_image'] ) ) {
   910 			if ( ! empty( $parsed_args['feed_image'] ) ) {
   864 				$row .= '<img src="' . esc_url( $args['feed_image'] ) . '" style="border: none;"' . $alt . ' />';
   911 				$row .= '<img src="' . esc_url( $parsed_args['feed_image'] ) . '" style="border: none;"' . $alt . ' />';
   865 			} else {
   912 			} else {
   866 				$row .= $name;
   913 				$row .= $name;
   867 			}
   914 			}
   868 
   915 
   869 			$row .= '</a>';
   916 			$row .= '</a>';
   870 
   917 
   871 			if ( empty( $args['feed_image'] ) ) {
   918 			if ( empty( $parsed_args['feed_image'] ) ) {
   872 				$row .= ')';
   919 				$row .= ')';
   873 			}
   920 			}
   874 		}
   921 		}
   875 
   922 
   876 		$return .= $row;
   923 		$return .= $row;
   877 		$return .= ( 'list' === $args['style'] ) ? '</li>' : ', ';
   924 		$return .= ( 'list' === $parsed_args['style'] ) ? '</li>' : ', ';
   878 	}
   925 	}
   879 
   926 
   880 	$return = rtrim( $return, ', ' );
   927 	$return = rtrim( $return, ', ' );
   881 
   928 
   882 	if ( ! $args['echo'] ) {
   929 	if ( ! $parsed_args['echo'] ) {
   883 		return $return;
   930 		return $return;
   884 	}
   931 	}
   885 	echo $return;
   932 	echo $return;
   886 }
   933 }
   887 
   934 
   933 		return array();
   980 		return array();
   934 	}
   981 	}
   935 
   982 
   936 	if ( ! is_multisite() ) {
   983 	if ( ! is_multisite() ) {
   937 		$site_id                        = get_current_blog_id();
   984 		$site_id                        = get_current_blog_id();
   938 		$sites                          = array( $site_id => new stdClass );
   985 		$sites                          = array( $site_id => new stdClass() );
   939 		$sites[ $site_id ]->userblog_id = $site_id;
   986 		$sites[ $site_id ]->userblog_id = $site_id;
   940 		$sites[ $site_id ]->blogname    = get_option( 'blogname' );
   987 		$sites[ $site_id ]->blogname    = get_option( 'blogname' );
   941 		$sites[ $site_id ]->domain      = '';
   988 		$sites[ $site_id ]->domain      = '';
   942 		$sites[ $site_id ]->path        = '';
   989 		$sites[ $site_id ]->path        = '';
   943 		$sites[ $site_id ]->site_id     = 1;
   990 		$sites[ $site_id ]->site_id     = 1;
   956 	}
  1003 	}
   957 
  1004 
   958 	$keys = array_keys( $keys );
  1005 	$keys = array_keys( $keys );
   959 
  1006 
   960 	foreach ( $keys as $key ) {
  1007 	foreach ( $keys as $key ) {
   961 		if ( 'capabilities' !== substr( $key, -12 ) ) {
  1008 		if ( ! str_ends_with( $key, 'capabilities' ) ) {
   962 			continue;
  1009 			continue;
   963 		}
  1010 		}
   964 		if ( $wpdb->base_prefix && 0 !== strpos( $key, $wpdb->base_prefix ) ) {
  1011 		if ( $wpdb->base_prefix && ! str_starts_with( $key, $wpdb->base_prefix ) ) {
   965 			continue;
  1012 			continue;
   966 		}
  1013 		}
   967 		$site_id = str_replace( array( $wpdb->base_prefix, '_capabilities' ), '', $key );
  1014 		$site_id = str_replace( array( $wpdb->base_prefix, '_capabilities' ), '', $key );
   968 		if ( ! is_numeric( $site_id ) ) {
  1015 		if ( ! is_numeric( $site_id ) ) {
   969 			continue;
  1016 			continue;
   974 
  1021 
   975 	$sites = array();
  1022 	$sites = array();
   976 
  1023 
   977 	if ( ! empty( $site_ids ) ) {
  1024 	if ( ! empty( $site_ids ) ) {
   978 		$args = array(
  1025 		$args = array(
   979 			'number'                 => '',
  1026 			'number'   => '',
   980 			'site__in'               => $site_ids,
  1027 			'site__in' => $site_ids,
   981 			'update_site_meta_cache' => false,
       
   982 		);
  1028 		);
   983 		if ( ! $all ) {
  1029 		if ( ! $all ) {
   984 			$args['archived'] = 0;
  1030 			$args['archived'] = 0;
   985 			$args['spam']     = 0;
  1031 			$args['spam']     = 0;
   986 			$args['deleted']  = 0;
  1032 			$args['deleted']  = 0;
  1036 
  1082 
  1037 	if ( empty( $user_id ) ) {
  1083 	if ( empty( $user_id ) ) {
  1038 		$user_id = get_current_user_id();
  1084 		$user_id = get_current_user_id();
  1039 	}
  1085 	}
  1040 
  1086 
  1041 	// Technically not needed, but does save calls to get_site() and get_user_meta()
  1087 	/*
  1042 	// in the event that the function is called when a user isn't logged in.
  1088 	 * Technically not needed, but does save calls to get_site() and get_user_meta()
       
  1089 	 * in the event that the function is called when a user isn't logged in.
       
  1090 	 */
  1043 	if ( empty( $user_id ) ) {
  1091 	if ( empty( $user_id ) ) {
  1044 		return false;
  1092 		return false;
  1045 	} else {
  1093 	} else {
  1046 		$user = get_userdata( $user_id );
  1094 		$user = get_userdata( $user_id );
  1047 		if ( ! $user instanceof WP_User ) {
  1095 		if ( ! $user instanceof WP_User ) {
  1070 
  1118 
  1071 	// No underscore before capabilities in $base_capabilities_key.
  1119 	// No underscore before capabilities in $base_capabilities_key.
  1072 	$base_capabilities_key = $wpdb->base_prefix . 'capabilities';
  1120 	$base_capabilities_key = $wpdb->base_prefix . 'capabilities';
  1073 	$site_capabilities_key = $wpdb->base_prefix . $blog_id . '_capabilities';
  1121 	$site_capabilities_key = $wpdb->base_prefix . $blog_id . '_capabilities';
  1074 
  1122 
  1075 	if ( isset( $keys[ $base_capabilities_key ] ) && 1 == $blog_id ) {
  1123 	if ( isset( $keys[ $base_capabilities_key ] ) && 1 === $blog_id ) {
  1076 		return true;
  1124 		return true;
  1077 	}
  1125 	}
  1078 
  1126 
  1079 	if ( isset( $keys[ $site_capabilities_key ] ) ) {
  1127 	if ( isset( $keys[ $site_capabilities_key ] ) ) {
  1080 		return true;
  1128 		return true;
  1206 	 *
  1254 	 *
  1207 	 * Return a non-null value to cause count_users() to return early.
  1255 	 * Return a non-null value to cause count_users() to return early.
  1208 	 *
  1256 	 *
  1209 	 * @since 5.1.0
  1257 	 * @since 5.1.0
  1210 	 *
  1258 	 *
  1211 	 * @param null|string $result   The value to return instead. Default null to continue with the query.
  1259 	 * @param null|array $result   The value to return instead. Default null to continue with the query.
  1212 	 * @param string      $strategy Optional. The computational strategy to use when counting the users.
  1260 	 * @param string     $strategy Optional. The computational strategy to use when counting the users.
  1213 	 *                              Accepts either 'time' or 'memory'. Default 'time'.
  1261 	 *                             Accepts either 'time' or 'memory'. Default 'time'.
  1214 	 * @param int|null    $site_id  Optional. The site ID to count users for. Defaults to the current site.
  1262 	 * @param int        $site_id  The site ID to count users for.
  1215 	 */
  1263 	 */
  1216 	$pre = apply_filters( 'pre_count_users', null, $strategy, $site_id );
  1264 	$pre = apply_filters( 'pre_count_users', null, $strategy, $site_id );
  1217 
  1265 
  1218 	if ( null !== $pre ) {
  1266 	if ( null !== $pre ) {
  1219 		return $pre;
  1267 		return $pre;
  1221 
  1269 
  1222 	$blog_prefix = $wpdb->get_blog_prefix( $site_id );
  1270 	$blog_prefix = $wpdb->get_blog_prefix( $site_id );
  1223 	$result      = array();
  1271 	$result      = array();
  1224 
  1272 
  1225 	if ( 'time' === $strategy ) {
  1273 	if ( 'time' === $strategy ) {
  1226 		if ( is_multisite() && get_current_blog_id() != $site_id ) {
  1274 		if ( is_multisite() && get_current_blog_id() !== $site_id ) {
  1227 			switch_to_blog( $site_id );
  1275 			switch_to_blog( $site_id );
  1228 			$avail_roles = wp_roles()->get_names();
  1276 			$avail_roles = wp_roles()->get_names();
  1229 			restore_current_blog();
  1277 			restore_current_blog();
  1230 		} else {
  1278 		} else {
  1231 			$avail_roles = wp_roles()->get_names();
  1279 			$avail_roles = wp_roles()->get_names();
  1285 			$b_roles = maybe_unserialize( $caps_meta );
  1333 			$b_roles = maybe_unserialize( $caps_meta );
  1286 			if ( ! is_array( $b_roles ) ) {
  1334 			if ( ! is_array( $b_roles ) ) {
  1287 				continue;
  1335 				continue;
  1288 			}
  1336 			}
  1289 			if ( empty( $b_roles ) ) {
  1337 			if ( empty( $b_roles ) ) {
  1290 				$avail_roles['none']++;
  1338 				++$avail_roles['none'];
  1291 			}
  1339 			}
  1292 			foreach ( $b_roles as $b_role => $val ) {
  1340 			foreach ( $b_roles as $b_role => $val ) {
  1293 				if ( isset( $avail_roles[ $b_role ] ) ) {
  1341 				if ( isset( $avail_roles[ $b_role ] ) ) {
  1294 					$avail_roles[ $b_role ]++;
  1342 					++$avail_roles[ $b_role ];
  1295 				} else {
  1343 				} else {
  1296 					$avail_roles[ $b_role ] = 1;
  1344 					$avail_roles[ $b_role ] = 1;
  1297 				}
  1345 				}
  1298 			}
  1346 			}
  1299 		}
  1347 		}
  1508  *
  1556  *
  1509  * The available arguments are as follows:
  1557  * The available arguments are as follows:
  1510  *
  1558  *
  1511  * @since 2.3.0
  1559  * @since 2.3.0
  1512  * @since 4.5.0 Added the 'display_name_with_login' value for 'show'.
  1560  * @since 4.5.0 Added the 'display_name_with_login' value for 'show'.
  1513  * @since 4.7.0 Added the `$role`, `$role__in`, and `$role__not_in` parameters.
  1561  * @since 4.7.0 Added the 'role', 'role__in', and 'role__not_in' parameters.
       
  1562  * @since 5.9.0 Added the 'capability', 'capability__in', and 'capability__not_in' parameters.
       
  1563  *              Deprecated the 'who' parameter.
  1514  *
  1564  *
  1515  * @param array|string $args {
  1565  * @param array|string $args {
  1516  *     Optional. Array or string of arguments to generate a drop-down of users.
  1566  *     Optional. Array or string of arguments to generate a drop-down of users.
  1517  *     See WP_User_Query::prepare_query() for additional available arguments.
  1567  *     See WP_User_Query::prepare_query() for additional available arguments.
  1518  *
  1568  *
  1519  *     @type string       $show_option_all         Text to show as the drop-down default (all).
  1569  *     @type string          $show_option_all         Text to show as the drop-down default (all).
  1520  *                                                 Default empty.
  1570  *                                                    Default empty.
  1521  *     @type string       $show_option_none        Text to show as the drop-down default when no
  1571  *     @type string          $show_option_none        Text to show as the drop-down default when no
  1522  *                                                 users were found. Default empty.
  1572  *                                                    users were found. Default empty.
  1523  *     @type int|string   $option_none_value       Value to use for $show_option_non when no users
  1573  *     @type int|string      $option_none_value       Value to use for `$show_option_none` when no users
  1524  *                                                 were found. Default -1.
  1574  *                                                    were found. Default -1.
  1525  *     @type string       $hide_if_only_one_author Whether to skip generating the drop-down
  1575  *     @type string          $hide_if_only_one_author Whether to skip generating the drop-down
  1526  *                                                 if only one user was found. Default empty.
  1576  *                                                    if only one user was found. Default empty.
  1527  *     @type string       $orderby                 Field to order found users by. Accepts user fields.
  1577  *     @type string          $orderby                 Field to order found users by. Accepts user fields.
  1528  *                                                 Default 'display_name'.
  1578  *                                                    Default 'display_name'.
  1529  *     @type string       $order                   Whether to order users in ascending or descending
  1579  *     @type string          $order                   Whether to order users in ascending or descending
  1530  *                                                 order. Accepts 'ASC' (ascending) or 'DESC' (descending).
  1580  *                                                    order. Accepts 'ASC' (ascending) or 'DESC' (descending).
  1531  *                                                 Default 'ASC'.
  1581  *                                                    Default 'ASC'.
  1532  *     @type int[]|string $include                 Array or comma-separated list of user IDs to include.
  1582  *     @type int[]|string    $include                 Array or comma-separated list of user IDs to include.
  1533  *                                                 Default empty.
  1583  *                                                    Default empty.
  1534  *     @type int[]|string $exclude                 Array or comma-separated list of user IDs to exclude.
  1584  *     @type int[]|string    $exclude                 Array or comma-separated list of user IDs to exclude.
  1535  *                                                 Default empty.
  1585  *                                                    Default empty.
  1536  *     @type bool|int     $multi                   Whether to skip the ID attribute on the 'select' element.
  1586  *     @type bool|int        $multi                   Whether to skip the ID attribute on the 'select' element.
  1537  *                                                 Accepts 1|true or 0|false. Default 0|false.
  1587  *                                                    Accepts 1|true or 0|false. Default 0|false.
  1538  *     @type string       $show                    User data to display. If the selected item is empty
  1588  *     @type string          $show                    User data to display. If the selected item is empty
  1539  *                                                 then the 'user_login' will be displayed in parentheses.
  1589  *                                                    then the 'user_login' will be displayed in parentheses.
  1540  *                                                 Accepts any user field, or 'display_name_with_login' to show
  1590  *                                                    Accepts any user field, or 'display_name_with_login' to show
  1541  *                                                 the display name with user_login in parentheses.
  1591  *                                                    the display name with user_login in parentheses.
  1542  *                                                 Default 'display_name'.
  1592  *                                                    Default 'display_name'.
  1543  *     @type int|bool     $echo                    Whether to echo or return the drop-down. Accepts 1|true (echo)
  1593  *     @type int|bool        $echo                    Whether to echo or return the drop-down. Accepts 1|true (echo)
  1544  *                                                 or 0|false (return). Default 1|true.
  1594  *                                                    or 0|false (return). Default 1|true.
  1545  *     @type int          $selected                Which user ID should be selected. Default 0.
  1595  *     @type int             $selected                Which user ID should be selected. Default 0.
  1546  *     @type bool         $include_selected        Whether to always include the selected user ID in the drop-
  1596  *     @type bool            $include_selected        Whether to always include the selected user ID in the drop-
  1547  *                                                 down. Default false.
  1597  *                                                    down. Default false.
  1548  *     @type string       $name                    Name attribute of select element. Default 'user'.
  1598  *     @type string          $name                    Name attribute of select element. Default 'user'.
  1549  *     @type string       $id                      ID attribute of the select element. Default is the value of $name.
  1599  *     @type string          $id                      ID attribute of the select element. Default is the value of `$name`.
  1550  *     @type string       $class                   Class attribute of the select element. Default empty.
  1600  *     @type string          $class                   Class attribute of the select element. Default empty.
  1551  *     @type int          $blog_id                 ID of blog (Multisite only). Default is ID of the current blog.
  1601  *     @type int             $blog_id                 ID of blog (Multisite only). Default is ID of the current blog.
  1552  *     @type string       $who                     Which type of users to query. Accepts only an empty string or
  1602  *     @type string          $who                     Deprecated, use `$capability` instead.
  1553  *                                                 'authors'. Default empty.
  1603  *                                                    Which type of users to query. Accepts only an empty string or
  1554  *     @type string|array $role                    An array or a comma-separated list of role names that users must
  1604  *                                                    'authors'. Default empty (all users).
  1555  *                                                 match to be included in results. Note that this is an inclusive
  1605  *     @type string|string[] $role                    An array or a comma-separated list of role names that users
  1556  *                                                 list: users must match *each* role. Default empty.
  1606  *                                                    must match to be included in results. Note that this is
  1557  *     @type string[]     $role__in                An array of role names. Matched users must have at least one of
  1607  *                                                    an inclusive list: users must match *each* role. Default empty.
  1558  *                                                 these roles. Default empty array.
  1608  *     @type string[]        $role__in                An array of role names. Matched users must have at least one
  1559  *     @type string[]     $role__not_in            An array of role names to exclude. Users matching one or more of
  1609  *                                                    of these roles. Default empty array.
  1560  *                                                 these roles will not be included in results. Default empty array.
  1610  *     @type string[]        $role__not_in            An array of role names to exclude. Users matching one or more
       
  1611  *                                                    of these roles will not be included in results. Default empty array.
       
  1612  *     @type string|string[] $capability              An array or a comma-separated list of capability names that users
       
  1613  *                                                    must match to be included in results. Note that this is
       
  1614  *                                                    an inclusive list: users must match *each* capability.
       
  1615  *                                                    Does NOT work for capabilities not in the database or filtered
       
  1616  *                                                    via {@see 'map_meta_cap'}. Default empty.
       
  1617  *     @type string[]        $capability__in          An array of capability names. Matched users must have at least one
       
  1618  *                                                    of these capabilities.
       
  1619  *                                                    Does NOT work for capabilities not in the database or filtered
       
  1620  *                                                    via {@see 'map_meta_cap'}. Default empty array.
       
  1621  *     @type string[]        $capability__not_in      An array of capability names to exclude. Users matching one or more
       
  1622  *                                                    of these capabilities will not be included in results.
       
  1623  *                                                    Does NOT work for capabilities not in the database or filtered
       
  1624  *                                                    via {@see 'map_meta_cap'}. Default empty array.
  1561  * }
  1625  * }
  1562  * @return string HTML dropdown list of users.
  1626  * @return string HTML dropdown list of users.
  1563  */
  1627  */
  1564 function wp_dropdown_users( $args = '' ) {
  1628 function wp_dropdown_users( $args = '' ) {
  1565 	$defaults = array(
  1629 	$defaults = array(
  1736 
  1800 
  1737 	if ( ! is_string( $value ) && ! is_numeric( $value ) ) {
  1801 	if ( ! is_string( $value ) && ! is_numeric( $value ) ) {
  1738 		return $value;
  1802 		return $value;
  1739 	}
  1803 	}
  1740 
  1804 
  1741 	$prefixed = false !== strpos( $field, 'user_' );
  1805 	$prefixed = str_contains( $field, 'user_' );
  1742 
  1806 
  1743 	if ( 'edit' === $context ) {
  1807 	if ( 'edit' === $context ) {
  1744 		if ( $prefixed ) {
  1808 		if ( $prefixed ) {
  1745 
  1809 
  1746 			/** This filter is documented in wp-includes/post.php */
  1810 			/** This filter is documented in wp-includes/post.php */
  1843 		$user = $user->data;
  1907 		$user = $user->data;
  1844 	}
  1908 	}
  1845 
  1909 
  1846 	wp_cache_add( $user->ID, $user, 'users' );
  1910 	wp_cache_add( $user->ID, $user, 'users' );
  1847 	wp_cache_add( $user->user_login, $user->ID, 'userlogins' );
  1911 	wp_cache_add( $user->user_login, $user->ID, 'userlogins' );
  1848 	wp_cache_add( $user->user_email, $user->ID, 'useremail' );
       
  1849 	wp_cache_add( $user->user_nicename, $user->ID, 'userslugs' );
  1912 	wp_cache_add( $user->user_nicename, $user->ID, 'userslugs' );
       
  1913 
       
  1914 	if ( ! empty( $user->user_email ) ) {
       
  1915 		wp_cache_add( $user->user_email, $user->ID, 'useremail' );
       
  1916 	}
  1850 }
  1917 }
  1851 
  1918 
  1852 /**
  1919 /**
  1853  * Cleans all user caches.
  1920  * Cleans all user caches.
  1854  *
  1921  *
  1855  * @since 3.0.0
  1922  * @since 3.0.0
  1856  * @since 4.4.0 'clean_user_cache' action was added.
  1923  * @since 4.4.0 'clean_user_cache' action was added.
  1857  * @since 5.8.0 Refreshes the global user instance if cleaning the user cache for the current user.
  1924  * @since 6.2.0 User metadata caches are now cleared.
  1858  *
       
  1859  * @global WP_User $current_user The current user object which holds the user data.
       
  1860  *
  1925  *
  1861  * @param WP_User|int $user User object or ID to be cleaned from the cache
  1926  * @param WP_User|int $user User object or ID to be cleaned from the cache
  1862  */
  1927  */
  1863 function clean_user_cache( $user ) {
  1928 function clean_user_cache( $user ) {
  1864 	global $current_user;
       
  1865 
       
  1866 	if ( is_numeric( $user ) ) {
  1929 	if ( is_numeric( $user ) ) {
  1867 		$user = new WP_User( $user );
  1930 		$user = new WP_User( $user );
  1868 	}
  1931 	}
  1869 
  1932 
  1870 	if ( ! $user->exists() ) {
  1933 	if ( ! $user->exists() ) {
  1871 		return;
  1934 		return;
  1872 	}
  1935 	}
  1873 
  1936 
  1874 	wp_cache_delete( $user->ID, 'users' );
  1937 	wp_cache_delete( $user->ID, 'users' );
  1875 	wp_cache_delete( $user->user_login, 'userlogins' );
  1938 	wp_cache_delete( $user->user_login, 'userlogins' );
  1876 	wp_cache_delete( $user->user_email, 'useremail' );
       
  1877 	wp_cache_delete( $user->user_nicename, 'userslugs' );
  1939 	wp_cache_delete( $user->user_nicename, 'userslugs' );
       
  1940 
       
  1941 	if ( ! empty( $user->user_email ) ) {
       
  1942 		wp_cache_delete( $user->user_email, 'useremail' );
       
  1943 	}
       
  1944 
       
  1945 	wp_cache_delete( $user->ID, 'user_meta' );
       
  1946 	wp_cache_set_users_last_changed();
  1878 
  1947 
  1879 	/**
  1948 	/**
  1880 	 * Fires immediately after the given user's cache is cleaned.
  1949 	 * Fires immediately after the given user's cache is cleaned.
  1881 	 *
  1950 	 *
  1882 	 * @since 4.4.0
  1951 	 * @since 4.4.0
  1883 	 *
  1952 	 *
  1884 	 * @param int     $user_id User ID.
  1953 	 * @param int     $user_id User ID.
  1885 	 * @param WP_User $user    User object.
  1954 	 * @param WP_User $user    User object.
  1886 	 */
  1955 	 */
  1887 	do_action( 'clean_user_cache', $user->ID, $user );
  1956 	do_action( 'clean_user_cache', $user->ID, $user );
  1888 
       
  1889 	// Refresh the global user instance if the cleaning current user.
       
  1890 	if ( get_current_user_id() === (int) $user->ID ) {
       
  1891 		$user_id      = (int) $user->ID;
       
  1892 		$current_user = null;
       
  1893 		wp_set_current_user( $user_id, '' );
       
  1894 	}
       
  1895 }
  1957 }
  1896 
  1958 
  1897 /**
  1959 /**
  1898  * Determines whether the given username exists.
  1960  * Determines whether the given username exists.
  1899  *
  1961  *
  1967  * @param string $username Username.
  2029  * @param string $username Username.
  1968  * @return bool Whether username given is valid.
  2030  * @return bool Whether username given is valid.
  1969  */
  2031  */
  1970 function validate_username( $username ) {
  2032 function validate_username( $username ) {
  1971 	$sanitized = sanitize_user( $username, true );
  2033 	$sanitized = sanitize_user( $username, true );
  1972 	$valid     = ( $sanitized == $username && ! empty( $sanitized ) );
  2034 	$valid     = ( $sanitized === $username && ! empty( $sanitized ) );
  1973 
  2035 
  1974 	/**
  2036 	/**
  1975 	 * Filters whether the provided username is valid.
  2037 	 * Filters whether the provided username is valid.
  1976 	 *
  2038 	 *
  1977 	 * @since 2.0.1
  2039 	 * @since 2.0.1
  2003  *
  2065  *
  2004  * @param array|object|WP_User $userdata {
  2066  * @param array|object|WP_User $userdata {
  2005  *     An array, object, or WP_User object of user data arguments.
  2067  *     An array, object, or WP_User object of user data arguments.
  2006  *
  2068  *
  2007  *     @type int    $ID                   User ID. If supplied, the user will be updated.
  2069  *     @type int    $ID                   User ID. If supplied, the user will be updated.
  2008  *     @type string $user_pass            The plain-text user password.
  2070  *     @type string $user_pass            The plain-text user password for new users.
       
  2071  *                                        Hashed password for existing users.
  2009  *     @type string $user_login           The user's login username.
  2072  *     @type string $user_login           The user's login username.
  2010  *     @type string $user_nicename        The URL-friendly user name.
  2073  *     @type string $user_nicename        The URL-friendly user name.
  2011  *     @type string $user_url             The user URL.
  2074  *     @type string $user_url             The user URL.
  2012  *     @type string $user_email           The user email address.
  2075  *     @type string $user_email           The user email address.
  2013  *     @type string $display_name         The user's display name.
  2076  *     @type string $display_name         The user's display name.
  2065 
  2128 
  2066 		if ( ! $old_user_data ) {
  2129 		if ( ! $old_user_data ) {
  2067 			return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
  2130 			return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
  2068 		}
  2131 		}
  2069 
  2132 
       
  2133 		// Slash current user email to compare it later with slashed new user email.
       
  2134 		$old_user_data->user_email = wp_slash( $old_user_data->user_email );
       
  2135 
  2070 		// Hashed in wp_update_user(), plaintext if called directly.
  2136 		// Hashed in wp_update_user(), plaintext if called directly.
  2071 		$user_pass = ! empty( $userdata['user_pass'] ) ? $userdata['user_pass'] : $old_user_data->user_pass;
  2137 		$user_pass = ! empty( $userdata['user_pass'] ) ? $userdata['user_pass'] : $old_user_data->user_pass;
  2072 	} else {
  2138 	} else {
  2073 		$update = false;
  2139 		$update = false;
  2074 		// Hash the password.
  2140 		// Hash the password.
  2147 		while ( $user_nicename_check ) {
  2213 		while ( $user_nicename_check ) {
  2148 			// user_nicename allows 50 chars. Subtract one for a hyphen, plus the length of the suffix.
  2214 			// user_nicename allows 50 chars. Subtract one for a hyphen, plus the length of the suffix.
  2149 			$base_length         = 49 - mb_strlen( $suffix );
  2215 			$base_length         = 49 - mb_strlen( $suffix );
  2150 			$alt_user_nicename   = mb_substr( $user_nicename, 0, $base_length ) . "-$suffix";
  2216 			$alt_user_nicename   = mb_substr( $user_nicename, 0, $base_length ) . "-$suffix";
  2151 			$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 ) );
  2217 			$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 ) );
  2152 			$suffix++;
  2218 			++$suffix;
  2153 		}
  2219 		}
  2154 		$user_nicename = $alt_user_nicename;
  2220 		$user_nicename = $alt_user_nicename;
  2155 	}
  2221 	}
  2156 
  2222 
  2157 	$raw_user_email = empty( $userdata['user_email'] ) ? '' : $userdata['user_email'];
  2223 	$raw_user_email = empty( $userdata['user_email'] ) ? '' : $userdata['user_email'];
  2240 
  2306 
  2241 	if ( empty( $userdata['display_name'] ) ) {
  2307 	if ( empty( $userdata['display_name'] ) ) {
  2242 		if ( $update ) {
  2308 		if ( $update ) {
  2243 			$display_name = $user_login;
  2309 			$display_name = $user_login;
  2244 		} elseif ( $meta['first_name'] && $meta['last_name'] ) {
  2310 		} elseif ( $meta['first_name'] && $meta['last_name'] ) {
  2245 			/* translators: 1: User's first name, 2: Last name. */
  2311 			$display_name = sprintf(
  2246 			$display_name = sprintf( _x( '%1$s %2$s', 'Display name based on first name and last name' ), $meta['first_name'], $meta['last_name'] );
  2312 				/* translators: 1: User's first name, 2: Last name. */
       
  2313 				_x( '%1$s %2$s', 'Display name based on first name and last name' ),
       
  2314 				$meta['first_name'],
       
  2315 				$meta['last_name']
       
  2316 			);
  2247 		} elseif ( $meta['first_name'] ) {
  2317 		} elseif ( $meta['first_name'] ) {
  2248 			$display_name = $meta['first_name'];
  2318 			$display_name = $meta['first_name'];
  2249 		} elseif ( $meta['last_name'] ) {
  2319 		} elseif ( $meta['last_name'] ) {
  2250 			$display_name = $meta['last_name'];
  2320 			$display_name = $meta['last_name'];
  2251 		} else {
  2321 		} else {
  2397 	 */
  2467 	 */
  2398 	$custom_meta = apply_filters( 'insert_custom_user_meta', $custom_meta, $user, $update, $userdata );
  2468 	$custom_meta = apply_filters( 'insert_custom_user_meta', $custom_meta, $user, $update, $userdata );
  2399 
  2469 
  2400 	$meta = array_merge( $meta, $custom_meta );
  2470 	$meta = array_merge( $meta, $custom_meta );
  2401 
  2471 
  2402 	// Update user meta.
  2472 	if ( $update ) {
  2403 	foreach ( $meta as $key => $value ) {
  2473 		// Update user meta.
  2404 		update_user_meta( $user_id, $key, $value );
  2474 		foreach ( $meta as $key => $value ) {
       
  2475 			update_user_meta( $user_id, $key, $value );
       
  2476 		}
       
  2477 	} else {
       
  2478 		// Add user meta.
       
  2479 		foreach ( $meta as $key => $value ) {
       
  2480 			add_user_meta( $user_id, $key, $value );
       
  2481 		}
  2405 	}
  2482 	}
  2406 
  2483 
  2407 	foreach ( wp_get_user_contact_methods( $user ) as $key => $value ) {
  2484 	foreach ( wp_get_user_contact_methods( $user ) as $key => $value ) {
  2408 		if ( isset( $userdata[ $key ] ) ) {
  2485 		if ( isset( $userdata[ $key ] ) ) {
  2409 			update_user_meta( $user_id, $key, $userdata[ $key ] );
  2486 			update_user_meta( $user_id, $key, $userdata[ $key ] );
  2429 		 * @param WP_User $old_user_data Object containing user's data prior to update.
  2506 		 * @param WP_User $old_user_data Object containing user's data prior to update.
  2430 		 * @param array   $userdata      The raw array of data passed to wp_insert_user().
  2507 		 * @param array   $userdata      The raw array of data passed to wp_insert_user().
  2431 		 */
  2508 		 */
  2432 		do_action( 'profile_update', $user_id, $old_user_data, $userdata );
  2509 		do_action( 'profile_update', $user_id, $old_user_data, $userdata );
  2433 
  2510 
  2434 		if ( isset( $userdata['spam'] ) && $userdata['spam'] != $old_user_data->spam ) {
  2511 		if ( isset( $userdata['spam'] ) && $userdata['spam'] !== $old_user_data->spam ) {
  2435 			if ( 1 == $userdata['spam'] ) {
  2512 			if ( '1' === $userdata['spam'] ) {
  2436 				/**
  2513 				/**
  2437 				 * Fires after the user is marked as a SPAM user.
  2514 				 * Fires after the user is marked as a SPAM user.
  2438 				 *
  2515 				 *
  2439 				 * @since 3.0.0
  2516 				 * @since 3.0.0
  2440 				 *
  2517 				 *
  2489 		$userdata = get_object_vars( $userdata );
  2566 		$userdata = get_object_vars( $userdata );
  2490 	} elseif ( $userdata instanceof WP_User ) {
  2567 	} elseif ( $userdata instanceof WP_User ) {
  2491 		$userdata = $userdata->to_array();
  2568 		$userdata = $userdata->to_array();
  2492 	}
  2569 	}
  2493 
  2570 
       
  2571 	$userdata_raw = $userdata;
       
  2572 
  2494 	$user_id = isset( $userdata['ID'] ) ? (int) $userdata['ID'] : 0;
  2573 	$user_id = isset( $userdata['ID'] ) ? (int) $userdata['ID'] : 0;
  2495 	if ( ! $user_id ) {
  2574 	if ( ! $user_id ) {
  2496 		return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
  2575 		return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
  2497 	}
  2576 	}
  2498 
  2577 
  2558 
  2637 
  2559 	$blog_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
  2638 	$blog_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
  2560 
  2639 
  2561 	$switched_locale = false;
  2640 	$switched_locale = false;
  2562 	if ( ! empty( $send_password_change_email ) || ! empty( $send_email_change_email ) ) {
  2641 	if ( ! empty( $send_password_change_email ) || ! empty( $send_email_change_email ) ) {
  2563 		$switched_locale = switch_to_locale( get_user_locale( $user_id ) );
  2642 		$switched_locale = switch_to_user_locale( $user_id );
  2564 	}
  2643 	}
  2565 
  2644 
  2566 	if ( ! empty( $send_password_change_email ) ) {
  2645 	if ( ! empty( $send_password_change_email ) ) {
  2567 		/* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
  2646 		/* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
  2568 		$pass_change_text = __(
  2647 		$pass_change_text = __(
  2685 		restore_previous_locale();
  2764 		restore_previous_locale();
  2686 	}
  2765 	}
  2687 
  2766 
  2688 	// Update the cookies if the password changed.
  2767 	// Update the cookies if the password changed.
  2689 	$current_user = wp_get_current_user();
  2768 	$current_user = wp_get_current_user();
  2690 	if ( $current_user->ID == $user_id ) {
  2769 	if ( $current_user->ID === $user_id ) {
  2691 		if ( isset( $plaintext_pass ) ) {
  2770 		if ( isset( $plaintext_pass ) ) {
  2692 			wp_clear_auth_cookie();
  2771 			wp_clear_auth_cookie();
  2693 
  2772 
  2694 			// Here we calculate the expiration length of the current auth cookie and compare it to the default expiration.
  2773 			/*
  2695 			// If it's greater than this, then we know the user checked 'Remember Me' when they logged in.
  2774 			 * Here we calculate the expiration length of the current auth cookie and compare it to the default expiration.
       
  2775 			 * If it's greater than this, then we know the user checked 'Remember Me' when they logged in.
       
  2776 			 */
  2696 			$logged_in_cookie = wp_parse_auth_cookie( '', 'logged_in' );
  2777 			$logged_in_cookie = wp_parse_auth_cookie( '', 'logged_in' );
  2697 			/** This filter is documented in wp-includes/pluggable.php */
  2778 			/** This filter is documented in wp-includes/pluggable.php */
  2698 			$default_cookie_life = apply_filters( 'auth_cookie_expiration', ( 2 * DAY_IN_SECONDS ), $user_id, false );
  2779 			$default_cookie_life = apply_filters( 'auth_cookie_expiration', ( 2 * DAY_IN_SECONDS ), $user_id, false );
  2699 			$remember            = false;
  2780 
       
  2781 			$remember = false;
       
  2782 
  2700 			if ( false !== $logged_in_cookie && ( $logged_in_cookie['expiration'] - time() ) > $default_cookie_life ) {
  2783 			if ( false !== $logged_in_cookie && ( $logged_in_cookie['expiration'] - time() ) > $default_cookie_life ) {
  2701 				$remember = true;
  2784 				$remember = true;
  2702 			}
  2785 			}
  2703 
  2786 
  2704 			wp_set_auth_cookie( $user_id, $remember );
  2787 			wp_set_auth_cookie( $user_id, $remember );
  2705 		}
  2788 		}
  2706 	}
  2789 	}
       
  2790 
       
  2791 	/**
       
  2792 	 * Fires after the user has been updated and emails have been sent.
       
  2793 	 *
       
  2794 	 * @since 6.3.0
       
  2795 	 *
       
  2796 	 * @param int   $user_id      The ID of the user that was just updated.
       
  2797 	 * @param array $userdata     The array of user data that was updated.
       
  2798 	 * @param array $userdata_raw The unedited array of user data that was updated.
       
  2799 	 */
       
  2800 	do_action( 'wp_update_user', $user_id, $userdata, $userdata_raw );
  2707 
  2801 
  2708 	return $user_id;
  2802 	return $user_id;
  2709 }
  2803 }
  2710 
  2804 
  2711 /**
  2805 /**
  2819 /**
  2913 /**
  2820  * Creates, stores, then returns a password reset key for user.
  2914  * Creates, stores, then returns a password reset key for user.
  2821  *
  2915  *
  2822  * @since 4.4.0
  2916  * @since 4.4.0
  2823  *
  2917  *
  2824  * @global PasswordHash $wp_hasher Portable PHP password hashing framework.
  2918  * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
  2825  *
  2919  *
  2826  * @param WP_User $user User to retrieve password reset key for.
  2920  * @param WP_User $user User to retrieve password reset key for.
  2827  * @return string|WP_Error Password reset key on success. WP_Error on error.
  2921  * @return string|WP_Error Password reset key on success. WP_Error on error.
  2828  */
  2922  */
  2829 function get_password_reset_key( $user ) {
  2923 function get_password_reset_key( $user ) {
  2830 	global $wp_hasher;
  2924 	global $wp_hasher;
  2831 
  2925 
  2832 	if ( ! ( $user instanceof WP_User ) ) {
  2926 	if ( ! ( $user instanceof WP_User ) ) {
  2833 		return new WP_Error( 'invalidcombo', __( '<strong>Error</strong>: There is no account with that username or email address.' ) );
  2927 		return new WP_Error( 'invalidcombo', __( '<strong>Error:</strong> There is no account with that username or email address.' ) );
  2834 	}
  2928 	}
  2835 
  2929 
  2836 	/**
  2930 	/**
  2837 	 * Fires before a new password is retrieved.
  2931 	 * Fires before a new password is retrieved.
  2838 	 *
  2932 	 *
  2852 	 *
  2946 	 *
  2853 	 * @param string $user_login The user login name.
  2947 	 * @param string $user_login The user login name.
  2854 	 */
  2948 	 */
  2855 	do_action( 'retrieve_password', $user->user_login );
  2949 	do_action( 'retrieve_password', $user->user_login );
  2856 
  2950 
  2857 	$allow = true;
  2951 	$password_reset_allowed = wp_is_password_reset_allowed_for_user( $user );
  2858 	if ( is_multisite() && is_user_spammy( $user ) ) {
  2952 	if ( ! $password_reset_allowed ) {
  2859 		$allow = false;
       
  2860 	}
       
  2861 
       
  2862 	/**
       
  2863 	 * Filters whether to allow a password to be reset.
       
  2864 	 *
       
  2865 	 * @since 2.7.0
       
  2866 	 *
       
  2867 	 * @param bool $allow   Whether to allow the password to be reset. Default true.
       
  2868 	 * @param int  $user_id The ID of the user attempting to reset a password.
       
  2869 	 */
       
  2870 	$allow = apply_filters( 'allow_password_reset', $allow, $user->ID );
       
  2871 
       
  2872 	if ( ! $allow ) {
       
  2873 		return new WP_Error( 'no_password_reset', __( 'Password reset is not allowed for this user' ) );
  2953 		return new WP_Error( 'no_password_reset', __( 'Password reset is not allowed for this user' ) );
  2874 	} elseif ( is_wp_error( $allow ) ) {
  2954 	} elseif ( is_wp_error( $password_reset_allowed ) ) {
  2875 		return $allow;
  2955 		return $password_reset_allowed;
  2876 	}
  2956 	}
  2877 
  2957 
  2878 	// Generate something random for a password reset key.
  2958 	// Generate something random for a password reset key.
  2879 	$key = wp_generate_password( 20, false );
  2959 	$key = wp_generate_password( 20, false );
  2880 
  2960 
  2918  * hashing process. This field is now hashed; old values are no longer accepted
  2998  * hashing process. This field is now hashed; old values are no longer accepted
  2919  * but have a different WP_Error code so good user feedback can be provided.
  2999  * but have a different WP_Error code so good user feedback can be provided.
  2920  *
  3000  *
  2921  * @since 3.1.0
  3001  * @since 3.1.0
  2922  *
  3002  *
  2923  * @global wpdb         $wpdb      WordPress database object for queries.
       
  2924  * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
  3003  * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
  2925  *
  3004  *
  2926  * @param string $key       Hash to validate sending user's password.
  3005  * @param string $key       Hash to validate sending user's password.
  2927  * @param string $login     The user login.
  3006  * @param string $login     The user login.
  2928  * @return WP_User|WP_Error WP_User object on success, WP_Error object for invalid or expired keys.
  3007  * @return WP_User|WP_Error WP_User object on success, WP_Error object for invalid or expired keys.
  2929  */
  3008  */
  2930 function check_password_reset_key( $key, $login ) {
  3009 function check_password_reset_key( $key, $login ) {
  2931 	global $wpdb, $wp_hasher;
  3010 	global $wp_hasher;
  2932 
  3011 
  2933 	$key = preg_replace( '/[^a-z0-9]/i', '', $key );
  3012 	$key = preg_replace( '/[^a-z0-9]/i', '', $key );
  2934 
  3013 
  2935 	if ( empty( $key ) || ! is_string( $key ) ) {
  3014 	if ( empty( $key ) || ! is_string( $key ) ) {
  2936 		return new WP_Error( 'invalid_key', __( 'Invalid key.' ) );
  3015 		return new WP_Error( 'invalid_key', __( 'Invalid key.' ) );
  2958 	 *
  3037 	 *
  2959 	 * @param int $expiration The expiration time in seconds.
  3038 	 * @param int $expiration The expiration time in seconds.
  2960 	 */
  3039 	 */
  2961 	$expiration_duration = apply_filters( 'password_reset_expiration', DAY_IN_SECONDS );
  3040 	$expiration_duration = apply_filters( 'password_reset_expiration', DAY_IN_SECONDS );
  2962 
  3041 
  2963 	if ( false !== strpos( $user->user_activation_key, ':' ) ) {
  3042 	if ( str_contains( $user->user_activation_key, ':' ) ) {
  2964 		list( $pass_request_time, $pass_key ) = explode( ':', $user->user_activation_key, 2 );
  3043 		list( $pass_request_time, $pass_key ) = explode( ':', $user->user_activation_key, 2 );
  2965 		$expiration_time                      = $pass_request_time + $expiration_duration;
  3044 		$expiration_time                      = $pass_request_time + $expiration_duration;
  2966 	} else {
  3045 	} else {
  2967 		$pass_key        = $user->user_activation_key;
  3046 		$pass_key        = $user->user_activation_key;
  2968 		$expiration_time = false;
  3047 		$expiration_time = false;
  3006  * Handles sending a password retrieval email to a user.
  3085  * Handles sending a password retrieval email to a user.
  3007  *
  3086  *
  3008  * @since 2.5.0
  3087  * @since 2.5.0
  3009  * @since 5.7.0 Added `$user_login` parameter.
  3088  * @since 5.7.0 Added `$user_login` parameter.
  3010  *
  3089  *
  3011  * @global wpdb         $wpdb       WordPress database abstraction object.
  3090  * @global wpdb         $wpdb      WordPress database abstraction object.
  3012  * @global PasswordHash $wp_hasher  Portable PHP password hashing framework.
  3091  * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
  3013  *
  3092  *
  3014  * @param string $user_login Optional. Username to send a password retrieval email for.
  3093  * @param string $user_login Optional. Username to send a password retrieval email for.
  3015  *                           Defaults to `$_POST['user_login']` if not set.
  3094  *                           Defaults to `$_POST['user_login']` if not set.
  3016  * @return true|WP_Error True when finished, WP_Error object on error.
  3095  * @return true|WP_Error True when finished, WP_Error object on error.
  3017  */
  3096  */
  3022 	// Use the passed $user_login if available, otherwise use $_POST['user_login'].
  3101 	// Use the passed $user_login if available, otherwise use $_POST['user_login'].
  3023 	if ( ! $user_login && ! empty( $_POST['user_login'] ) ) {
  3102 	if ( ! $user_login && ! empty( $_POST['user_login'] ) ) {
  3024 		$user_login = $_POST['user_login'];
  3103 		$user_login = $_POST['user_login'];
  3025 	}
  3104 	}
  3026 
  3105 
       
  3106 	$user_login = trim( wp_unslash( $user_login ) );
       
  3107 
  3027 	if ( empty( $user_login ) ) {
  3108 	if ( empty( $user_login ) ) {
  3028 		$errors->add( 'empty_username', __( '<strong>Error</strong>: Please enter a username or email address.' ) );
  3109 		$errors->add( 'empty_username', __( '<strong>Error:</strong> Please enter a username or email address.' ) );
  3029 	} elseif ( strpos( $user_login, '@' ) ) {
  3110 	} elseif ( strpos( $user_login, '@' ) ) {
  3030 		$user_data = get_user_by( 'email', trim( wp_unslash( $user_login ) ) );
  3111 		$user_data = get_user_by( 'email', $user_login );
       
  3112 
  3031 		if ( empty( $user_data ) ) {
  3113 		if ( empty( $user_data ) ) {
  3032 			$errors->add( 'invalid_email', __( '<strong>Error</strong>: There is no account with that username or email address.' ) );
  3114 			$user_data = get_user_by( 'login', $user_login );
       
  3115 		}
       
  3116 
       
  3117 		if ( empty( $user_data ) ) {
       
  3118 			$errors->add( 'invalid_email', __( '<strong>Error:</strong> There is no account with that username or email address.' ) );
  3033 		}
  3119 		}
  3034 	} else {
  3120 	} else {
  3035 		$user_data = get_user_by( 'login', trim( wp_unslash( $user_login ) ) );
  3121 		$user_data = get_user_by( 'login', $user_login );
  3036 	}
  3122 	}
  3037 
  3123 
  3038 	/**
  3124 	/**
  3039 	 * Filters the user data during a password reset request.
  3125 	 * Filters the user data during a password reset request.
  3040 	 *
  3126 	 *
  3081 	if ( $errors->has_errors() ) {
  3167 	if ( $errors->has_errors() ) {
  3082 		return $errors;
  3168 		return $errors;
  3083 	}
  3169 	}
  3084 
  3170 
  3085 	if ( ! $user_data ) {
  3171 	if ( ! $user_data ) {
  3086 		$errors->add( 'invalidcombo', __( '<strong>Error</strong>: There is no account with that username or email address.' ) );
  3172 		$errors->add( 'invalidcombo', __( '<strong>Error:</strong> There is no account with that username or email address.' ) );
  3087 		return $errors;
  3173 		return $errors;
  3088 	}
  3174 	}
  3089 
  3175 
  3090 	/**
  3176 	/**
  3091 	 * Filters whether to send the retrieve password email.
  3177 	 * Filters whether to send the retrieve password email.
  3112 	}
  3198 	}
  3113 
  3199 
  3114 	// Localize password reset message content for user.
  3200 	// Localize password reset message content for user.
  3115 	$locale = get_user_locale( $user_data );
  3201 	$locale = get_user_locale( $user_data );
  3116 
  3202 
  3117 	$switched_locale = switch_to_locale( $locale );
  3203 	$switched_locale = switch_to_user_locale( $user_data->ID );
  3118 
  3204 
  3119 	if ( is_multisite() ) {
  3205 	if ( is_multisite() ) {
  3120 		$site_name = get_network()->site_name;
  3206 		$site_name = get_network()->site_name;
  3121 	} else {
  3207 	} else {
  3122 		/*
  3208 		/*
  3203 	 *     @type string $to      The intended recipient - user email address.
  3289 	 *     @type string $to      The intended recipient - user email address.
  3204 	 *     @type string $subject The subject of the email.
  3290 	 *     @type string $subject The subject of the email.
  3205 	 *     @type string $message The body of the email.
  3291 	 *     @type string $message The body of the email.
  3206 	 *     @type string $headers The headers of the email.
  3292 	 *     @type string $headers The headers of the email.
  3207 	 * }
  3293 	 * }
  3208 	 * @type string  $key        The activation key.
  3294 	 * @param string  $key        The activation key.
  3209 	 * @type string  $user_login The username for the user.
  3295 	 * @param string  $user_login The username for the user.
  3210 	 * @type WP_User $user_data  WP_User object.
  3296 	 * @param WP_User $user_data  WP_User object.
  3211 	 */
  3297 	 */
  3212 	$notification_email = apply_filters( 'retrieve_password_notification_email', $defaults, $key, $user_login, $user_data );
  3298 	$notification_email = apply_filters( 'retrieve_password_notification_email', $defaults, $key, $user_login, $user_data );
  3213 
  3299 
  3214 	if ( $switched_locale ) {
  3300 	if ( $switched_locale ) {
  3215 		restore_previous_locale();
  3301 		restore_previous_locale();
  3229 	if ( ! wp_mail( $to, $subject, $message, $headers ) ) {
  3315 	if ( ! wp_mail( $to, $subject, $message, $headers ) ) {
  3230 		$errors->add(
  3316 		$errors->add(
  3231 			'retrieve_password_email_failure',
  3317 			'retrieve_password_email_failure',
  3232 			sprintf(
  3318 			sprintf(
  3233 				/* translators: %s: Documentation URL. */
  3319 				/* translators: %s: Documentation URL. */
  3234 				__( '<strong>Error</strong>: The email could not be sent. Your site may not be correctly configured to send emails. <a href="%s">Get support for resetting your password</a>.' ),
  3320 				__( '<strong>Error:</strong> The email could not be sent. Your site may not be correctly configured to send emails. <a href="%s">Get support for resetting your password</a>.' ),
  3235 				esc_url( __( 'https://wordpress.org/support/article/resetting-your-password/' ) )
  3321 				esc_url( __( 'https://wordpress.org/documentation/article/reset-your-password/' ) )
  3236 			)
  3322 			)
  3237 		);
  3323 		);
  3238 		return $errors;
  3324 		return $errors;
  3239 	}
  3325 	}
  3240 
  3326 
  3296 	 */
  3382 	 */
  3297 	$user_email = apply_filters( 'user_registration_email', $user_email );
  3383 	$user_email = apply_filters( 'user_registration_email', $user_email );
  3298 
  3384 
  3299 	// Check the username.
  3385 	// Check the username.
  3300 	if ( '' === $sanitized_user_login ) {
  3386 	if ( '' === $sanitized_user_login ) {
  3301 		$errors->add( 'empty_username', __( '<strong>Error</strong>: Please enter a username.' ) );
  3387 		$errors->add( 'empty_username', __( '<strong>Error:</strong> Please enter a username.' ) );
  3302 	} elseif ( ! validate_username( $user_login ) ) {
  3388 	} elseif ( ! validate_username( $user_login ) ) {
  3303 		$errors->add( 'invalid_username', __( '<strong>Error</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ) );
  3389 		$errors->add( 'invalid_username', __( '<strong>Error:</strong> This username is invalid because it uses illegal characters. Please enter a valid username.' ) );
  3304 		$sanitized_user_login = '';
  3390 		$sanitized_user_login = '';
  3305 	} elseif ( username_exists( $sanitized_user_login ) ) {
  3391 	} elseif ( username_exists( $sanitized_user_login ) ) {
  3306 		$errors->add( 'username_exists', __( '<strong>Error</strong>: This username is already registered. Please choose another one.' ) );
  3392 		$errors->add( 'username_exists', __( '<strong>Error:</strong> This username is already registered. Please choose another one.' ) );
  3307 
       
  3308 	} else {
  3393 	} else {
  3309 		/** This filter is documented in wp-includes/user.php */
  3394 		/** This filter is documented in wp-includes/user.php */
  3310 		$illegal_user_logins = (array) apply_filters( 'illegal_user_logins', array() );
  3395 		$illegal_user_logins = (array) apply_filters( 'illegal_user_logins', array() );
  3311 		if ( in_array( strtolower( $sanitized_user_login ), array_map( 'strtolower', $illegal_user_logins ), true ) ) {
  3396 		if ( in_array( strtolower( $sanitized_user_login ), array_map( 'strtolower', $illegal_user_logins ), true ) ) {
  3312 			$errors->add( 'invalid_username', __( '<strong>Error</strong>: Sorry, that username is not allowed.' ) );
  3397 			$errors->add( 'invalid_username', __( '<strong>Error:</strong> Sorry, that username is not allowed.' ) );
  3313 		}
  3398 		}
  3314 	}
  3399 	}
  3315 
  3400 
  3316 	// Check the email address.
  3401 	// Check the email address.
  3317 	if ( '' === $user_email ) {
  3402 	if ( '' === $user_email ) {
  3318 		$errors->add( 'empty_email', __( '<strong>Error</strong>: Please type your email address.' ) );
  3403 		$errors->add( 'empty_email', __( '<strong>Error:</strong> Please type your email address.' ) );
  3319 	} elseif ( ! is_email( $user_email ) ) {
  3404 	} elseif ( ! is_email( $user_email ) ) {
  3320 		$errors->add( 'invalid_email', __( '<strong>Error</strong>: The email address is not correct.' ) );
  3405 		$errors->add( 'invalid_email', __( '<strong>Error:</strong> The email address is not correct.' ) );
  3321 		$user_email = '';
  3406 		$user_email = '';
  3322 	} elseif ( email_exists( $user_email ) ) {
  3407 	} elseif ( email_exists( $user_email ) ) {
  3323 		$errors->add(
  3408 		$errors->add(
  3324 			'email_exists',
  3409 			'email_exists',
  3325 			sprintf(
  3410 			sprintf(
  3370 	if ( ! $user_id || is_wp_error( $user_id ) ) {
  3455 	if ( ! $user_id || is_wp_error( $user_id ) ) {
  3371 		$errors->add(
  3456 		$errors->add(
  3372 			'registerfail',
  3457 			'registerfail',
  3373 			sprintf(
  3458 			sprintf(
  3374 				/* translators: %s: Admin email address. */
  3459 				/* translators: %s: Admin email address. */
  3375 				__( '<strong>Error</strong>: Could not register you&hellip; please contact the <a href="mailto:%s">site admin</a>!' ),
  3460 				__( '<strong>Error:</strong> Could not register you&hellip; please contact the <a href="mailto:%s">site admin</a>!' ),
  3376 				get_option( 'admin_email' )
  3461 				get_option( 'admin_email' )
  3377 			)
  3462 			)
  3378 		);
  3463 		);
  3379 		return $errors;
  3464 		return $errors;
  3380 	}
  3465 	}
  3482  * Gets the user IDs of all users with no role on this site.
  3567  * Gets the user IDs of all users with no role on this site.
  3483  *
  3568  *
  3484  * @since 4.4.0
  3569  * @since 4.4.0
  3485  * @since 4.9.0 The `$site_id` parameter was added to support multisite.
  3570  * @since 4.9.0 The `$site_id` parameter was added to support multisite.
  3486  *
  3571  *
       
  3572  * @global wpdb $wpdb WordPress database abstraction object.
       
  3573  *
  3487  * @param int|null $site_id Optional. The site ID to get users with no role for. Defaults to the current site.
  3574  * @param int|null $site_id Optional. The site ID to get users with no role for. Defaults to the current site.
  3488  * @return string[] Array of user IDs as strings.
  3575  * @return string[] Array of user IDs as strings.
  3489  */
  3576  */
  3490 function wp_get_users_with_no_role( $site_id = null ) {
  3577 function wp_get_users_with_no_role( $site_id = null ) {
  3491 	global $wpdb;
  3578 	global $wpdb;
  3494 		$site_id = get_current_blog_id();
  3581 		$site_id = get_current_blog_id();
  3495 	}
  3582 	}
  3496 
  3583 
  3497 	$prefix = $wpdb->get_blog_prefix( $site_id );
  3584 	$prefix = $wpdb->get_blog_prefix( $site_id );
  3498 
  3585 
  3499 	if ( is_multisite() && get_current_blog_id() != $site_id ) {
  3586 	if ( is_multisite() && get_current_blog_id() !== $site_id ) {
  3500 		switch_to_blog( $site_id );
  3587 		switch_to_blog( $site_id );
  3501 		$role_names = wp_roles()->get_names();
  3588 		$role_names = wp_roles()->get_names();
  3502 		restore_current_blog();
  3589 		restore_current_blog();
  3503 	} else {
  3590 	} else {
  3504 		$role_names = wp_roles()->get_names();
  3591 		$role_names = wp_roles()->get_names();
  3506 
  3593 
  3507 	$regex = implode( '|', array_keys( $role_names ) );
  3594 	$regex = implode( '|', array_keys( $role_names ) );
  3508 	$regex = preg_replace( '/[^a-zA-Z_\|-]/', '', $regex );
  3595 	$regex = preg_replace( '/[^a-zA-Z_\|-]/', '', $regex );
  3509 	$users = $wpdb->get_col(
  3596 	$users = $wpdb->get_col(
  3510 		$wpdb->prepare(
  3597 		$wpdb->prepare(
  3511 			"
  3598 			"SELECT user_id
  3512 		SELECT user_id
  3599 			FROM $wpdb->usermeta
  3513 		FROM $wpdb->usermeta
  3600 			WHERE meta_key = '{$prefix}capabilities'
  3514 		WHERE meta_key = '{$prefix}capabilities'
  3601 			AND meta_value NOT REGEXP %s",
  3515 		AND meta_value NOT REGEXP %s
       
  3516 	",
       
  3517 			$regex
  3602 			$regex
  3518 		)
  3603 		)
  3519 	);
  3604 	);
  3520 
  3605 
  3521 	return $users;
  3606 	return $users;
  3605 	$current_user = wp_get_current_user();
  3690 	$current_user = wp_get_current_user();
  3606 	if ( ! is_object( $errors ) ) {
  3691 	if ( ! is_object( $errors ) ) {
  3607 		$errors = new WP_Error();
  3692 		$errors = new WP_Error();
  3608 	}
  3693 	}
  3609 
  3694 
  3610 	if ( $current_user->ID != $_POST['user_id'] ) {
  3695 	if ( $current_user->ID !== (int) $_POST['user_id'] ) {
  3611 		return false;
  3696 		return false;
  3612 	}
  3697 	}
  3613 
  3698 
  3614 	if ( $current_user->user_email != $_POST['email'] ) {
  3699 	if ( $current_user->user_email !== $_POST['email'] ) {
  3615 		if ( ! is_email( $_POST['email'] ) ) {
  3700 		if ( ! is_email( $_POST['email'] ) ) {
  3616 			$errors->add(
  3701 			$errors->add(
  3617 				'user_email',
  3702 				'user_email',
  3618 				__( '<strong>Error</strong>: The email address is not correct.' ),
  3703 				__( '<strong>Error:</strong> The email address is not correct.' ),
  3619 				array(
  3704 				array(
  3620 					'form-field' => 'email',
  3705 					'form-field' => 'email',
  3621 				)
  3706 				)
  3622 			);
  3707 			);
  3623 
  3708 
  3625 		}
  3710 		}
  3626 
  3711 
  3627 		if ( email_exists( $_POST['email'] ) ) {
  3712 		if ( email_exists( $_POST['email'] ) ) {
  3628 			$errors->add(
  3713 			$errors->add(
  3629 				'user_email',
  3714 				'user_email',
  3630 				__( '<strong>Error</strong>: The email address is already used.' ),
  3715 				__( '<strong>Error:</strong> The email address is already used.' ),
  3631 				array(
  3716 				array(
  3632 					'form-field' => 'email',
  3717 					'form-field' => 'email',
  3633 				)
  3718 				)
  3634 			);
  3719 			);
  3635 			delete_user_meta( $current_user->ID, '_new_email' );
  3720 			delete_user_meta( $current_user->ID, '_new_email' );
  3687 		 * }
  3772 		 * }
  3688 		 */
  3773 		 */
  3689 		$content = apply_filters( 'new_user_email_content', $email_text, $new_user_email );
  3774 		$content = apply_filters( 'new_user_email_content', $email_text, $new_user_email );
  3690 
  3775 
  3691 		$content = str_replace( '###USERNAME###', $current_user->user_login, $content );
  3776 		$content = str_replace( '###USERNAME###', $current_user->user_login, $content );
  3692 		$content = str_replace( '###ADMIN_URL###', esc_url( admin_url( 'profile.php?newuseremail=' . $hash ) ), $content );
  3777 		$content = str_replace( '###ADMIN_URL###', esc_url( self_admin_url( 'profile.php?newuseremail=' . $hash ) ), $content );
  3693 		$content = str_replace( '###EMAIL###', $_POST['email'], $content );
  3778 		$content = str_replace( '###EMAIL###', $_POST['email'], $content );
  3694 		$content = str_replace( '###SITENAME###', $sitename, $content );
  3779 		$content = str_replace( '###SITENAME###', $sitename, $content );
  3695 		$content = str_replace( '###SITEURL###', home_url(), $content );
  3780 		$content = str_replace( '###SITEURL###', home_url(), $content );
  3696 
  3781 
  3697 		/* translators: New email address notification email subject. %s: Site title. */
  3782 		/* translators: New email address notification email subject. %s: Site title. */
  3714 	global $pagenow;
  3799 	global $pagenow;
  3715 
  3800 
  3716 	if ( 'profile.php' === $pagenow && isset( $_GET['updated'] ) ) {
  3801 	if ( 'profile.php' === $pagenow && isset( $_GET['updated'] ) ) {
  3717 		$email = get_user_meta( get_current_user_id(), '_new_email', true );
  3802 		$email = get_user_meta( get_current_user_id(), '_new_email', true );
  3718 		if ( $email ) {
  3803 		if ( $email ) {
  3719 			/* translators: %s: New email address. */
  3804 			$message = sprintf(
  3720 			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>';
  3805 				/* translators: %s: New email address. */
       
  3806 				__( 'Your email address has not been updated yet. Please check your inbox at %s for a confirmation email.' ),
       
  3807 				'<code>' . esc_html( $email['newemail'] ) . '</code>'
       
  3808 			);
       
  3809 			wp_admin_notice( $message, array( 'type' => 'info' ) );
  3721 		}
  3810 		}
  3722 	}
  3811 	}
  3723 }
  3812 }
  3724 
  3813 
  3725 /**
  3814 /**
  3726  * Gets all personal data request types.
  3815  * Gets all personal data request types.
  3727  *
  3816  *
  3728  * @since 4.9.6
  3817  * @since 4.9.6
  3729  * @access private
  3818  * @access private
  3730  *
  3819  *
  3731  * @return array List of core privacy action types.
  3820  * @return string[] List of core privacy action types.
  3732  */
  3821  */
  3733 function _wp_privacy_action_request_types() {
  3822 function _wp_privacy_action_request_types() {
  3734 	return array(
  3823 	return array(
  3735 		'export_personal_data',
  3824 		'export_personal_data',
  3736 		'remove_personal_data',
  3825 		'remove_personal_data',
  3740 /**
  3829 /**
  3741  * Registers the personal data exporter for users.
  3830  * Registers the personal data exporter for users.
  3742  *
  3831  *
  3743  * @since 4.9.6
  3832  * @since 4.9.6
  3744  *
  3833  *
  3745  * @param array $exporters  An array of personal data exporters.
  3834  * @param array[] $exporters An array of personal data exporters.
  3746  * @return array An array of personal data exporters.
  3835  * @return array[] An array of personal data exporters.
  3747  */
  3836  */
  3748 function wp_register_user_personal_data_exporter( $exporters ) {
  3837 function wp_register_user_personal_data_exporter( $exporters ) {
  3749 	$exporters['wordpress-user'] = array(
  3838 	$exporters['wordpress-user'] = array(
  3750 		'exporter_friendly_name' => __( 'WordPress User' ),
  3839 		'exporter_friendly_name' => __( 'WordPress User' ),
  3751 		'callback'               => 'wp_user_personal_data_exporter',
  3840 		'callback'               => 'wp_user_personal_data_exporter',
  3760  * @since 4.9.6
  3849  * @since 4.9.6
  3761  * @since 5.4.0 Added 'Community Events Location' group to the export data.
  3850  * @since 5.4.0 Added 'Community Events Location' group to the export data.
  3762  * @since 5.4.0 Added 'Session Tokens' group to the export data.
  3851  * @since 5.4.0 Added 'Session Tokens' group to the export data.
  3763  *
  3852  *
  3764  * @param string $email_address  The user's email address.
  3853  * @param string $email_address  The user's email address.
  3765  * @return array An array of personal data.
  3854  * @return array {
       
  3855  *     An array of personal data.
       
  3856  *
       
  3857  *     @type array[] $data An array of personal data arrays.
       
  3858  *     @type bool    $done Whether the exporter is finished.
       
  3859  * }
  3766  */
  3860  */
  3767 function wp_user_personal_data_exporter( $email_address ) {
  3861 function wp_user_personal_data_exporter( $email_address ) {
  3768 	$email_address = trim( $email_address );
  3862 	$email_address = trim( $email_address );
  3769 
  3863 
  3770 	$data_to_export = array();
  3864 	$data_to_export = array();
  3847 
  3941 
  3848 	if ( is_array( $_extra_data ) && ! empty( $_extra_data ) ) {
  3942 	if ( is_array( $_extra_data ) && ! empty( $_extra_data ) ) {
  3849 		// Remove items that use reserved names.
  3943 		// Remove items that use reserved names.
  3850 		$extra_data = array_filter(
  3944 		$extra_data = array_filter(
  3851 			$_extra_data,
  3945 			$_extra_data,
  3852 			static function( $item ) use ( $reserved_names ) {
  3946 			static function ( $item ) use ( $reserved_names ) {
  3853 				return ! in_array( $item['name'], $reserved_names, true );
  3947 				return ! in_array( $item['name'], $reserved_names, true );
  3854 			}
  3948 			}
  3855 		);
  3949 		);
  3856 
  3950 
  3857 		if ( count( $extra_data ) !== count( $_extra_data ) ) {
  3951 		if ( count( $extra_data ) !== count( $_extra_data ) ) {
  3991  * @param int $request_id The ID of the request.
  4085  * @param int $request_id The ID of the request.
  3992  */
  4086  */
  3993 function _wp_privacy_send_request_confirmation_notification( $request_id ) {
  4087 function _wp_privacy_send_request_confirmation_notification( $request_id ) {
  3994 	$request = wp_get_user_request( $request_id );
  4088 	$request = wp_get_user_request( $request_id );
  3995 
  4089 
  3996 	if ( ! is_a( $request, 'WP_User_Request' ) || 'request-confirmed' !== $request->status ) {
  4090 	if ( ! ( $request instanceof WP_User_Request ) || 'request-confirmed' !== $request->status ) {
  3997 		return;
  4091 		return;
  3998 	}
  4092 	}
  3999 
  4093 
  4000 	$already_notified = (bool) get_post_meta( $request_id, '_wp_admin_notified', true );
  4094 	$already_notified = (bool) get_post_meta( $request_id, '_wp_admin_notified', true );
  4001 
  4095 
  4156 	$content = apply_filters( 'user_request_confirmed_email_content', $content, $email_data );
  4250 	$content = apply_filters( 'user_request_confirmed_email_content', $content, $email_data );
  4157 
  4251 
  4158 	$content = str_replace( '###SITENAME###', $email_data['sitename'], $content );
  4252 	$content = str_replace( '###SITENAME###', $email_data['sitename'], $content );
  4159 	$content = str_replace( '###USER_EMAIL###', $email_data['user_email'], $content );
  4253 	$content = str_replace( '###USER_EMAIL###', $email_data['user_email'], $content );
  4160 	$content = str_replace( '###DESCRIPTION###', $email_data['description'], $content );
  4254 	$content = str_replace( '###DESCRIPTION###', $email_data['description'], $content );
  4161 	$content = str_replace( '###MANAGE_URL###', esc_url_raw( $email_data['manage_url'] ), $content );
  4255 	$content = str_replace( '###MANAGE_URL###', sanitize_url( $email_data['manage_url'] ), $content );
  4162 	$content = str_replace( '###SITEURL###', esc_url_raw( $email_data['siteurl'] ), $content );
  4256 	$content = str_replace( '###SITEURL###', sanitize_url( $email_data['siteurl'] ), $content );
  4163 
  4257 
  4164 	$headers = '';
  4258 	$headers = '';
  4165 
  4259 
  4166 	/**
  4260 	/**
  4167 	 * Filters the headers of the user request confirmation email.
  4261 	 * Filters the headers of the user request confirmation email.
  4203  * @param int $request_id The privacy request post ID associated with this request.
  4297  * @param int $request_id The privacy request post ID associated with this request.
  4204  */
  4298  */
  4205 function _wp_privacy_send_erasure_fulfillment_notification( $request_id ) {
  4299 function _wp_privacy_send_erasure_fulfillment_notification( $request_id ) {
  4206 	$request = wp_get_user_request( $request_id );
  4300 	$request = wp_get_user_request( $request_id );
  4207 
  4301 
  4208 	if ( ! is_a( $request, 'WP_User_Request' ) || 'request-completed' !== $request->status ) {
  4302 	if ( ! ( $request instanceof WP_User_Request ) || 'request-completed' !== $request->status ) {
  4209 		return;
  4303 		return;
  4210 	}
  4304 	}
  4211 
  4305 
  4212 	$already_notified = (bool) get_post_meta( $request_id, '_wp_user_notified', true );
  4306 	$already_notified = (bool) get_post_meta( $request_id, '_wp_user_notified', true );
  4213 
  4307 
  4215 		return;
  4309 		return;
  4216 	}
  4310 	}
  4217 
  4311 
  4218 	// Localize message content for user; fallback to site default for visitors.
  4312 	// Localize message content for user; fallback to site default for visitors.
  4219 	if ( ! empty( $request->user_id ) ) {
  4313 	if ( ! empty( $request->user_id ) ) {
  4220 		$locale = get_user_locale( $request->user_id );
  4314 		$switched_locale = switch_to_user_locale( $request->user_id );
  4221 	} else {
  4315 	} else {
  4222 		$locale = get_locale();
  4316 		$switched_locale = switch_to_locale( get_locale() );
  4223 	}
  4317 	}
  4224 
       
  4225 	$switched_locale = switch_to_locale( $locale );
       
  4226 
  4318 
  4227 	/**
  4319 	/**
  4228 	 * Filters the recipient of the data erasure fulfillment notification.
  4320 	 * Filters the recipient of the data erasure fulfillment notification.
  4229 	 *
  4321 	 *
  4230 	 * @since 4.9.6
  4322 	 * @since 4.9.6
  4397 	 */
  4489 	 */
  4398 	$content = apply_filters( 'user_erasure_fulfillment_email_content', $content, $email_data );
  4490 	$content = apply_filters( 'user_erasure_fulfillment_email_content', $content, $email_data );
  4399 
  4491 
  4400 	$content = str_replace( '###SITENAME###', $email_data['sitename'], $content );
  4492 	$content = str_replace( '###SITENAME###', $email_data['sitename'], $content );
  4401 	$content = str_replace( '###PRIVACY_POLICY_URL###', $email_data['privacy_policy_url'], $content );
  4493 	$content = str_replace( '###PRIVACY_POLICY_URL###', $email_data['privacy_policy_url'], $content );
  4402 	$content = str_replace( '###SITEURL###', esc_url_raw( $email_data['siteurl'] ), $content );
  4494 	$content = str_replace( '###SITEURL###', sanitize_url( $email_data['siteurl'] ), $content );
  4403 
  4495 
  4404 	$headers = '';
  4496 	$headers = '';
  4405 
  4497 
  4406 	/**
  4498 	/**
  4407 	 * Filters the headers of the data erasure fulfillment notification.
  4499 	 * Filters the headers of the data erasure fulfillment notification.
  4626 		return new WP_Error( 'invalid_request', __( 'Invalid personal data request.' ) );
  4718 		return new WP_Error( 'invalid_request', __( 'Invalid personal data request.' ) );
  4627 	}
  4719 	}
  4628 
  4720 
  4629 	// Localize message content for user; fallback to site default for visitors.
  4721 	// Localize message content for user; fallback to site default for visitors.
  4630 	if ( ! empty( $request->user_id ) ) {
  4722 	if ( ! empty( $request->user_id ) ) {
  4631 		$locale = get_user_locale( $request->user_id );
  4723 		$switched_locale = switch_to_user_locale( $request->user_id );
  4632 	} else {
  4724 	} else {
  4633 		$locale = get_locale();
  4725 		$switched_locale = switch_to_locale( get_locale() );
  4634 	}
  4726 	}
  4635 
       
  4636 	$switched_locale = switch_to_locale( $locale );
       
  4637 
  4727 
  4638 	$email_data = array(
  4728 	$email_data = array(
  4639 		'request'     => $request,
  4729 		'request'     => $request,
  4640 		'email'       => $request->email,
  4730 		'email'       => $request->email,
  4641 		'description' => wp_user_request_action_description( $request->action_name ),
  4731 		'description' => wp_user_request_action_description( $request->action_name ),
  4718 	 * }
  4808 	 * }
  4719 	 */
  4809 	 */
  4720 	$content = apply_filters( 'user_request_action_email_content', $content, $email_data );
  4810 	$content = apply_filters( 'user_request_action_email_content', $content, $email_data );
  4721 
  4811 
  4722 	$content = str_replace( '###DESCRIPTION###', $email_data['description'], $content );
  4812 	$content = str_replace( '###DESCRIPTION###', $email_data['description'], $content );
  4723 	$content = str_replace( '###CONFIRM_URL###', esc_url_raw( $email_data['confirm_url'] ), $content );
  4813 	$content = str_replace( '###CONFIRM_URL###', sanitize_url( $email_data['confirm_url'] ), $content );
  4724 	$content = str_replace( '###EMAIL###', $email_data['email'], $content );
  4814 	$content = str_replace( '###EMAIL###', $email_data['email'], $content );
  4725 	$content = str_replace( '###SITENAME###', $email_data['sitename'], $content );
  4815 	$content = str_replace( '###SITENAME###', $email_data['sitename'], $content );
  4726 	$content = str_replace( '###SITEURL###', esc_url_raw( $email_data['siteurl'] ), $content );
  4816 	$content = str_replace( '###SITEURL###', sanitize_url( $email_data['siteurl'] ), $content );
  4727 
  4817 
  4728 	$headers = '';
  4818 	$headers = '';
  4729 
  4819 
  4730 	/**
  4820 	/**
  4731 	 * Filters the headers of the email sent when an account action is attempted.
  4821 	 * Filters the headers of the email sent when an account action is attempted.
  4765 /**
  4855 /**
  4766  * Returns a confirmation key for a user action and stores the hashed version for future comparison.
  4856  * Returns a confirmation key for a user action and stores the hashed version for future comparison.
  4767  *
  4857  *
  4768  * @since 4.9.6
  4858  * @since 4.9.6
  4769  *
  4859  *
       
  4860  * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
       
  4861  *
  4770  * @param int $request_id Request ID.
  4862  * @param int $request_id Request ID.
  4771  * @return string Confirmation key.
  4863  * @return string Confirmation key.
  4772  */
  4864  */
  4773 function wp_generate_user_request_key( $request_id ) {
  4865 function wp_generate_user_request_key( $request_id ) {
  4774 	global $wp_hasher;
  4866 	global $wp_hasher;
  4796 /**
  4888 /**
  4797  * Validates a user request by comparing the key with the request's key.
  4889  * Validates a user request by comparing the key with the request's key.
  4798  *
  4890  *
  4799  * @since 4.9.6
  4891  * @since 4.9.6
  4800  *
  4892  *
       
  4893  * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
       
  4894  *
  4801  * @param string $request_id ID of the request being confirmed.
  4895  * @param string $request_id ID of the request being confirmed.
  4802  * @param string $key        Provided key to validate.
  4896  * @param string $key        Provided key to validate.
  4803  * @return true|WP_Error True on success, WP_Error on failure.
  4897  * @return true|WP_Error True on success, WP_Error on failure.
  4804  */
  4898  */
  4805 function wp_validate_user_request_key( $request_id, $key ) {
  4899 function wp_validate_user_request_key( $request_id, $key ) {
  4934 	 * @param bool    $available True if available, false otherwise.
  5028 	 * @param bool    $available True if available, false otherwise.
  4935 	 * @param WP_User $user      The user to check.
  5029 	 * @param WP_User $user      The user to check.
  4936 	 */
  5030 	 */
  4937 	return apply_filters( 'wp_is_application_passwords_available_for_user', true, $user );
  5031 	return apply_filters( 'wp_is_application_passwords_available_for_user', true, $user );
  4938 }
  5032 }
       
  5033 
       
  5034 /**
       
  5035  * Registers the user meta property for persisted preferences.
       
  5036  *
       
  5037  * This property is used to store user preferences across page reloads and is
       
  5038  * currently used by the block editor for preferences like 'fullscreenMode' and
       
  5039  * 'fixedToolbar'.
       
  5040  *
       
  5041  * @since 6.1.0
       
  5042  * @access private
       
  5043  *
       
  5044  * @global wpdb $wpdb WordPress database abstraction object.
       
  5045  */
       
  5046 function wp_register_persisted_preferences_meta() {
       
  5047 	/*
       
  5048 	 * Create a meta key that incorporates the blog prefix so that each site
       
  5049 	 * on a multisite can have distinct user preferences.
       
  5050 	 */
       
  5051 	global $wpdb;
       
  5052 	$meta_key = $wpdb->get_blog_prefix() . 'persisted_preferences';
       
  5053 
       
  5054 	register_meta(
       
  5055 		'user',
       
  5056 		$meta_key,
       
  5057 		array(
       
  5058 			'type'         => 'object',
       
  5059 			'single'       => true,
       
  5060 			'show_in_rest' => array(
       
  5061 				'name'   => 'persisted_preferences',
       
  5062 				'type'   => 'object',
       
  5063 				'schema' => array(
       
  5064 					'type'                 => 'object',
       
  5065 					'context'              => array( 'edit' ),
       
  5066 					'properties'           => array(
       
  5067 						'_modified' => array(
       
  5068 							'description' => __( 'The date and time the preferences were updated.' ),
       
  5069 							'type'        => 'string',
       
  5070 							'format'      => 'date-time',
       
  5071 							'readonly'    => false,
       
  5072 						),
       
  5073 					),
       
  5074 					'additionalProperties' => true,
       
  5075 				),
       
  5076 			),
       
  5077 		)
       
  5078 	);
       
  5079 }
       
  5080 
       
  5081 /**
       
  5082  * Sets the last changed time for the 'users' cache group.
       
  5083  *
       
  5084  * @since 6.3.0
       
  5085  */
       
  5086 function wp_cache_set_users_last_changed() {
       
  5087 	wp_cache_set_last_changed( 'users' );
       
  5088 }
       
  5089 
       
  5090 /**
       
  5091  * Checks if password reset is allowed for a specific user.
       
  5092  *
       
  5093  * @since 6.3.0
       
  5094  *
       
  5095  * @param int|WP_User $user The user to check.
       
  5096  * @return bool|WP_Error True if allowed, false or WP_Error otherwise.
       
  5097  */
       
  5098 function wp_is_password_reset_allowed_for_user( $user ) {
       
  5099 	if ( ! is_object( $user ) ) {
       
  5100 		$user = get_userdata( $user );
       
  5101 	}
       
  5102 
       
  5103 	if ( ! $user || ! $user->exists() ) {
       
  5104 		return false;
       
  5105 	}
       
  5106 	$allow = true;
       
  5107 	if ( is_multisite() && is_user_spammy( $user ) ) {
       
  5108 		$allow = false;
       
  5109 	}
       
  5110 
       
  5111 	/**
       
  5112 	 * Filters whether to allow a password to be reset.
       
  5113 	 *
       
  5114 	 * @since 2.7.0
       
  5115 	 *
       
  5116 	 * @param bool $allow   Whether to allow the password to be reset. Default true.
       
  5117 	 * @param int  $user_id The ID of the user attempting to reset a password.
       
  5118 	 */
       
  5119 	return apply_filters( 'allow_password_reset', $allow, $user->ID );
       
  5120 }