wp/wp-admin/includes/user.php
changeset 9 177826044cd9
parent 7 cf61fcea0001
child 16 a86126ab1dd4
equal deleted inserted replaced
8:c7c34916027a 9:177826044cd9
    23  * Used on user-edit.php and profile.php to manage and process user options, passwords etc.
    23  * Used on user-edit.php and profile.php to manage and process user options, passwords etc.
    24  *
    24  *
    25  * @since 2.0.0
    25  * @since 2.0.0
    26  *
    26  *
    27  * @param int $user_id Optional. User ID.
    27  * @param int $user_id Optional. User ID.
    28  * @return int|WP_Error user id of the updated user
    28  * @return int|WP_Error user id of the updated user.
    29  */
    29  */
    30 function edit_user( $user_id = 0 ) {
    30 function edit_user( $user_id = 0 ) {
    31 	$wp_roles = wp_roles();
    31 	$wp_roles = wp_roles();
    32 	$user = new stdClass;
    32 	$user     = new stdClass;
       
    33 	$user_id  = (int) $user_id;
    33 	if ( $user_id ) {
    34 	if ( $user_id ) {
    34 		$update = true;
    35 		$update           = true;
    35 		$user->ID = (int) $user_id;
    36 		$user->ID         = $user_id;
    36 		$userdata = get_userdata( $user_id );
    37 		$userdata         = get_userdata( $user_id );
    37 		$user->user_login = wp_slash( $userdata->user_login );
    38 		$user->user_login = wp_slash( $userdata->user_login );
    38 	} else {
    39 	} else {
    39 		$update = false;
    40 		$update = false;
    40 	}
    41 	}
    41 
    42 
    42 	if ( !$update && isset( $_POST['user_login'] ) )
    43 	if ( ! $update && isset( $_POST['user_login'] ) ) {
    43 		$user->user_login = sanitize_user($_POST['user_login'], true);
    44 		$user->user_login = sanitize_user( $_POST['user_login'], true );
       
    45 	}
    44 
    46 
    45 	$pass1 = $pass2 = '';
    47 	$pass1 = $pass2 = '';
    46 	if ( isset( $_POST['pass1'] ) )
    48 	if ( isset( $_POST['pass1'] ) ) {
    47 		$pass1 = $_POST['pass1'];
    49 		$pass1 = $_POST['pass1'];
    48 	if ( isset( $_POST['pass2'] ) )
    50 	}
       
    51 	if ( isset( $_POST['pass2'] ) ) {
    49 		$pass2 = $_POST['pass2'];
    52 		$pass2 = $_POST['pass2'];
    50 
    53 	}
    51 	if ( isset( $_POST['role'] ) && current_user_can( 'edit_users' ) ) {
    54 
       
    55 	if ( isset( $_POST['role'] ) && current_user_can( 'promote_users' ) && ( ! $user_id || current_user_can( 'promote_user', $user_id ) ) ) {
    52 		$new_role = sanitize_text_field( $_POST['role'] );
    56 		$new_role = sanitize_text_field( $_POST['role'] );
    53 		$potential_role = isset($wp_roles->role_objects[$new_role]) ? $wp_roles->role_objects[$new_role] : false;
    57 
    54 		// Don't let anyone with 'edit_users' (admins) edit their own role to something without it.
    58 		// If the new role isn't editable by the logged-in user die with error.
    55 		// Multisite super admins can freely edit their blog roles -- they possess all caps.
    59 		$editable_roles = get_editable_roles();
    56 		if ( ( is_multisite() && current_user_can( 'manage_sites' ) ) || $user_id != get_current_user_id() || ($potential_role && $potential_role->has_cap( 'edit_users' ) ) )
    60 		if ( ! empty( $new_role ) && empty( $editable_roles[ $new_role ] ) ) {
       
    61 			wp_die( __( 'Sorry, you are not allowed to give users that role.' ), 403 );
       
    62 		}
       
    63 
       
    64 		$potential_role = isset( $wp_roles->role_objects[ $new_role ] ) ? $wp_roles->role_objects[ $new_role ] : false;
       
    65 
       
    66 		/*
       
    67 		 * Don't let anyone with 'promote_users' edit their own role to something without it.
       
    68 		 * Multisite super admins can freely edit their roles, they possess all caps.
       
    69 		 */
       
    70 		if (
       
    71 			( is_multisite() && current_user_can( 'manage_network_users' ) ) ||
       
    72 			$user_id !== get_current_user_id() ||
       
    73 			( $potential_role && $potential_role->has_cap( 'promote_users' ) )
       
    74 		) {
    57 			$user->role = $new_role;
    75 			$user->role = $new_role;
    58 
    76 		}
    59 		// If the new role isn't editable by the logged-in user die with error
    77 	}
    60 		$editable_roles = get_editable_roles();
    78 
    61 		if ( ! empty( $new_role ) && empty( $editable_roles[$new_role] ) )
    79 	if ( isset( $_POST['email'] ) ) {
    62 			wp_die( __( 'Sorry, you are not allowed to give users that role.' ), 403 );
       
    63 	}
       
    64 
       
    65 	if ( isset( $_POST['email'] ))
       
    66 		$user->user_email = sanitize_text_field( wp_unslash( $_POST['email'] ) );
    80 		$user->user_email = sanitize_text_field( wp_unslash( $_POST['email'] ) );
       
    81 	}
    67 	if ( isset( $_POST['url'] ) ) {
    82 	if ( isset( $_POST['url'] ) ) {
    68 		if ( empty ( $_POST['url'] ) || $_POST['url'] == 'http://' ) {
    83 		if ( empty( $_POST['url'] ) || $_POST['url'] == 'http://' ) {
    69 			$user->user_url = '';
    84 			$user->user_url = '';
    70 		} else {
    85 		} else {
    71 			$user->user_url = esc_url_raw( $_POST['url'] );
    86 			$user->user_url = esc_url_raw( $_POST['url'] );
    72 			$protocols = implode( '|', array_map( 'preg_quote', wp_allowed_protocols() ) );
    87 			$protocols      = implode( '|', array_map( 'preg_quote', wp_allowed_protocols() ) );
    73 			$user->user_url = preg_match('/^(' . $protocols . '):/is', $user->user_url) ? $user->user_url : 'http://'.$user->user_url;
    88 			$user->user_url = preg_match( '/^(' . $protocols . '):/is', $user->user_url ) ? $user->user_url : 'http://' . $user->user_url;
    74 		}
    89 		}
    75 	}
    90 	}
    76 	if ( isset( $_POST['first_name'] ) )
    91 	if ( isset( $_POST['first_name'] ) ) {
    77 		$user->first_name = sanitize_text_field( $_POST['first_name'] );
    92 		$user->first_name = sanitize_text_field( $_POST['first_name'] );
    78 	if ( isset( $_POST['last_name'] ) )
    93 	}
       
    94 	if ( isset( $_POST['last_name'] ) ) {
    79 		$user->last_name = sanitize_text_field( $_POST['last_name'] );
    95 		$user->last_name = sanitize_text_field( $_POST['last_name'] );
    80 	if ( isset( $_POST['nickname'] ) )
    96 	}
       
    97 	if ( isset( $_POST['nickname'] ) ) {
    81 		$user->nickname = sanitize_text_field( $_POST['nickname'] );
    98 		$user->nickname = sanitize_text_field( $_POST['nickname'] );
    82 	if ( isset( $_POST['display_name'] ) )
    99 	}
       
   100 	if ( isset( $_POST['display_name'] ) ) {
    83 		$user->display_name = sanitize_text_field( $_POST['display_name'] );
   101 		$user->display_name = sanitize_text_field( $_POST['display_name'] );
    84 
   102 	}
    85 	if ( isset( $_POST['description'] ) )
   103 
       
   104 	if ( isset( $_POST['description'] ) ) {
    86 		$user->description = trim( $_POST['description'] );
   105 		$user->description = trim( $_POST['description'] );
       
   106 	}
    87 
   107 
    88 	foreach ( wp_get_user_contact_methods( $user ) as $method => $name ) {
   108 	foreach ( wp_get_user_contact_methods( $user ) as $method => $name ) {
    89 		if ( isset( $_POST[$method] ))
   109 		if ( isset( $_POST[ $method ] ) ) {
    90 			$user->$method = sanitize_text_field( $_POST[$method] );
   110 			$user->$method = sanitize_text_field( $_POST[ $method ] );
       
   111 		}
    91 	}
   112 	}
    92 
   113 
    93 	if ( $update ) {
   114 	if ( $update ) {
    94 		$user->rich_editing = isset( $_POST['rich_editing'] ) && 'false' === $_POST['rich_editing'] ? 'false' : 'true';
   115 		$user->rich_editing         = isset( $_POST['rich_editing'] ) && 'false' === $_POST['rich_editing'] ? 'false' : 'true';
    95 		$user->syntax_highlighting = isset( $_POST['syntax_highlighting'] ) && 'false' === $_POST['syntax_highlighting'] ? 'false' : 'true';
   116 		$user->syntax_highlighting  = isset( $_POST['syntax_highlighting'] ) && 'false' === $_POST['syntax_highlighting'] ? 'false' : 'true';
    96 		$user->admin_color = isset( $_POST['admin_color'] ) ? sanitize_text_field( $_POST['admin_color'] ) : 'fresh';
   117 		$user->admin_color          = isset( $_POST['admin_color'] ) ? sanitize_text_field( $_POST['admin_color'] ) : 'fresh';
    97 		$user->show_admin_bar_front = isset( $_POST['admin_bar_front'] ) ? 'true' : 'false';
   118 		$user->show_admin_bar_front = isset( $_POST['admin_bar_front'] ) ? 'true' : 'false';
    98 		$user->locale = '';
   119 		$user->locale               = '';
    99 
   120 
   100 		if ( isset( $_POST['locale'] ) ) {
   121 		if ( isset( $_POST['locale'] ) ) {
   101 			$locale = sanitize_text_field( $_POST['locale'] );
   122 			$locale = sanitize_text_field( $_POST['locale'] );
   102 			if ( 'site-default' === $locale ) {
   123 			if ( 'site-default' === $locale ) {
   103 				$locale = '';
   124 				$locale = '';
   112 	}
   133 	}
   113 
   134 
   114 	$user->comment_shortcuts = isset( $_POST['comment_shortcuts'] ) && 'true' == $_POST['comment_shortcuts'] ? 'true' : '';
   135 	$user->comment_shortcuts = isset( $_POST['comment_shortcuts'] ) && 'true' == $_POST['comment_shortcuts'] ? 'true' : '';
   115 
   136 
   116 	$user->use_ssl = 0;
   137 	$user->use_ssl = 0;
   117 	if ( !empty($_POST['use_ssl']) )
   138 	if ( ! empty( $_POST['use_ssl'] ) ) {
   118 		$user->use_ssl = 1;
   139 		$user->use_ssl = 1;
       
   140 	}
   119 
   141 
   120 	$errors = new WP_Error();
   142 	$errors = new WP_Error();
   121 
   143 
   122 	/* checking that username has been typed */
   144 	/* checking that username has been typed */
   123 	if ( $user->user_login == '' )
   145 	if ( $user->user_login == '' ) {
   124 		$errors->add( 'user_login', __( '<strong>ERROR</strong>: Please enter a username.' ) );
   146 		$errors->add( 'user_login', __( '<strong>ERROR</strong>: Please enter a username.' ) );
       
   147 	}
   125 
   148 
   126 	/* checking that nickname has been typed */
   149 	/* checking that nickname has been typed */
   127 	if ( $update && empty( $user->nickname ) ) {
   150 	if ( $update && empty( $user->nickname ) ) {
   128 		$errors->add( 'nickname', __( '<strong>ERROR</strong>: Please enter a nickname.' ) );
   151 		$errors->add( 'nickname', __( '<strong>ERROR</strong>: Please enter a nickname.' ) );
   129 	}
   152 	}
   143 	if ( ! $update && empty( $pass1 ) ) {
   166 	if ( ! $update && empty( $pass1 ) ) {
   144 		$errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter a password.' ), array( 'form-field' => 'pass1' ) );
   167 		$errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter a password.' ), array( 'form-field' => 'pass1' ) );
   145 	}
   168 	}
   146 
   169 
   147 	// Check for "\" in password.
   170 	// Check for "\" in password.
   148 	if ( false !== strpos( wp_unslash( $pass1 ), "\\" ) ) {
   171 	if ( false !== strpos( wp_unslash( $pass1 ), '\\' ) ) {
   149 		$errors->add( 'pass', __( '<strong>ERROR</strong>: Passwords may not contain the character "\\".' ), array( 'form-field' => 'pass1' ) );
   172 		$errors->add( 'pass', __( '<strong>ERROR</strong>: Passwords may not contain the character "\\".' ), array( 'form-field' => 'pass1' ) );
   150 	}
   173 	}
   151 
   174 
   152 	// Checking the password has been typed twice the same.
   175 	// Checking the password has been typed twice the same.
   153 	if ( ( $update || ! empty( $pass1 ) ) && $pass1 != $pass2 ) {
   176 	if ( ( $update || ! empty( $pass1 ) ) && $pass1 != $pass2 ) {
   154 		$errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter the same password in both password fields.' ), array( 'form-field' => 'pass1' ) );
   177 		$errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter the same password in both password fields.' ), array( 'form-field' => 'pass1' ) );
   155 	}
   178 	}
   156 
   179 
   157 	if ( !empty( $pass1 ) )
   180 	if ( ! empty( $pass1 ) ) {
   158 		$user->user_pass = $pass1;
   181 		$user->user_pass = $pass1;
   159 
   182 	}
   160 	if ( !$update && isset( $_POST['user_login'] ) && !validate_username( $_POST['user_login'] ) )
   183 
   161 		$errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ));
   184 	if ( ! $update && isset( $_POST['user_login'] ) && ! validate_username( $_POST['user_login'] ) ) {
   162 
   185 		$errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ) );
   163 	if ( !$update && username_exists( $user->user_login ) )
   186 	}
   164 		$errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ));
   187 
       
   188 	if ( ! $update && username_exists( $user->user_login ) ) {
       
   189 		$errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ) );
       
   190 	}
   165 
   191 
   166 	/** This filter is documented in wp-includes/user.php */
   192 	/** This filter is documented in wp-includes/user.php */
   167 	$illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
   193 	$illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
   168 
   194 
   169 	if ( in_array( strtolower( $user->user_login ), array_map( 'strtolower', $illegal_logins ) ) ) {
   195 	if ( in_array( strtolower( $user->user_login ), array_map( 'strtolower', $illegal_logins ) ) ) {
   171 	}
   197 	}
   172 
   198 
   173 	/* checking email address */
   199 	/* checking email address */
   174 	if ( empty( $user->user_email ) ) {
   200 	if ( empty( $user->user_email ) ) {
   175 		$errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please enter an email address.' ), array( 'form-field' => 'email' ) );
   201 		$errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please enter an email address.' ), array( 'form-field' => 'email' ) );
   176 	} elseif ( !is_email( $user->user_email ) ) {
   202 	} elseif ( ! is_email( $user->user_email ) ) {
   177 		$errors->add( 'invalid_email', __( '<strong>ERROR</strong>: The email address isn&#8217;t correct.' ), array( 'form-field' => 'email' ) );
   203 		$errors->add( 'invalid_email', __( '<strong>ERROR</strong>: The email address isn&#8217;t correct.' ), array( 'form-field' => 'email' ) );
   178 	} elseif ( ( $owner_id = email_exists($user->user_email) ) && ( !$update || ( $owner_id != $user->ID ) ) ) {
   204 	} elseif ( ( $owner_id = email_exists( $user->user_email ) ) && ( ! $update || ( $owner_id != $user->ID ) ) ) {
   179 		$errors->add( 'email_exists', __('<strong>ERROR</strong>: This email is already registered, please choose another one.'), array( 'form-field' => 'email' ) );
   205 		$errors->add( 'email_exists', __( '<strong>ERROR</strong>: This email is already registered, please choose another one.' ), array( 'form-field' => 'email' ) );
   180 	}
   206 	}
   181 
   207 
   182 	/**
   208 	/**
   183 	 * Fires before user profile update errors are returned.
   209 	 * Fires before user profile update errors are returned.
   184 	 *
   210 	 *
   188 	 * @param bool     $update  Whether this is a user update.
   214 	 * @param bool     $update  Whether this is a user update.
   189 	 * @param stdClass $user   User object (passed by reference).
   215 	 * @param stdClass $user   User object (passed by reference).
   190 	 */
   216 	 */
   191 	do_action_ref_array( 'user_profile_update_errors', array( &$errors, $update, &$user ) );
   217 	do_action_ref_array( 'user_profile_update_errors', array( &$errors, $update, &$user ) );
   192 
   218 
   193 	if ( $errors->get_error_codes() )
   219 	if ( $errors->has_errors() ) {
   194 		return $errors;
   220 		return $errors;
       
   221 	}
   195 
   222 
   196 	if ( $update ) {
   223 	if ( $update ) {
   197 		$user_id = wp_update_user( $user );
   224 		$user_id = wp_update_user( $user );
   198 	} else {
   225 	} else {
   199 		$user_id = wp_insert_user( $user );
   226 		$user_id = wp_insert_user( $user );
   200 		$notify  = isset( $_POST['send_user_notification'] ) ? 'both' : 'admin';
   227 		$notify  = isset( $_POST['send_user_notification'] ) ? 'both' : 'admin';
   201 
   228 
   202 		/**
   229 		/**
   203 		  * Fires after a new user has been created.
   230 		 * Fires after a new user has been created.
   204 		  *
   231 		 *
   205 		  * @since 4.4.0
   232 		 * @since 4.4.0
   206 		  *
   233 		 *
   207 		  * @param int    $user_id ID of the newly created user.
   234 		 * @param int    $user_id ID of the newly created user.
   208 		  * @param string $notify  Type of notification that should happen. See wp_send_new_user_notifications()
   235 		 * @param string $notify  Type of notification that should happen. See wp_send_new_user_notifications()
   209 		  *                        for more information on possible values.
   236 		 *                        for more information on possible values.
   210 		  */
   237 		 */
   211 		do_action( 'edit_user_created_user', $user_id, $notify );
   238 		do_action( 'edit_user_created_user', $user_id, $notify );
   212 	}
   239 	}
   213 	return $user_id;
   240 	return $user_id;
   214 }
   241 }
   215 
   242 
   216 /**
   243 /**
   217  * Fetch a filtered list of user roles that the current user is
   244  * Fetch a filtered list of user roles that the current user is
   218  * allowed to edit.
   245  * allowed to edit.
   219  *
   246  *
   220  * Simple function who's main purpose is to allow filtering of the
   247  * Simple function whose main purpose is to allow filtering of the
   221  * list of roles in the $wp_roles object so that plugins can remove
   248  * list of roles in the $wp_roles object so that plugins can remove
   222  * inappropriate ones depending on the situation or user making edits.
   249  * inappropriate ones depending on the situation or user making edits.
   223  * Specifically because without filtering anyone with the edit_users
   250  * Specifically because without filtering anyone with the edit_users
   224  * capability can edit others to be administrators, even if they are
   251  * capability can edit others to be administrators, even if they are
   225  * only editors or authors. This filter allows admins to delegate
   252  * only editors or authors. This filter allows admins to delegate
   226  * user management.
   253  * user management.
   227  *
   254  *
   228  * @since 2.8.0
   255  * @since 2.8.0
   229  *
   256  *
   230  * @return array
   257  * @return array[] Array of arrays containing role information.
   231  */
   258  */
   232 function get_editable_roles() {
   259 function get_editable_roles() {
   233 	$all_roles = wp_roles()->roles;
   260 	$all_roles = wp_roles()->roles;
   234 
   261 
   235 	/**
   262 	/**
   236 	 * Filters the list of editable roles.
   263 	 * Filters the list of editable roles.
   237 	 *
   264 	 *
   238 	 * @since 2.8.0
   265 	 * @since 2.8.0
   239 	 *
   266 	 *
   240 	 * @param array $all_roles List of roles.
   267 	 * @param array[] $all_roles Array of arrays containing role information.
   241 	 */
   268 	 */
   242 	$editable_roles = apply_filters( 'editable_roles', $all_roles );
   269 	$editable_roles = apply_filters( 'editable_roles', $all_roles );
   243 
   270 
   244 	return $editable_roles;
   271 	return $editable_roles;
   245 }
   272 }
   253  * @return WP_User|bool WP_User object on success, false on failure.
   280  * @return WP_User|bool WP_User object on success, false on failure.
   254  */
   281  */
   255 function get_user_to_edit( $user_id ) {
   282 function get_user_to_edit( $user_id ) {
   256 	$user = get_userdata( $user_id );
   283 	$user = get_userdata( $user_id );
   257 
   284 
   258 	if ( $user )
   285 	if ( $user ) {
   259 		$user->filter = 'edit';
   286 		$user->filter = 'edit';
       
   287 	}
   260 
   288 
   261 	return $user;
   289 	return $user;
   262 }
   290 }
   263 
   291 
   264 /**
   292 /**
   271  * @param int $user_id User ID.
   299  * @param int $user_id User ID.
   272  * @return array
   300  * @return array
   273  */
   301  */
   274 function get_users_drafts( $user_id ) {
   302 function get_users_drafts( $user_id ) {
   275 	global $wpdb;
   303 	global $wpdb;
   276 	$query = $wpdb->prepare("SELECT ID, post_title FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'draft' AND post_author = %d ORDER BY post_modified DESC", $user_id);
   304 	$query = $wpdb->prepare( "SELECT ID, post_title FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'draft' AND post_author = %d ORDER BY post_modified DESC", $user_id );
   277 
   305 
   278 	/**
   306 	/**
   279 	 * Filters the user's drafts query string.
   307 	 * Filters the user's drafts query string.
   280 	 *
   308 	 *
   281 	 * @since 2.0.0
   309 	 * @since 2.0.0
   307 
   335 
   308 	if ( ! is_numeric( $id ) ) {
   336 	if ( ! is_numeric( $id ) ) {
   309 		return false;
   337 		return false;
   310 	}
   338 	}
   311 
   339 
   312 	$id = (int) $id;
   340 	$id   = (int) $id;
   313 	$user = new WP_User( $id );
   341 	$user = new WP_User( $id );
   314 
   342 
   315 	if ( !$user->exists() )
   343 	if ( ! $user->exists() ) {
   316 		return false;
   344 		return false;
       
   345 	}
   317 
   346 
   318 	// Normalize $reassign to null or a user ID. 'novalue' was an older default.
   347 	// Normalize $reassign to null or a user ID. 'novalue' was an older default.
   319 	if ( 'novalue' === $reassign ) {
   348 	if ( 'novalue' === $reassign ) {
   320 		$reassign = null;
   349 		$reassign = null;
   321 	} elseif ( null !== $reassign ) {
   350 	} elseif ( null !== $reassign ) {
   346 		/**
   375 		/**
   347 		 * Filters the list of post types to delete with a user.
   376 		 * Filters the list of post types to delete with a user.
   348 		 *
   377 		 *
   349 		 * @since 3.4.0
   378 		 * @since 3.4.0
   350 		 *
   379 		 *
   351 		 * @param array $post_types_to_delete Post types to delete.
   380 		 * @param string[] $post_types_to_delete Array of post types to delete.
   352 		 * @param int   $id                   User ID.
   381 		 * @param int      $id                   User ID.
   353 		 */
   382 		 */
   354 		$post_types_to_delete = apply_filters( 'post_types_to_delete_with_user', $post_types_to_delete, $id );
   383 		$post_types_to_delete = apply_filters( 'post_types_to_delete_with_user', $post_types_to_delete, $id );
   355 		$post_types_to_delete = implode( "', '", $post_types_to_delete );
   384 		$post_types_to_delete = implode( "', '", $post_types_to_delete );
   356 		$post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d AND post_type IN ('$post_types_to_delete')", $id ) );
   385 		$post_ids             = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d AND post_type IN ('$post_types_to_delete')", $id ) );
   357 		if ( $post_ids ) {
   386 		if ( $post_ids ) {
   358 			foreach ( $post_ids as $post_id )
   387 			foreach ( $post_ids as $post_id ) {
   359 				wp_delete_post( $post_id );
   388 				wp_delete_post( $post_id );
       
   389 			}
   360 		}
   390 		}
   361 
   391 
   362 		// Clean links
   392 		// Clean links
   363 		$link_ids = $wpdb->get_col( $wpdb->prepare("SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id) );
   393 		$link_ids = $wpdb->get_col( $wpdb->prepare( "SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id ) );
   364 
   394 
   365 		if ( $link_ids ) {
   395 		if ( $link_ids ) {
   366 			foreach ( $link_ids as $link_id )
   396 			foreach ( $link_ids as $link_id ) {
   367 				wp_delete_link($link_id);
   397 				wp_delete_link( $link_id );
       
   398 			}
   368 		}
   399 		}
   369 	} else {
   400 	} else {
   370 		$post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d", $id ) );
   401 		$post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d", $id ) );
   371 		$wpdb->update( $wpdb->posts, array('post_author' => $reassign), array('post_author' => $id) );
   402 		$wpdb->update( $wpdb->posts, array( 'post_author' => $reassign ), array( 'post_author' => $id ) );
   372 		if ( ! empty( $post_ids ) ) {
   403 		if ( ! empty( $post_ids ) ) {
   373 			foreach ( $post_ids as $post_id )
   404 			foreach ( $post_ids as $post_id ) {
   374 				clean_post_cache( $post_id );
   405 				clean_post_cache( $post_id );
   375 		}
   406 			}
   376 		$link_ids = $wpdb->get_col( $wpdb->prepare("SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id) );
   407 		}
   377 		$wpdb->update( $wpdb->links, array('link_owner' => $reassign), array('link_owner' => $id) );
   408 		$link_ids = $wpdb->get_col( $wpdb->prepare( "SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id ) );
       
   409 		$wpdb->update( $wpdb->links, array( 'link_owner' => $reassign ), array( 'link_owner' => $id ) );
   378 		if ( ! empty( $link_ids ) ) {
   410 		if ( ! empty( $link_ids ) ) {
   379 			foreach ( $link_ids as $link_id )
   411 			foreach ( $link_ids as $link_id ) {
   380 				clean_bookmark_cache( $link_id );
   412 				clean_bookmark_cache( $link_id );
       
   413 			}
   381 		}
   414 		}
   382 	}
   415 	}
   383 
   416 
   384 	// FINALLY, delete user
   417 	// FINALLY, delete user
   385 	if ( is_multisite() ) {
   418 	if ( is_multisite() ) {
   386 		remove_user_from_blog( $id, get_current_blog_id() );
   419 		remove_user_from_blog( $id, get_current_blog_id() );
   387 	} else {
   420 	} else {
   388 		$meta = $wpdb->get_col( $wpdb->prepare( "SELECT umeta_id FROM $wpdb->usermeta WHERE user_id = %d", $id ) );
   421 		$meta = $wpdb->get_col( $wpdb->prepare( "SELECT umeta_id FROM $wpdb->usermeta WHERE user_id = %d", $id ) );
   389 		foreach ( $meta as $mid )
   422 		foreach ( $meta as $mid ) {
   390 			delete_metadata_by_mid( 'user', $mid );
   423 			delete_metadata_by_mid( 'user', $mid );
       
   424 		}
   391 
   425 
   392 		$wpdb->delete( $wpdb->users, array( 'ID' => $id ) );
   426 		$wpdb->delete( $wpdb->users, array( 'ID' => $id ) );
   393 	}
   427 	}
   394 
   428 
   395 	clean_user_cache( $user );
   429 	clean_user_cache( $user );
   413  *
   447  *
   414  * @since 2.1.0
   448  * @since 2.1.0
   415  *
   449  *
   416  * @param int $id User ID.
   450  * @param int $id User ID.
   417  */
   451  */
   418 function wp_revoke_user($id) {
   452 function wp_revoke_user( $id ) {
   419 	$id = (int) $id;
   453 	$id = (int) $id;
   420 
   454 
   421 	$user = new WP_User($id);
   455 	$user = new WP_User( $id );
   422 	$user->remove_all_caps();
   456 	$user->remove_all_caps();
   423 }
   457 }
   424 
   458 
   425 /**
   459 /**
   426  * @since 2.8.0
   460  * @since 2.8.0
   427  *
   461  *
   428  * @global int $user_ID
   462  * @global int $user_ID
   429  *
   463  *
   430  * @param false $errors Deprecated.
   464  * @param false $errors Deprecated.
   431  */
   465  */
   432 function default_password_nag_handler($errors = false) {
   466 function default_password_nag_handler( $errors = false ) {
   433 	global $user_ID;
   467 	global $user_ID;
   434 	// Short-circuit it.
   468 	// Short-circuit it.
   435 	if ( ! get_user_option('default_password_nag') )
   469 	if ( ! get_user_option( 'default_password_nag' ) ) {
   436 		return;
   470 		return;
       
   471 	}
   437 
   472 
   438 	// get_user_setting = JS saved UI setting. else no-js-fallback code.
   473 	// get_user_setting = JS saved UI setting. else no-js-fallback code.
   439 	if ( 'hide' == get_user_setting('default_password_nag') || isset($_GET['default_password_nag']) && '0' == $_GET['default_password_nag'] ) {
   474 	if ( 'hide' == get_user_setting( 'default_password_nag' ) || isset( $_GET['default_password_nag'] ) && '0' == $_GET['default_password_nag'] ) {
   440 		delete_user_setting('default_password_nag');
   475 		delete_user_setting( 'default_password_nag' );
   441 		update_user_option($user_ID, 'default_password_nag', false, true);
   476 		update_user_option( $user_ID, 'default_password_nag', false, true );
   442 	}
   477 	}
   443 }
   478 }
   444 
   479 
   445 /**
   480 /**
   446  * @since 2.8.0
   481  * @since 2.8.0
   447  *
   482  *
   448  * @param int    $user_ID
   483  * @param int    $user_ID
   449  * @param object $old_data
   484  * @param object $old_data
   450  */
   485  */
   451 function default_password_nag_edit_user($user_ID, $old_data) {
   486 function default_password_nag_edit_user( $user_ID, $old_data ) {
   452 	// Short-circuit it.
   487 	// Short-circuit it.
   453 	if ( ! get_user_option('default_password_nag', $user_ID) )
   488 	if ( ! get_user_option( 'default_password_nag', $user_ID ) ) {
   454 		return;
   489 		return;
   455 
   490 	}
   456 	$new_data = get_userdata($user_ID);
   491 
       
   492 	$new_data = get_userdata( $user_ID );
   457 
   493 
   458 	// Remove the nag if the password has been changed.
   494 	// Remove the nag if the password has been changed.
   459 	if ( $new_data->user_pass != $old_data->user_pass ) {
   495 	if ( $new_data->user_pass != $old_data->user_pass ) {
   460 		delete_user_setting('default_password_nag');
   496 		delete_user_setting( 'default_password_nag' );
   461 		update_user_option($user_ID, 'default_password_nag', false, true);
   497 		update_user_option( $user_ID, 'default_password_nag', false, true );
   462 	}
   498 	}
   463 }
   499 }
   464 
   500 
   465 /**
   501 /**
   466  * @since 2.8.0
   502  * @since 2.8.0
   468  * @global string $pagenow
   504  * @global string $pagenow
   469  */
   505  */
   470 function default_password_nag() {
   506 function default_password_nag() {
   471 	global $pagenow;
   507 	global $pagenow;
   472 	// Short-circuit it.
   508 	// Short-circuit it.
   473 	if ( 'profile.php' == $pagenow || ! get_user_option('default_password_nag') )
   509 	if ( 'profile.php' == $pagenow || ! get_user_option( 'default_password_nag' ) ) {
   474 		return;
   510 		return;
       
   511 	}
   475 
   512 
   476 	echo '<div class="error default-password-nag">';
   513 	echo '<div class="error default-password-nag">';
   477 	echo '<p>';
   514 	echo '<p>';
   478 	echo '<strong>' . __('Notice:') . '</strong> ';
   515 	echo '<strong>' . __( 'Notice:' ) . '</strong> ';
   479 	_e('You&rsquo;re using the auto-generated password for your account. Would you like to change it?');
   516 	_e( 'You&rsquo;re using the auto-generated password for your account. Would you like to change it?' );
   480 	echo '</p><p>';
   517 	echo '</p><p>';
   481 	printf( '<a href="%s">' . __('Yes, take me to my profile page') . '</a> | ', get_edit_profile_url() . '#password' );
   518 	printf( '<a href="%s">' . __( 'Yes, take me to my profile page' ) . '</a> | ', get_edit_profile_url() . '#password' );
   482 	printf( '<a href="%s" id="default-password-nag-no">' . __('No thanks, do not remind me again') . '</a>', '?default_password_nag=0' );
   519 	printf( '<a href="%s" id="default-password-nag-no">' . __( 'No thanks, do not remind me again' ) . '</a>', '?default_password_nag=0' );
   483 	echo '</p></div>';
   520 	echo '</p></div>';
   484 }
   521 }
   485 
   522 
   486 /**
   523 /**
   487  * @since 3.5.0
   524  * @since 3.5.0
   488  * @access private
   525  * @access private
   489  */
   526  */
   490 function delete_users_add_js() { ?>
   527 function delete_users_add_js() {
       
   528 	?>
   491 <script>
   529 <script>
   492 jQuery(document).ready( function($) {
   530 jQuery(document).ready( function($) {
   493 	var submit = $('#submit').prop('disabled', true);
   531 	var submit = $('#submit').prop('disabled', true);
   494 	$('input[name="delete_option"]').one('change', function() {
   532 	$('input[name="delete_option"]').one('change', function() {
   495 		submit.prop('disabled', false);
   533 		submit.prop('disabled', false);
   497 	$('#reassign_user').focus( function() {
   535 	$('#reassign_user').focus( function() {
   498 		$('#delete_option1').prop('checked', true).trigger('change');
   536 		$('#delete_option1').prop('checked', true).trigger('change');
   499 	});
   537 	});
   500 });
   538 });
   501 </script>
   539 </script>
   502 <?php
   540 	<?php
   503 }
   541 }
   504 
   542 
   505 /**
   543 /**
   506  * Optional SSL preference that can be turned on by hooking to the 'personal_options' action.
   544  * Optional SSL preference that can be turned on by hooking to the 'personal_options' action.
   507  *
   545  *
   508  * See the {@see 'personal_options'} action.
   546  * See the {@see 'personal_options'} action.
   509  *
   547  *
   510  * @since 2.7.0
   548  * @since 2.7.0
   511  *
   549  *
   512  * @param object $user User data object
   550  * @param object $user User data object.
   513  */
   551  */
   514 function use_ssl_preference($user) {
   552 function use_ssl_preference( $user ) {
   515 ?>
   553 	?>
   516 	<tr class="user-use-ssl-wrap">
   554 	<tr class="user-use-ssl-wrap">
   517 		<th scope="row"><?php _e('Use https')?></th>
   555 		<th scope="row"><?php _e( 'Use https' ); ?></th>
   518 		<td><label for="use_ssl"><input name="use_ssl" type="checkbox" id="use_ssl" value="1" <?php checked('1', $user->use_ssl); ?> /> <?php _e('Always use https when visiting the admin'); ?></label></td>
   556 		<td><label for="use_ssl"><input name="use_ssl" type="checkbox" id="use_ssl" value="1" <?php checked( '1', $user->use_ssl ); ?> /> <?php _e( 'Always use https when visiting the admin' ); ?></label></td>
   519 	</tr>
   557 	</tr>
   520 <?php
   558 	<?php
   521 }
   559 }
   522 
   560 
   523 /**
   561 /**
   524  *
       
   525  * @param string $text
   562  * @param string $text
   526  * @return string
   563  * @return string
   527  */
   564  */
   528 function admin_created_user_email( $text ) {
   565 function admin_created_user_email( $text ) {
   529 	$roles = get_editable_roles();
   566 	$roles = get_editable_roles();
   530 	$role = $roles[ $_REQUEST['role'] ];
   567 	$role  = $roles[ $_REQUEST['role'] ];
   531 	/* translators: 1: Site name, 2: site URL, 3: role */
   568 	/* translators: 1: site name, 2: site URL, 3: role */
   532 	return sprintf( __( 'Hi,
   569 	return sprintf(
       
   570 		__(
       
   571 			'Hi,
   533 You\'ve been invited to join \'%1$s\' at
   572 You\'ve been invited to join \'%1$s\' at
   534 %2$s with the role of %3$s.
   573 %2$s with the role of %3$s.
   535 If you do not want to join this site please ignore
   574 If you do not want to join this site please ignore
   536 this email. This invitation will expire in a few days.
   575 this email. This invitation will expire in a few days.
   537 
   576 
   538 Please click the following link to activate your user account:
   577 Please click the following link to activate your user account:
   539 %%s' ), wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ), home_url(), wp_specialchars_decode( translate_user_role( $role['name'] ) ) );
   578 %%s'
       
   579 		),
       
   580 		wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ),
       
   581 		home_url(),
       
   582 		wp_specialchars_decode( translate_user_role( $role['name'] ) )
       
   583 	);
   540 }
   584 }
   541 
   585 
   542 /**
   586 /**
   543  * Resend an existing request and return the result.
   587  * Resend an existing request and return the result.
   544  *
   588  *
   572  *
   616  *
   573  * @since 4.9.6
   617  * @since 4.9.6
   574  * @access private
   618  * @access private
   575  *
   619  *
   576  * @param  int          $request_id Request ID.
   620  * @param  int          $request_id Request ID.
   577  * @return int|WP_Error $request    Request ID on success or WP_Error.
   621  * @return int|WP_Error $result Request ID on success or WP_Error.
   578  */
   622  */
   579 function _wp_privacy_completed_request( $request_id ) {
   623 function _wp_privacy_completed_request( $request_id ) {
   580 	$request_id   = absint( $request_id );
   624 	$request_id = absint( $request_id );
   581 	$request_data = wp_get_user_request_data( $request_id );
   625 	$request    = wp_get_user_request_data( $request_id );
   582 
   626 
   583 	if ( ! $request_data ) {
   627 	if ( ! $request ) {
   584 		return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) );
   628 		return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) );
   585 	}
   629 	}
   586 
   630 
   587 	update_post_meta( $request_id, '_wp_user_request_completed_timestamp', time() );
   631 	update_post_meta( $request_id, '_wp_user_request_completed_timestamp', time() );
   588 
   632 
   589 	$request = wp_update_post( array(
   633 	$result = wp_update_post(
   590 		'ID'          => $request_id,
   634 		array(
   591 		'post_status' => 'request-completed',
   635 			'ID'          => $request_id,
   592 	) );
   636 			'post_status' => 'request-completed',
   593 
   637 		)
   594 	return $request;
   638 	);
       
   639 
       
   640 	return $result;
   595 }
   641 }
   596 
   642 
   597 /**
   643 /**
   598  * Handle list table actions.
   644  * Handle list table actions.
   599  *
   645  *
   710  * @since 4.9.6
   756  * @since 4.9.6
   711  * @access private
   757  * @access private
   712  */
   758  */
   713 function _wp_personal_data_cleanup_requests() {
   759 function _wp_personal_data_cleanup_requests() {
   714 	/** This filter is documented in wp-includes/user.php */
   760 	/** This filter is documented in wp-includes/user.php */
   715 	$expires        = (int) apply_filters( 'user_request_key_expiration', DAY_IN_SECONDS );
   761 	$expires = (int) apply_filters( 'user_request_key_expiration', DAY_IN_SECONDS );
   716 
   762 
   717 	$requests_query = new WP_Query( array(
   763 	$requests_query = new WP_Query(
   718 		'post_type'      => 'user_request',
   764 		array(
   719 		'posts_per_page' => -1,
   765 			'post_type'      => 'user_request',
   720 		'post_status'    => 'request-pending',
   766 			'posts_per_page' => -1,
   721 		'fields'         => 'ids',
   767 			'post_status'    => 'request-pending',
   722 		'date_query'     => array(
   768 			'fields'         => 'ids',
       
   769 			'date_query'     => array(
       
   770 				array(
       
   771 					'column' => 'post_modified_gmt',
       
   772 					'before' => $expires . ' seconds ago',
       
   773 				),
       
   774 			),
       
   775 		)
       
   776 	);
       
   777 
       
   778 	$request_ids = $requests_query->posts;
       
   779 
       
   780 	foreach ( $request_ids as $request_id ) {
       
   781 		wp_update_post(
   723 			array(
   782 			array(
   724 				'column' => 'post_modified_gmt',
   783 				'ID'            => $request_id,
   725 				'before' => $expires . ' seconds ago',
   784 				'post_status'   => 'request-failed',
   726 			),
   785 				'post_password' => '',
   727 		),
   786 			)
   728 	) );
   787 		);
   729 
       
   730 	$request_ids = $requests_query->posts;
       
   731 
       
   732 	foreach ( $request_ids as $request_id ) {
       
   733 		wp_update_post( array(
       
   734 			'ID'            => $request_id,
       
   735 			'post_status'   => 'request-failed',
       
   736 			'post_password' => '',
       
   737 		) );
       
   738 	}
   788 	}
   739 }
   789 }
   740 
   790 
   741 /**
   791 /**
   742  * Personal data export.
   792  * Personal data export.
   753 	_wp_personal_data_cleanup_requests();
   803 	_wp_personal_data_cleanup_requests();
   754 
   804 
   755 	// "Borrow" xfn.js for now so we don't have to create new files.
   805 	// "Borrow" xfn.js for now so we don't have to create new files.
   756 	wp_enqueue_script( 'xfn' );
   806 	wp_enqueue_script( 'xfn' );
   757 
   807 
   758 	$requests_table = new WP_Privacy_Data_Export_Requests_Table( array(
   808 	$requests_table = new WP_Privacy_Data_Export_Requests_Table(
   759 		'plural'   => 'privacy_requests',
   809 		array(
   760 		'singular' => 'privacy_request',
   810 			'plural'   => 'privacy_requests',
   761 	) );
   811 			'singular' => 'privacy_request',
       
   812 			'screen'   => 'export_personal_data',
       
   813 		)
       
   814 	);
       
   815 
       
   816 	$requests_table->screen->set_screen_reader_content(
       
   817 		array(
       
   818 			'heading_views'      => __( 'Filter export personal data list' ),
       
   819 			'heading_pagination' => __( 'Export personal data list navigation' ),
       
   820 			'heading_list'       => __( 'Export personal data list' ),
       
   821 		)
       
   822 	);
       
   823 
   762 	$requests_table->process_bulk_action();
   824 	$requests_table->process_bulk_action();
   763 	$requests_table->prepare_items();
   825 	$requests_table->prepare_items();
   764 	?>
   826 	?>
   765 	<div class="wrap nosubsub">
   827 	<div class="wrap nosubsub">
   766 		<h1><?php esc_html_e( 'Export Personal Data' ); ?></h1>
   828 		<h1><?php esc_html_e( 'Export Personal Data' ); ?></h1>
   767 		<hr class="wp-header-end" />
   829 		<hr class="wp-header-end" />
   768 
   830 
   769 		<?php settings_errors(); ?>
   831 		<?php settings_errors(); ?>
   770 
   832 
   771 		<form method="post" class="wp-privacy-request-form">
   833 		<form action="<?php echo esc_url( admin_url( 'tools.php?page=export_personal_data' ) ); ?>" method="post" class="wp-privacy-request-form">
   772 			<h2><?php esc_html_e( 'Add Data Export Request' ); ?></h2>
   834 			<h2><?php esc_html_e( 'Add Data Export Request' ); ?></h2>
   773 			<p><?php esc_html_e( 'An email will be sent to the user at this email address asking them to verify the request.' ); ?></p>
   835 			<p><?php esc_html_e( 'An email will be sent to the user at this email address asking them to verify the request.' ); ?></p>
   774 
   836 
   775 			<div class="wp-privacy-request-form-field">
   837 			<div class="wp-privacy-request-form-field">
   776 				<label for="username_or_email_for_privacy_request"><?php esc_html_e( 'Username or email address' ); ?></label>
   838 				<label for="username_or_email_for_privacy_request"><?php esc_html_e( 'Username or email address' ); ?></label>
   824 	_wp_personal_data_cleanup_requests();
   886 	_wp_personal_data_cleanup_requests();
   825 
   887 
   826 	// "Borrow" xfn.js for now so we don't have to create new files.
   888 	// "Borrow" xfn.js for now so we don't have to create new files.
   827 	wp_enqueue_script( 'xfn' );
   889 	wp_enqueue_script( 'xfn' );
   828 
   890 
   829 	$requests_table = new WP_Privacy_Data_Removal_Requests_Table( array(
   891 	$requests_table = new WP_Privacy_Data_Removal_Requests_Table(
   830 		'plural'   => 'privacy_requests',
   892 		array(
   831 		'singular' => 'privacy_request',
   893 			'plural'   => 'privacy_requests',
   832 	) );
   894 			'singular' => 'privacy_request',
       
   895 			'screen'   => 'remove_personal_data',
       
   896 		)
       
   897 	);
       
   898 
       
   899 	$requests_table->screen->set_screen_reader_content(
       
   900 		array(
       
   901 			'heading_views'      => __( 'Filter erase personal data list' ),
       
   902 			'heading_pagination' => __( 'Erase personal data list navigation' ),
       
   903 			'heading_list'       => __( 'Erase personal data list' ),
       
   904 		)
       
   905 	);
   833 
   906 
   834 	$requests_table->process_bulk_action();
   907 	$requests_table->process_bulk_action();
   835 	$requests_table->prepare_items();
   908 	$requests_table->prepare_items();
   836 
   909 
   837 	?>
   910 	?>
   839 		<h1><?php esc_html_e( 'Erase Personal Data' ); ?></h1>
   912 		<h1><?php esc_html_e( 'Erase Personal Data' ); ?></h1>
   840 		<hr class="wp-header-end" />
   913 		<hr class="wp-header-end" />
   841 
   914 
   842 		<?php settings_errors(); ?>
   915 		<?php settings_errors(); ?>
   843 
   916 
   844 		<form method="post" class="wp-privacy-request-form">
   917 		<form action="<?php echo esc_url( admin_url( 'tools.php?page=remove_personal_data' ) ); ?>" method="post" class="wp-privacy-request-form">
   845 			<h2><?php esc_html_e( 'Add Data Erasure Request' ); ?></h2>
   918 			<h2><?php esc_html_e( 'Add Data Erasure Request' ); ?></h2>
   846 			<p><?php esc_html_e( 'An email will be sent to the user at this email address asking them to verify the request.' ); ?></p>
   919 			<p><?php esc_html_e( 'An email will be sent to the user at this email address asking them to verify the request.' ); ?></p>
   847 
   920 
   848 			<div class="wp-privacy-request-form-field">
   921 			<div class="wp-privacy-request-form-field">
   849 				<label for="username_or_email_for_privacy_request"><?php esc_html_e( 'Username or email address' ); ?></label>
   922 				<label for="username_or_email_for_privacy_request"><?php esc_html_e( 'Username or email address' ); ?></label>
   970  * @since 4.9.8
  1043  * @since 4.9.8
   971  * @access private
  1044  * @access private
   972  */
  1045  */
   973 function _wp_privacy_requests_screen_options() {
  1046 function _wp_privacy_requests_screen_options() {
   974 	$args = array(
  1047 	$args = array(
   975 		'option'  => str_replace( 'tools_page_', '', get_current_screen()->id ) . '_requests_per_page',
  1048 		'option' => str_replace( 'tools_page_', '', get_current_screen()->id ) . '_requests_per_page',
   976 	);
  1049 	);
   977 	add_screen_option( 'per_page', $args );
  1050 	add_screen_option( 'per_page', $args );
   978 }
  1051 }
   979 
  1052 
   980 // TODO: move the following classes in new files.
  1053 // TODO: move the following classes in new files.
  1034 	 * @since 4.9.6
  1107 	 * @since 4.9.6
  1035 	 *
  1108 	 *
  1036 	 * @return array Default sortable columns.
  1109 	 * @return array Default sortable columns.
  1037 	 */
  1110 	 */
  1038 	protected function get_sortable_columns() {
  1111 	protected function get_sortable_columns() {
  1039 		return array();
  1112 		// The initial sorting is by 'Requested' (post_date) and descending.
       
  1113 		// With initial sorting, the first click on 'Requested' should be ascending.
       
  1114 		// With 'Requester' sorting active, the next click on 'Requested' should be descending.
       
  1115 		$desc_first = isset( $_GET['orderby'] );
       
  1116 
       
  1117 		return array(
       
  1118 			'email'             => 'requester',
       
  1119 			'created_timestamp' => array( 'requested', $desc_first ),
       
  1120 		);
  1040 	}
  1121 	}
  1041 
  1122 
  1042 	/**
  1123 	/**
  1043 	 * Default primary column.
  1124 	 * Default primary column.
  1044 	 *
  1125 	 *
  1098 		$current_status = isset( $_REQUEST['filter-status'] ) ? sanitize_text_field( $_REQUEST['filter-status'] ) : '';
  1179 		$current_status = isset( $_REQUEST['filter-status'] ) ? sanitize_text_field( $_REQUEST['filter-status'] ) : '';
  1099 		$statuses       = _wp_privacy_statuses();
  1180 		$statuses       = _wp_privacy_statuses();
  1100 		$views          = array();
  1181 		$views          = array();
  1101 		$admin_url      = admin_url( 'tools.php?page=' . $this->request_type );
  1182 		$admin_url      = admin_url( 'tools.php?page=' . $this->request_type );
  1102 		$counts         = $this->get_request_counts();
  1183 		$counts         = $this->get_request_counts();
       
  1184 		$total_requests = absint( array_sum( (array) $counts ) );
  1103 
  1185 
  1104 		$current_link_attributes = empty( $current_status ) ? ' class="current" aria-current="page"' : '';
  1186 		$current_link_attributes = empty( $current_status ) ? ' class="current" aria-current="page"' : '';
  1105 		$views['all']            = '<a href="' . esc_url( $admin_url ) . "\" $current_link_attributes>" . esc_html__( 'All' ) . ' (' . absint( array_sum( (array) $counts ) ) . ')</a>';
  1187 		$status_label            = sprintf(
       
  1188 			/* translators: %s: all requests count */
       
  1189 			_nx(
       
  1190 				'All <span class="count">(%s)</span>',
       
  1191 				'All <span class="count">(%s)</span>',
       
  1192 				$total_requests,
       
  1193 				'requests'
       
  1194 			),
       
  1195 			number_format_i18n( $total_requests )
       
  1196 		);
       
  1197 
       
  1198 		$views['all'] = sprintf(
       
  1199 			'<a href="%s"%s>%s</a>',
       
  1200 			esc_url( $admin_url ),
       
  1201 			$current_link_attributes,
       
  1202 			$status_label
       
  1203 		);
  1106 
  1204 
  1107 		foreach ( $statuses as $status => $label ) {
  1205 		foreach ( $statuses as $status => $label ) {
       
  1206 			$post_status = get_post_status_object( $status );
       
  1207 			if ( ! $post_status ) {
       
  1208 				continue;
       
  1209 			}
       
  1210 
  1108 			$current_link_attributes = $status === $current_status ? ' class="current" aria-current="page"' : '';
  1211 			$current_link_attributes = $status === $current_status ? ' class="current" aria-current="page"' : '';
  1109 			$views[ $status ]        = '<a href="' . esc_url( add_query_arg( 'filter-status', $status, $admin_url ) ) . "\" $current_link_attributes>" . esc_html( $label ) . ' (' . absint( $counts->$status ) . ')</a>';
  1212 			$total_status_requests   = absint( $counts->{$status} );
       
  1213 			$status_label            = sprintf(
       
  1214 				translate_nooped_plural( $post_status->label_count, $total_status_requests ),
       
  1215 				number_format_i18n( $total_status_requests )
       
  1216 			);
       
  1217 			$status_link             = add_query_arg( 'filter-status', $status, $admin_url );
       
  1218 
       
  1219 			$views[ $status ] = sprintf(
       
  1220 				'<a href="%s"%s>%s</a>',
       
  1221 				esc_url( $status_link ),
       
  1222 				$current_link_attributes,
       
  1223 				$status_label
       
  1224 			);
  1110 		}
  1225 		}
  1111 
  1226 
  1112 		return $views;
  1227 		return $views;
  1113 	}
  1228 	}
  1114 
  1229 
  1132 	 * @since 4.9.6
  1247 	 * @since 4.9.6
  1133 	 */
  1248 	 */
  1134 	public function process_bulk_action() {
  1249 	public function process_bulk_action() {
  1135 		$action      = $this->current_action();
  1250 		$action      = $this->current_action();
  1136 		$request_ids = isset( $_REQUEST['request_id'] ) ? wp_parse_id_list( wp_unslash( $_REQUEST['request_id'] ) ) : array();
  1251 		$request_ids = isset( $_REQUEST['request_id'] ) ? wp_parse_id_list( wp_unslash( $_REQUEST['request_id'] ) ) : array();
  1137 		
  1252 
  1138 		$count       = 0;
  1253 		$count = 0;
  1139 
  1254 
  1140 		if ( $request_ids ) {
  1255 		if ( $request_ids ) {
  1141 			check_admin_referer( 'bulk-privacy_requests' );
  1256 			check_admin_referer( 'bulk-privacy_requests' );
  1142 		}
  1257 		}
  1143 
  1258 
  1179 
  1294 
  1180 	/**
  1295 	/**
  1181 	 * Prepare items to output.
  1296 	 * Prepare items to output.
  1182 	 *
  1297 	 *
  1183 	 * @since 4.9.6
  1298 	 * @since 4.9.6
       
  1299 	 * @since 5.1.0 Added support for column sorting.
  1184 	 */
  1300 	 */
  1185 	public function prepare_items() {
  1301 	public function prepare_items() {
  1186 		global $wpdb;
  1302 		global $wpdb;
  1187 
       
  1188 		$primary               = $this->get_primary_column_name();
       
  1189 		$this->_column_headers = array(
       
  1190 			$this->get_columns(),
       
  1191 			array(),
       
  1192 			$this->get_sortable_columns(),
       
  1193 			$primary,
       
  1194 		);
       
  1195 
  1303 
  1196 		$this->items    = array();
  1304 		$this->items    = array();
  1197 		$posts_per_page = $this->get_items_per_page( $this->request_type . '_requests_per_page' );
  1305 		$posts_per_page = $this->get_items_per_page( $this->request_type . '_requests_per_page' );
  1198 		$args           = array(
  1306 		$args           = array(
  1199 			'post_type'      => $this->post_type,
  1307 			'post_type'      => $this->post_type,
  1202 			'offset'         => isset( $_REQUEST['paged'] ) ? max( 0, absint( $_REQUEST['paged'] ) - 1 ) * $posts_per_page : 0,
  1310 			'offset'         => isset( $_REQUEST['paged'] ) ? max( 0, absint( $_REQUEST['paged'] ) - 1 ) * $posts_per_page : 0,
  1203 			'post_status'    => 'any',
  1311 			'post_status'    => 'any',
  1204 			's'              => isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : '',
  1312 			's'              => isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : '',
  1205 		);
  1313 		);
  1206 
  1314 
       
  1315 		$orderby_mapping = array(
       
  1316 			'requester' => 'post_title',
       
  1317 			'requested' => 'post_date',
       
  1318 		);
       
  1319 
       
  1320 		if ( isset( $_REQUEST['orderby'] ) && isset( $orderby_mapping[ $_REQUEST['orderby'] ] ) ) {
       
  1321 			$args['orderby'] = $orderby_mapping[ $_REQUEST['orderby'] ];
       
  1322 		}
       
  1323 
       
  1324 		if ( isset( $_REQUEST['order'] ) && in_array( strtoupper( $_REQUEST['order'] ), array( 'ASC', 'DESC' ), true ) ) {
       
  1325 			$args['order'] = strtoupper( $_REQUEST['order'] );
       
  1326 		}
       
  1327 
  1207 		if ( ! empty( $_REQUEST['filter-status'] ) ) {
  1328 		if ( ! empty( $_REQUEST['filter-status'] ) ) {
  1208 			$filter_status       = isset( $_REQUEST['filter-status'] ) ? sanitize_text_field( $_REQUEST['filter-status'] ) : '';
  1329 			$filter_status       = isset( $_REQUEST['filter-status'] ) ? sanitize_text_field( $_REQUEST['filter-status'] ) : '';
  1209 			$args['post_status'] = $filter_status;
  1330 			$args['post_status'] = $filter_status;
  1210 		}
  1331 		}
  1211 
  1332 
  1286 	protected function get_timestamp_as_date( $timestamp ) {
  1407 	protected function get_timestamp_as_date( $timestamp ) {
  1287 		if ( empty( $timestamp ) ) {
  1408 		if ( empty( $timestamp ) ) {
  1288 			return '';
  1409 			return '';
  1289 		}
  1410 		}
  1290 
  1411 
  1291 		$time_diff = current_time( 'timestamp', true ) - $timestamp;
  1412 		$time_diff = time() - $timestamp;
  1292 
  1413 
  1293 		if ( $time_diff >= 0 && $time_diff < DAY_IN_SECONDS ) {
  1414 		if ( $time_diff >= 0 && $time_diff < DAY_IN_SECONDS ) {
  1294 			/* translators: human readable timestamp */
  1415 			/* translators: human readable timestamp */
  1295 			return sprintf( __( '%s ago' ), human_time_diff( $timestamp ) );
  1416 			return sprintf( __( '%s ago' ), human_time_diff( $timestamp ) );
  1296 		}
  1417 		}
  1407 			'">';
  1528 			'">';
  1408 
  1529 
  1409 		$download_data_markup .= '<span class="export-personal-data-idle"><button type="button" class="button-link export-personal-data-handle">' . __( 'Download Personal Data' ) . '</button></span>' .
  1530 		$download_data_markup .= '<span class="export-personal-data-idle"><button type="button" class="button-link export-personal-data-handle">' . __( 'Download Personal Data' ) . '</button></span>' .
  1410 			'<span style="display:none" class="export-personal-data-processing" >' . __( 'Downloading Data...' ) . '</span>' .
  1531 			'<span style="display:none" class="export-personal-data-processing" >' . __( 'Downloading Data...' ) . '</span>' .
  1411 			'<span style="display:none" class="export-personal-data-success"><button type="button" class="button-link export-personal-data-handle">' . __( 'Download Personal Data Again' ) . '</button></span>' .
  1532 			'<span style="display:none" class="export-personal-data-success"><button type="button" class="button-link export-personal-data-handle">' . __( 'Download Personal Data Again' ) . '</button></span>' .
  1412 			'<span style="display:none" class="export-personal-data-failed">' . __( 'Download has failed.' ) . ' <button type="button" class="button-link">' . __( 'Retry' ) . '</button></span>';
  1533 			'<span style="display:none" class="export-personal-data-failed">' . __( 'Download failed.' ) . ' <button type="button" class="button-link">' . __( 'Retry' ) . '</button></span>';
  1413 
  1534 
  1414 		$download_data_markup .= '</div>';
  1535 		$download_data_markup .= '</div>';
  1415 
  1536 
  1416 		$row_actions = array(
  1537 		$row_actions = array(
  1417 			'download-data' => $download_data_markup,
  1538 			'download-data' => $download_data_markup,
  1447 					'data-request-id="' . esc_attr( $request_id ) . '" ' .
  1568 					'data-request-id="' . esc_attr( $request_id ) . '" ' .
  1448 					'data-nonce="' . esc_attr( $nonce ) .
  1569 					'data-nonce="' . esc_attr( $nonce ) .
  1449 					'">';
  1570 					'">';
  1450 
  1571 
  1451 				?>
  1572 				?>
  1452 				<span class="export-personal-data-idle"><button type="button" class="button export-personal-data-handle"><?php _e( 'Email Data' ); ?></button></span>
  1573 				<span class="export-personal-data-idle"><button type="button" class="button export-personal-data-handle"><?php _e( 'Send Export Link' ); ?></button></span>
  1453 				<span style="display:none" class="export-personal-data-processing button updating-message" ><?php _e( 'Sending Email...' ); ?></span>
  1574 				<span style="display:none" class="export-personal-data-processing button updating-message" ><?php _e( 'Sending Email...' ); ?></span>
  1454 				<span style="display:none" class="export-personal-data-success success-message" ><?php _e( 'Email sent.' ); ?></span>
  1575 				<span style="display:none" class="export-personal-data-success success-message" ><?php _e( 'Email sent.' ); ?></span>
  1455 				<span style="display:none" class="export-personal-data-failed"><?php _e( 'Email could not be sent.' ); ?> <button type="button" class="button export-personal-data-handle"><?php _e( 'Retry' ); ?></button></span>
  1576 				<span style="display:none" class="export-personal-data-failed"><?php _e( 'Email could not be sent.' ); ?> <button type="button" class="button export-personal-data-handle"><?php _e( 'Retry' ); ?></button></span>
  1456 				<?php
  1577 				<?php
  1457 
  1578 
  1459 				break;
  1580 				break;
  1460 			case 'request-failed':
  1581 			case 'request-failed':
  1461 				submit_button( __( 'Retry' ), 'secondary', 'privacy_action_email_retry[' . $item->ID . ']', false );
  1582 				submit_button( __( 'Retry' ), 'secondary', 'privacy_action_email_retry[' . $item->ID . ']', false );
  1462 				break;
  1583 				break;
  1463 			case 'request-completed':
  1584 			case 'request-completed':
  1464 				echo '<a href="' . esc_url( wp_nonce_url( add_query_arg( array(
  1585 				echo '<a href="' . esc_url(
  1465 					'action'     => 'delete',
  1586 					wp_nonce_url(
  1466 					'request_id' => array( $item->ID ),
  1587 						add_query_arg(
  1467 				), admin_url( 'tools.php?page=export_personal_data' ) ), 'bulk-privacy_requests' ) ) . '" class="button">' . esc_html__( 'Remove request' ) . '</a>';
  1588 							array(
       
  1589 								'action'     => 'delete',
       
  1590 								'request_id' => array( $item->ID ),
       
  1591 							),
       
  1592 							admin_url( 'tools.php?page=export_personal_data' )
       
  1593 						),
       
  1594 						'bulk-privacy_requests'
       
  1595 					)
       
  1596 				) . '" class="button">' . esc_html__( 'Remove request' ) . '</a>';
  1468 				break;
  1597 				break;
  1469 		}
  1598 		}
  1470 	}
  1599 	}
  1471 }
  1600 }
  1472 
  1601 
  1573 				break;
  1702 				break;
  1574 			case 'request-failed':
  1703 			case 'request-failed':
  1575 				submit_button( __( 'Retry' ), 'secondary', 'privacy_action_email_retry[' . $item->ID . ']', false );
  1704 				submit_button( __( 'Retry' ), 'secondary', 'privacy_action_email_retry[' . $item->ID . ']', false );
  1576 				break;
  1705 				break;
  1577 			case 'request-completed':
  1706 			case 'request-completed':
  1578 				echo '<a href="' . esc_url( wp_nonce_url( add_query_arg( array(
  1707 				echo '<a href="' . esc_url(
  1579 					'action'     => 'delete',
  1708 					wp_nonce_url(
  1580 					'request_id' => array( $item->ID ),
  1709 						add_query_arg(
  1581 				), admin_url( 'tools.php?page=remove_personal_data' ) ), 'bulk-privacy_requests' ) ) . '" class="button">' . esc_html__( 'Remove request' ) . '</a>';
  1710 							array(
       
  1711 								'action'     => 'delete',
       
  1712 								'request_id' => array( $item->ID ),
       
  1713 							),
       
  1714 							admin_url( 'tools.php?page=remove_personal_data' )
       
  1715 						),
       
  1716 						'bulk-privacy_requests'
       
  1717 					)
       
  1718 				) . '" class="button">' . esc_html__( 'Remove request' ) . '</a>';
  1582 				break;
  1719 				break;
  1583 		}
  1720 		}
  1584 	}
  1721 	}
  1585 
  1722 
  1586 }
  1723 }