1 | <?php |
---|
2 | /** |
---|
3 | * WordPress user administration API. |
---|
4 | * |
---|
5 | * @package WordPress |
---|
6 | * @subpackage Administration |
---|
7 | */ |
---|
8 | |
---|
9 | /** |
---|
10 | * Creates a new user from the "Users" form using $_POST information. |
---|
11 | * |
---|
12 | * @since 2.0.0 |
---|
13 | * |
---|
14 | * @return int|WP_Error WP_Error or User ID. |
---|
15 | */ |
---|
16 | function add_user() { |
---|
17 | return edit_user(); |
---|
18 | } |
---|
19 | |
---|
20 | /** |
---|
21 | * Edit user settings based on contents of $_POST |
---|
22 | * |
---|
23 | * Used on user-edit.php and profile.php to manage and process user options, passwords etc. |
---|
24 | * |
---|
25 | * @since 2.0.0 |
---|
26 | * |
---|
27 | * @param int $user_id Optional. User ID. |
---|
28 | * @return int|WP_Error user id of the updated user |
---|
29 | */ |
---|
30 | function edit_user( $user_id = 0 ) { |
---|
31 | $wp_roles = wp_roles(); |
---|
32 | $user = new stdClass; |
---|
33 | if ( $user_id ) { |
---|
34 | $update = true; |
---|
35 | $user->ID = (int) $user_id; |
---|
36 | $userdata = get_userdata( $user_id ); |
---|
37 | $user->user_login = wp_slash( $userdata->user_login ); |
---|
38 | } else { |
---|
39 | $update = false; |
---|
40 | } |
---|
41 | |
---|
42 | if ( !$update && isset( $_POST['user_login'] ) ) |
---|
43 | $user->user_login = sanitize_user($_POST['user_login'], true); |
---|
44 | |
---|
45 | $pass1 = $pass2 = ''; |
---|
46 | if ( isset( $_POST['pass1'] ) ) |
---|
47 | $pass1 = $_POST['pass1']; |
---|
48 | if ( isset( $_POST['pass2'] ) ) |
---|
49 | $pass2 = $_POST['pass2']; |
---|
50 | |
---|
51 | if ( isset( $_POST['role'] ) && current_user_can( 'edit_users' ) ) { |
---|
52 | $new_role = sanitize_text_field( $_POST['role'] ); |
---|
53 | $potential_role = isset($wp_roles->role_objects[$new_role]) ? $wp_roles->role_objects[$new_role] : false; |
---|
54 | // Don't let anyone with 'edit_users' (admins) edit their own role to something without it. |
---|
55 | // Multisite super admins can freely edit their blog roles -- they possess all caps. |
---|
56 | if ( ( is_multisite() && current_user_can( 'manage_sites' ) ) || $user_id != get_current_user_id() || ($potential_role && $potential_role->has_cap( 'edit_users' ) ) ) |
---|
57 | $user->role = $new_role; |
---|
58 | |
---|
59 | // If the new role isn't editable by the logged-in user die with error |
---|
60 | $editable_roles = get_editable_roles(); |
---|
61 | if ( ! empty( $new_role ) && empty( $editable_roles[$new_role] ) ) |
---|
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'] ) ); |
---|
67 | if ( isset( $_POST['url'] ) ) { |
---|
68 | if ( empty ( $_POST['url'] ) || $_POST['url'] == 'http://' ) { |
---|
69 | $user->user_url = ''; |
---|
70 | } else { |
---|
71 | $user->user_url = esc_url_raw( $_POST['url'] ); |
---|
72 | $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; |
---|
74 | } |
---|
75 | } |
---|
76 | if ( isset( $_POST['first_name'] ) ) |
---|
77 | $user->first_name = sanitize_text_field( $_POST['first_name'] ); |
---|
78 | if ( isset( $_POST['last_name'] ) ) |
---|
79 | $user->last_name = sanitize_text_field( $_POST['last_name'] ); |
---|
80 | if ( isset( $_POST['nickname'] ) ) |
---|
81 | $user->nickname = sanitize_text_field( $_POST['nickname'] ); |
---|
82 | if ( isset( $_POST['display_name'] ) ) |
---|
83 | $user->display_name = sanitize_text_field( $_POST['display_name'] ); |
---|
84 | |
---|
85 | if ( isset( $_POST['description'] ) ) |
---|
86 | $user->description = trim( $_POST['description'] ); |
---|
87 | |
---|
88 | foreach ( wp_get_user_contact_methods( $user ) as $method => $name ) { |
---|
89 | if ( isset( $_POST[$method] )) |
---|
90 | $user->$method = sanitize_text_field( $_POST[$method] ); |
---|
91 | } |
---|
92 | |
---|
93 | if ( $update ) { |
---|
94 | $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'; |
---|
96 | $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'; |
---|
98 | $user->locale = ''; |
---|
99 | |
---|
100 | if ( isset( $_POST['locale'] ) ) { |
---|
101 | $locale = sanitize_text_field( $_POST['locale'] ); |
---|
102 | if ( 'site-default' === $locale ) { |
---|
103 | $locale = ''; |
---|
104 | } elseif ( '' === $locale ) { |
---|
105 | $locale = 'en_US'; |
---|
106 | } elseif ( ! in_array( $locale, get_available_languages(), true ) ) { |
---|
107 | $locale = ''; |
---|
108 | } |
---|
109 | |
---|
110 | $user->locale = $locale; |
---|
111 | } |
---|
112 | } |
---|
113 | |
---|
114 | $user->comment_shortcuts = isset( $_POST['comment_shortcuts'] ) && 'true' == $_POST['comment_shortcuts'] ? 'true' : ''; |
---|
115 | |
---|
116 | $user->use_ssl = 0; |
---|
117 | if ( !empty($_POST['use_ssl']) ) |
---|
118 | $user->use_ssl = 1; |
---|
119 | |
---|
120 | $errors = new WP_Error(); |
---|
121 | |
---|
122 | /* checking that username has been typed */ |
---|
123 | if ( $user->user_login == '' ) |
---|
124 | $errors->add( 'user_login', __( '<strong>ERROR</strong>: Please enter a username.' ) ); |
---|
125 | |
---|
126 | /* checking that nickname has been typed */ |
---|
127 | if ( $update && empty( $user->nickname ) ) { |
---|
128 | $errors->add( 'nickname', __( '<strong>ERROR</strong>: Please enter a nickname.' ) ); |
---|
129 | } |
---|
130 | |
---|
131 | /** |
---|
132 | * Fires before the password and confirm password fields are checked for congruity. |
---|
133 | * |
---|
134 | * @since 1.5.1 |
---|
135 | * |
---|
136 | * @param string $user_login The username. |
---|
137 | * @param string $pass1 The password (passed by reference). |
---|
138 | * @param string $pass2 The confirmed password (passed by reference). |
---|
139 | */ |
---|
140 | do_action_ref_array( 'check_passwords', array( $user->user_login, &$pass1, &$pass2 ) ); |
---|
141 | |
---|
142 | // Check for blank password when adding a user. |
---|
143 | if ( ! $update && empty( $pass1 ) ) { |
---|
144 | $errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter a password.' ), array( 'form-field' => 'pass1' ) ); |
---|
145 | } |
---|
146 | |
---|
147 | // Check for "\" in password. |
---|
148 | if ( false !== strpos( wp_unslash( $pass1 ), "\\" ) ) { |
---|
149 | $errors->add( 'pass', __( '<strong>ERROR</strong>: Passwords may not contain the character "\\".' ), array( 'form-field' => 'pass1' ) ); |
---|
150 | } |
---|
151 | |
---|
152 | // Checking the password has been typed twice the same. |
---|
153 | 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' ) ); |
---|
155 | } |
---|
156 | |
---|
157 | if ( !empty( $pass1 ) ) |
---|
158 | $user->user_pass = $pass1; |
---|
159 | |
---|
160 | if ( !$update && isset( $_POST['user_login'] ) && !validate_username( $_POST['user_login'] ) ) |
---|
161 | $errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' )); |
---|
162 | |
---|
163 | if ( !$update && username_exists( $user->user_login ) ) |
---|
164 | $errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' )); |
---|
165 | |
---|
166 | /** This filter is documented in wp-includes/user.php */ |
---|
167 | $illegal_logins = (array) apply_filters( 'illegal_user_logins', array() ); |
---|
168 | |
---|
169 | if ( in_array( strtolower( $user->user_login ), array_map( 'strtolower', $illegal_logins ) ) ) { |
---|
170 | $errors->add( 'invalid_username', __( '<strong>ERROR</strong>: Sorry, that username is not allowed.' ) ); |
---|
171 | } |
---|
172 | |
---|
173 | /* checking email address */ |
---|
174 | if ( empty( $user->user_email ) ) { |
---|
175 | $errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please enter an email address.' ), array( 'form-field' => 'email' ) ); |
---|
176 | } elseif ( !is_email( $user->user_email ) ) { |
---|
177 | $errors->add( 'invalid_email', __( '<strong>ERROR</strong>: The email address isn’t correct.' ), array( 'form-field' => 'email' ) ); |
---|
178 | } 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' ) ); |
---|
180 | } |
---|
181 | |
---|
182 | /** |
---|
183 | * Fires before user profile update errors are returned. |
---|
184 | * |
---|
185 | * @since 2.8.0 |
---|
186 | * |
---|
187 | * @param WP_Error $errors WP_Error object (passed by reference). |
---|
188 | * @param bool $update Whether this is a user update. |
---|
189 | * @param stdClass $user User object (passed by reference). |
---|
190 | */ |
---|
191 | do_action_ref_array( 'user_profile_update_errors', array( &$errors, $update, &$user ) ); |
---|
192 | |
---|
193 | if ( $errors->get_error_codes() ) |
---|
194 | return $errors; |
---|
195 | |
---|
196 | if ( $update ) { |
---|
197 | $user_id = wp_update_user( $user ); |
---|
198 | } else { |
---|
199 | $user_id = wp_insert_user( $user ); |
---|
200 | $notify = isset( $_POST['send_user_notification'] ) ? 'both' : 'admin'; |
---|
201 | |
---|
202 | /** |
---|
203 | * Fires after a new user has been created. |
---|
204 | * |
---|
205 | * @since 4.4.0 |
---|
206 | * |
---|
207 | * @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() |
---|
209 | * for more information on possible values. |
---|
210 | */ |
---|
211 | do_action( 'edit_user_created_user', $user_id, $notify ); |
---|
212 | } |
---|
213 | return $user_id; |
---|
214 | } |
---|
215 | |
---|
216 | /** |
---|
217 | * Fetch a filtered list of user roles that the current user is |
---|
218 | * allowed to edit. |
---|
219 | * |
---|
220 | * Simple function who's main purpose is to allow filtering of the |
---|
221 | * list of roles in the $wp_roles object so that plugins can remove |
---|
222 | * inappropriate ones depending on the situation or user making edits. |
---|
223 | * Specifically because without filtering anyone with the edit_users |
---|
224 | * capability can edit others to be administrators, even if they are |
---|
225 | * only editors or authors. This filter allows admins to delegate |
---|
226 | * user management. |
---|
227 | * |
---|
228 | * @since 2.8.0 |
---|
229 | * |
---|
230 | * @return array |
---|
231 | */ |
---|
232 | function get_editable_roles() { |
---|
233 | $all_roles = wp_roles()->roles; |
---|
234 | |
---|
235 | /** |
---|
236 | * Filters the list of editable roles. |
---|
237 | * |
---|
238 | * @since 2.8.0 |
---|
239 | * |
---|
240 | * @param array $all_roles List of roles. |
---|
241 | */ |
---|
242 | $editable_roles = apply_filters( 'editable_roles', $all_roles ); |
---|
243 | |
---|
244 | return $editable_roles; |
---|
245 | } |
---|
246 | |
---|
247 | /** |
---|
248 | * Retrieve user data and filter it. |
---|
249 | * |
---|
250 | * @since 2.0.5 |
---|
251 | * |
---|
252 | * @param int $user_id User ID. |
---|
253 | * @return WP_User|bool WP_User object on success, false on failure. |
---|
254 | */ |
---|
255 | function get_user_to_edit( $user_id ) { |
---|
256 | $user = get_userdata( $user_id ); |
---|
257 | |
---|
258 | if ( $user ) |
---|
259 | $user->filter = 'edit'; |
---|
260 | |
---|
261 | return $user; |
---|
262 | } |
---|
263 | |
---|
264 | /** |
---|
265 | * Retrieve the user's drafts. |
---|
266 | * |
---|
267 | * @since 2.0.0 |
---|
268 | * |
---|
269 | * @global wpdb $wpdb WordPress database abstraction object. |
---|
270 | * |
---|
271 | * @param int $user_id User ID. |
---|
272 | * @return array |
---|
273 | */ |
---|
274 | function get_users_drafts( $user_id ) { |
---|
275 | 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); |
---|
277 | |
---|
278 | /** |
---|
279 | * Filters the user's drafts query string. |
---|
280 | * |
---|
281 | * @since 2.0.0 |
---|
282 | * |
---|
283 | * @param string $query The user's drafts query string. |
---|
284 | */ |
---|
285 | $query = apply_filters( 'get_users_drafts', $query ); |
---|
286 | return $wpdb->get_results( $query ); |
---|
287 | } |
---|
288 | |
---|
289 | /** |
---|
290 | * Remove user and optionally reassign posts and links to another user. |
---|
291 | * |
---|
292 | * If the $reassign parameter is not assigned to a User ID, then all posts will |
---|
293 | * be deleted of that user. The action {@see 'delete_user'} that is passed the User ID |
---|
294 | * being deleted will be run after the posts are either reassigned or deleted. |
---|
295 | * The user meta will also be deleted that are for that User ID. |
---|
296 | * |
---|
297 | * @since 2.0.0 |
---|
298 | * |
---|
299 | * @global wpdb $wpdb WordPress database abstraction object. |
---|
300 | * |
---|
301 | * @param int $id User ID. |
---|
302 | * @param int $reassign Optional. Reassign posts and links to new User ID. |
---|
303 | * @return bool True when finished. |
---|
304 | */ |
---|
305 | function wp_delete_user( $id, $reassign = null ) { |
---|
306 | global $wpdb; |
---|
307 | |
---|
308 | if ( ! is_numeric( $id ) ) { |
---|
309 | return false; |
---|
310 | } |
---|
311 | |
---|
312 | $id = (int) $id; |
---|
313 | $user = new WP_User( $id ); |
---|
314 | |
---|
315 | if ( !$user->exists() ) |
---|
316 | return false; |
---|
317 | |
---|
318 | // Normalize $reassign to null or a user ID. 'novalue' was an older default. |
---|
319 | if ( 'novalue' === $reassign ) { |
---|
320 | $reassign = null; |
---|
321 | } elseif ( null !== $reassign ) { |
---|
322 | $reassign = (int) $reassign; |
---|
323 | } |
---|
324 | |
---|
325 | /** |
---|
326 | * Fires immediately before a user is deleted from the database. |
---|
327 | * |
---|
328 | * @since 2.0.0 |
---|
329 | * |
---|
330 | * @param int $id ID of the user to delete. |
---|
331 | * @param int|null $reassign ID of the user to reassign posts and links to. |
---|
332 | * Default null, for no reassignment. |
---|
333 | */ |
---|
334 | do_action( 'delete_user', $id, $reassign ); |
---|
335 | |
---|
336 | if ( null === $reassign ) { |
---|
337 | $post_types_to_delete = array(); |
---|
338 | foreach ( get_post_types( array(), 'objects' ) as $post_type ) { |
---|
339 | if ( $post_type->delete_with_user ) { |
---|
340 | $post_types_to_delete[] = $post_type->name; |
---|
341 | } elseif ( null === $post_type->delete_with_user && post_type_supports( $post_type->name, 'author' ) ) { |
---|
342 | $post_types_to_delete[] = $post_type->name; |
---|
343 | } |
---|
344 | } |
---|
345 | |
---|
346 | /** |
---|
347 | * Filters the list of post types to delete with a user. |
---|
348 | * |
---|
349 | * @since 3.4.0 |
---|
350 | * |
---|
351 | * @param array $post_types_to_delete Post types to delete. |
---|
352 | * @param int $id User ID. |
---|
353 | */ |
---|
354 | $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 ); |
---|
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 ) ); |
---|
357 | if ( $post_ids ) { |
---|
358 | foreach ( $post_ids as $post_id ) |
---|
359 | wp_delete_post( $post_id ); |
---|
360 | } |
---|
361 | |
---|
362 | // Clean links |
---|
363 | $link_ids = $wpdb->get_col( $wpdb->prepare("SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id) ); |
---|
364 | |
---|
365 | if ( $link_ids ) { |
---|
366 | foreach ( $link_ids as $link_id ) |
---|
367 | wp_delete_link($link_id); |
---|
368 | } |
---|
369 | } else { |
---|
370 | $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) ); |
---|
372 | if ( ! empty( $post_ids ) ) { |
---|
373 | foreach ( $post_ids as $post_id ) |
---|
374 | clean_post_cache( $post_id ); |
---|
375 | } |
---|
376 | $link_ids = $wpdb->get_col( $wpdb->prepare("SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id) ); |
---|
377 | $wpdb->update( $wpdb->links, array('link_owner' => $reassign), array('link_owner' => $id) ); |
---|
378 | if ( ! empty( $link_ids ) ) { |
---|
379 | foreach ( $link_ids as $link_id ) |
---|
380 | clean_bookmark_cache( $link_id ); |
---|
381 | } |
---|
382 | } |
---|
383 | |
---|
384 | // FINALLY, delete user |
---|
385 | if ( is_multisite() ) { |
---|
386 | remove_user_from_blog( $id, get_current_blog_id() ); |
---|
387 | } else { |
---|
388 | $meta = $wpdb->get_col( $wpdb->prepare( "SELECT umeta_id FROM $wpdb->usermeta WHERE user_id = %d", $id ) ); |
---|
389 | foreach ( $meta as $mid ) |
---|
390 | delete_metadata_by_mid( 'user', $mid ); |
---|
391 | |
---|
392 | $wpdb->delete( $wpdb->users, array( 'ID' => $id ) ); |
---|
393 | } |
---|
394 | |
---|
395 | clean_user_cache( $user ); |
---|
396 | |
---|
397 | /** |
---|
398 | * Fires immediately after a user is deleted from the database. |
---|
399 | * |
---|
400 | * @since 2.9.0 |
---|
401 | * |
---|
402 | * @param int $id ID of the deleted user. |
---|
403 | * @param int|null $reassign ID of the user to reassign posts and links to. |
---|
404 | * Default null, for no reassignment. |
---|
405 | */ |
---|
406 | do_action( 'deleted_user', $id, $reassign ); |
---|
407 | |
---|
408 | return true; |
---|
409 | } |
---|
410 | |
---|
411 | /** |
---|
412 | * Remove all capabilities from user. |
---|
413 | * |
---|
414 | * @since 2.1.0 |
---|
415 | * |
---|
416 | * @param int $id User ID. |
---|
417 | */ |
---|
418 | function wp_revoke_user($id) { |
---|
419 | $id = (int) $id; |
---|
420 | |
---|
421 | $user = new WP_User($id); |
---|
422 | $user->remove_all_caps(); |
---|
423 | } |
---|
424 | |
---|
425 | /** |
---|
426 | * @since 2.8.0 |
---|
427 | * |
---|
428 | * @global int $user_ID |
---|
429 | * |
---|
430 | * @param false $errors Deprecated. |
---|
431 | */ |
---|
432 | function default_password_nag_handler($errors = false) { |
---|
433 | global $user_ID; |
---|
434 | // Short-circuit it. |
---|
435 | if ( ! get_user_option('default_password_nag') ) |
---|
436 | return; |
---|
437 | |
---|
438 | // 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'] ) { |
---|
440 | delete_user_setting('default_password_nag'); |
---|
441 | update_user_option($user_ID, 'default_password_nag', false, true); |
---|
442 | } |
---|
443 | } |
---|
444 | |
---|
445 | /** |
---|
446 | * @since 2.8.0 |
---|
447 | * |
---|
448 | * @param int $user_ID |
---|
449 | * @param object $old_data |
---|
450 | */ |
---|
451 | function default_password_nag_edit_user($user_ID, $old_data) { |
---|
452 | // Short-circuit it. |
---|
453 | if ( ! get_user_option('default_password_nag', $user_ID) ) |
---|
454 | return; |
---|
455 | |
---|
456 | $new_data = get_userdata($user_ID); |
---|
457 | |
---|
458 | // Remove the nag if the password has been changed. |
---|
459 | if ( $new_data->user_pass != $old_data->user_pass ) { |
---|
460 | delete_user_setting('default_password_nag'); |
---|
461 | update_user_option($user_ID, 'default_password_nag', false, true); |
---|
462 | } |
---|
463 | } |
---|
464 | |
---|
465 | /** |
---|
466 | * @since 2.8.0 |
---|
467 | * |
---|
468 | * @global string $pagenow |
---|
469 | */ |
---|
470 | function default_password_nag() { |
---|
471 | global $pagenow; |
---|
472 | // Short-circuit it. |
---|
473 | if ( 'profile.php' == $pagenow || ! get_user_option('default_password_nag') ) |
---|
474 | return; |
---|
475 | |
---|
476 | echo '<div class="error default-password-nag">'; |
---|
477 | echo '<p>'; |
---|
478 | echo '<strong>' . __('Notice:') . '</strong> '; |
---|
479 | _e('You’re using the auto-generated password for your account. Would you like to change it?'); |
---|
480 | echo '</p><p>'; |
---|
481 | 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' ); |
---|
483 | echo '</p></div>'; |
---|
484 | } |
---|
485 | |
---|
486 | /** |
---|
487 | * @since 3.5.0 |
---|
488 | * @access private |
---|
489 | */ |
---|
490 | function delete_users_add_js() { ?> |
---|
491 | <script> |
---|
492 | jQuery(document).ready( function($) { |
---|
493 | var submit = $('#submit').prop('disabled', true); |
---|
494 | $('input[name="delete_option"]').one('change', function() { |
---|
495 | submit.prop('disabled', false); |
---|
496 | }); |
---|
497 | $('#reassign_user').focus( function() { |
---|
498 | $('#delete_option1').prop('checked', true).trigger('change'); |
---|
499 | }); |
---|
500 | }); |
---|
501 | </script> |
---|
502 | <?php |
---|
503 | } |
---|
504 | |
---|
505 | /** |
---|
506 | * Optional SSL preference that can be turned on by hooking to the 'personal_options' action. |
---|
507 | * |
---|
508 | * See the {@see 'personal_options'} action. |
---|
509 | * |
---|
510 | * @since 2.7.0 |
---|
511 | * |
---|
512 | * @param object $user User data object |
---|
513 | */ |
---|
514 | function use_ssl_preference($user) { |
---|
515 | ?> |
---|
516 | <tr class="user-use-ssl-wrap"> |
---|
517 | <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> |
---|
519 | </tr> |
---|
520 | <?php |
---|
521 | } |
---|
522 | |
---|
523 | /** |
---|
524 | * |
---|
525 | * @param string $text |
---|
526 | * @return string |
---|
527 | */ |
---|
528 | function admin_created_user_email( $text ) { |
---|
529 | $roles = get_editable_roles(); |
---|
530 | $role = $roles[ $_REQUEST['role'] ]; |
---|
531 | /* translators: 1: Site name, 2: site URL, 3: role */ |
---|
532 | return sprintf( __( 'Hi, |
---|
533 | You\'ve been invited to join \'%1$s\' at |
---|
534 | %2$s with the role of %3$s. |
---|
535 | If you do not want to join this site please ignore |
---|
536 | this email. This invitation will expire in a few days. |
---|
537 | |
---|
538 | 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'] ) ) ); |
---|
540 | } |
---|
541 | |
---|
542 | /** |
---|
543 | * Resend an existing request and return the result. |
---|
544 | * |
---|
545 | * @since 4.9.6 |
---|
546 | * @access private |
---|
547 | * |
---|
548 | * @param int $request_id Request ID. |
---|
549 | * @return bool|WP_Error Returns true/false based on the success of sending the email, or a WP_Error object. |
---|
550 | */ |
---|
551 | function _wp_privacy_resend_request( $request_id ) { |
---|
552 | $request_id = absint( $request_id ); |
---|
553 | $request = get_post( $request_id ); |
---|
554 | |
---|
555 | if ( ! $request || 'user_request' !== $request->post_type ) { |
---|
556 | return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) ); |
---|
557 | } |
---|
558 | |
---|
559 | $result = wp_send_user_request( $request_id ); |
---|
560 | |
---|
561 | if ( is_wp_error( $result ) ) { |
---|
562 | return $result; |
---|
563 | } elseif ( ! $result ) { |
---|
564 | return new WP_Error( 'privacy_request_error', __( 'Unable to initiate confirmation request.' ) ); |
---|
565 | } |
---|
566 | |
---|
567 | return true; |
---|
568 | } |
---|
569 | |
---|
570 | /** |
---|
571 | * Marks a request as completed by the admin and logs the current timestamp. |
---|
572 | * |
---|
573 | * @since 4.9.6 |
---|
574 | * @access private |
---|
575 | * |
---|
576 | * @param int $request_id Request ID. |
---|
577 | * @return int|WP_Error $request Request ID on success or WP_Error. |
---|
578 | */ |
---|
579 | function _wp_privacy_completed_request( $request_id ) { |
---|
580 | $request_id = absint( $request_id ); |
---|
581 | $request_data = wp_get_user_request_data( $request_id ); |
---|
582 | |
---|
583 | if ( ! $request_data ) { |
---|
584 | return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) ); |
---|
585 | } |
---|
586 | |
---|
587 | update_post_meta( $request_id, '_wp_user_request_completed_timestamp', time() ); |
---|
588 | |
---|
589 | $request = wp_update_post( array( |
---|
590 | 'ID' => $request_id, |
---|
591 | 'post_status' => 'request-completed', |
---|
592 | ) ); |
---|
593 | |
---|
594 | return $request; |
---|
595 | } |
---|
596 | |
---|
597 | /** |
---|
598 | * Handle list table actions. |
---|
599 | * |
---|
600 | * @since 4.9.6 |
---|
601 | * @access private |
---|
602 | */ |
---|
603 | function _wp_personal_data_handle_actions() { |
---|
604 | if ( isset( $_POST['privacy_action_email_retry'] ) ) { |
---|
605 | check_admin_referer( 'bulk-privacy_requests' ); |
---|
606 | |
---|
607 | $request_id = absint( current( array_keys( (array) wp_unslash( $_POST['privacy_action_email_retry'] ) ) ) ); |
---|
608 | $result = _wp_privacy_resend_request( $request_id ); |
---|
609 | |
---|
610 | if ( is_wp_error( $result ) ) { |
---|
611 | add_settings_error( |
---|
612 | 'privacy_action_email_retry', |
---|
613 | 'privacy_action_email_retry', |
---|
614 | $result->get_error_message(), |
---|
615 | 'error' |
---|
616 | ); |
---|
617 | } else { |
---|
618 | add_settings_error( |
---|
619 | 'privacy_action_email_retry', |
---|
620 | 'privacy_action_email_retry', |
---|
621 | __( 'Confirmation request sent again successfully.' ), |
---|
622 | 'updated' |
---|
623 | ); |
---|
624 | } |
---|
625 | } elseif ( isset( $_POST['action'] ) ) { |
---|
626 | $action = isset( $_POST['action'] ) ? sanitize_key( wp_unslash( $_POST['action'] ) ) : ''; |
---|
627 | |
---|
628 | switch ( $action ) { |
---|
629 | case 'add_export_personal_data_request': |
---|
630 | case 'add_remove_personal_data_request': |
---|
631 | check_admin_referer( 'personal-data-request' ); |
---|
632 | |
---|
633 | if ( ! isset( $_POST['type_of_action'], $_POST['username_or_email_for_privacy_request'] ) ) { |
---|
634 | add_settings_error( |
---|
635 | 'action_type', |
---|
636 | 'action_type', |
---|
637 | __( 'Invalid action.' ), |
---|
638 | 'error' |
---|
639 | ); |
---|
640 | } |
---|
641 | $action_type = sanitize_text_field( wp_unslash( $_POST['type_of_action'] ) ); |
---|
642 | $username_or_email_address = sanitize_text_field( wp_unslash( $_POST['username_or_email_for_privacy_request'] ) ); |
---|
643 | $email_address = ''; |
---|
644 | |
---|
645 | if ( ! in_array( $action_type, _wp_privacy_action_request_types(), true ) ) { |
---|
646 | add_settings_error( |
---|
647 | 'action_type', |
---|
648 | 'action_type', |
---|
649 | __( 'Invalid action.' ), |
---|
650 | 'error' |
---|
651 | ); |
---|
652 | } |
---|
653 | |
---|
654 | if ( ! is_email( $username_or_email_address ) ) { |
---|
655 | $user = get_user_by( 'login', $username_or_email_address ); |
---|
656 | if ( ! $user instanceof WP_User ) { |
---|
657 | add_settings_error( |
---|
658 | 'username_or_email_for_privacy_request', |
---|
659 | 'username_or_email_for_privacy_request', |
---|
660 | __( 'Unable to add this request. A valid email address or username must be supplied.' ), |
---|
661 | 'error' |
---|
662 | ); |
---|
663 | } else { |
---|
664 | $email_address = $user->user_email; |
---|
665 | } |
---|
666 | } else { |
---|
667 | $email_address = $username_or_email_address; |
---|
668 | } |
---|
669 | |
---|
670 | if ( empty( $email_address ) ) { |
---|
671 | break; |
---|
672 | } |
---|
673 | |
---|
674 | $request_id = wp_create_user_request( $email_address, $action_type ); |
---|
675 | |
---|
676 | if ( is_wp_error( $request_id ) ) { |
---|
677 | add_settings_error( |
---|
678 | 'username_or_email_for_privacy_request', |
---|
679 | 'username_or_email_for_privacy_request', |
---|
680 | $request_id->get_error_message(), |
---|
681 | 'error' |
---|
682 | ); |
---|
683 | break; |
---|
684 | } elseif ( ! $request_id ) { |
---|
685 | add_settings_error( |
---|
686 | 'username_or_email_for_privacy_request', |
---|
687 | 'username_or_email_for_privacy_request', |
---|
688 | __( 'Unable to initiate confirmation request.' ), |
---|
689 | 'error' |
---|
690 | ); |
---|
691 | break; |
---|
692 | } |
---|
693 | |
---|
694 | wp_send_user_request( $request_id ); |
---|
695 | |
---|
696 | add_settings_error( |
---|
697 | 'username_or_email_for_privacy_request', |
---|
698 | 'username_or_email_for_privacy_request', |
---|
699 | __( 'Confirmation request initiated successfully.' ), |
---|
700 | 'updated' |
---|
701 | ); |
---|
702 | break; |
---|
703 | } |
---|
704 | } |
---|
705 | } |
---|
706 | |
---|
707 | /** |
---|
708 | * Cleans up failed and expired requests before displaying the list table. |
---|
709 | * |
---|
710 | * @since 4.9.6 |
---|
711 | * @access private |
---|
712 | */ |
---|
713 | function _wp_personal_data_cleanup_requests() { |
---|
714 | /** This filter is documented in wp-includes/user.php */ |
---|
715 | $expires = (int) apply_filters( 'user_request_key_expiration', DAY_IN_SECONDS ); |
---|
716 | |
---|
717 | $requests_query = new WP_Query( array( |
---|
718 | 'post_type' => 'user_request', |
---|
719 | 'posts_per_page' => -1, |
---|
720 | 'post_status' => 'request-pending', |
---|
721 | 'fields' => 'ids', |
---|
722 | 'date_query' => array( |
---|
723 | array( |
---|
724 | 'column' => 'post_modified_gmt', |
---|
725 | 'before' => $expires . ' seconds ago', |
---|
726 | ), |
---|
727 | ), |
---|
728 | ) ); |
---|
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 | } |
---|
739 | } |
---|
740 | |
---|
741 | /** |
---|
742 | * Personal data export. |
---|
743 | * |
---|
744 | * @since 4.9.6 |
---|
745 | * @access private |
---|
746 | */ |
---|
747 | function _wp_personal_data_export_page() { |
---|
748 | if ( ! current_user_can( 'export_others_personal_data' ) ) { |
---|
749 | wp_die( __( 'Sorry, you are not allowed to export personal data on this site.' ) ); |
---|
750 | } |
---|
751 | |
---|
752 | _wp_personal_data_handle_actions(); |
---|
753 | _wp_personal_data_cleanup_requests(); |
---|
754 | |
---|
755 | // "Borrow" xfn.js for now so we don't have to create new files. |
---|
756 | wp_enqueue_script( 'xfn' ); |
---|
757 | |
---|
758 | $requests_table = new WP_Privacy_Data_Export_Requests_Table( array( |
---|
759 | 'plural' => 'privacy_requests', |
---|
760 | 'singular' => 'privacy_request', |
---|
761 | ) ); |
---|
762 | $requests_table->process_bulk_action(); |
---|
763 | $requests_table->prepare_items(); |
---|
764 | ?> |
---|
765 | <div class="wrap nosubsub"> |
---|
766 | <h1><?php esc_html_e( 'Export Personal Data' ); ?></h1> |
---|
767 | <hr class="wp-header-end" /> |
---|
768 | |
---|
769 | <?php settings_errors(); ?> |
---|
770 | |
---|
771 | <form method="post" class="wp-privacy-request-form"> |
---|
772 | <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> |
---|
774 | |
---|
775 | <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> |
---|
777 | <input type="text" required class="regular-text" id="username_or_email_for_privacy_request" name="username_or_email_for_privacy_request" /> |
---|
778 | <?php submit_button( __( 'Send Request' ), 'secondary', 'submit', false ); ?> |
---|
779 | </div> |
---|
780 | <?php wp_nonce_field( 'personal-data-request' ); ?> |
---|
781 | <input type="hidden" name="action" value="add_export_personal_data_request" /> |
---|
782 | <input type="hidden" name="type_of_action" value="export_personal_data" /> |
---|
783 | </form> |
---|
784 | <hr /> |
---|
785 | |
---|
786 | <?php $requests_table->views(); ?> |
---|
787 | |
---|
788 | <form class="search-form wp-clearfix"> |
---|
789 | <?php $requests_table->search_box( __( 'Search Requests' ), 'requests' ); ?> |
---|
790 | <input type="hidden" name="page" value="export_personal_data" /> |
---|
791 | <input type="hidden" name="filter-status" value="<?php echo isset( $_REQUEST['filter-status'] ) ? esc_attr( sanitize_text_field( $_REQUEST['filter-status'] ) ) : ''; ?>" /> |
---|
792 | <input type="hidden" name="orderby" value="<?php echo isset( $_REQUEST['orderby'] ) ? esc_attr( sanitize_text_field( $_REQUEST['orderby'] ) ) : ''; ?>" /> |
---|
793 | <input type="hidden" name="order" value="<?php echo isset( $_REQUEST['order'] ) ? esc_attr( sanitize_text_field( $_REQUEST['order'] ) ) : ''; ?>" /> |
---|
794 | </form> |
---|
795 | |
---|
796 | <form method="post"> |
---|
797 | <?php |
---|
798 | $requests_table->display(); |
---|
799 | $requests_table->embed_scripts(); |
---|
800 | ?> |
---|
801 | </form> |
---|
802 | </div> |
---|
803 | <?php |
---|
804 | } |
---|
805 | |
---|
806 | /** |
---|
807 | * Personal data anonymization. |
---|
808 | * |
---|
809 | * @since 4.9.6 |
---|
810 | * @access private |
---|
811 | */ |
---|
812 | function _wp_personal_data_removal_page() { |
---|
813 | /* |
---|
814 | * Require both caps in order to make it explicitly clear that delegating |
---|
815 | * erasure from network admins to single-site admins will give them the |
---|
816 | * ability to affect global users, rather than being limited to the site |
---|
817 | * that they administer. |
---|
818 | */ |
---|
819 | if ( ! current_user_can( 'erase_others_personal_data' ) || ! current_user_can( 'delete_users' ) ) { |
---|
820 | wp_die( __( 'Sorry, you are not allowed to erase data on this site.' ) ); |
---|
821 | } |
---|
822 | |
---|
823 | _wp_personal_data_handle_actions(); |
---|
824 | _wp_personal_data_cleanup_requests(); |
---|
825 | |
---|
826 | // "Borrow" xfn.js for now so we don't have to create new files. |
---|
827 | wp_enqueue_script( 'xfn' ); |
---|
828 | |
---|
829 | $requests_table = new WP_Privacy_Data_Removal_Requests_Table( array( |
---|
830 | 'plural' => 'privacy_requests', |
---|
831 | 'singular' => 'privacy_request', |
---|
832 | ) ); |
---|
833 | |
---|
834 | $requests_table->process_bulk_action(); |
---|
835 | $requests_table->prepare_items(); |
---|
836 | |
---|
837 | ?> |
---|
838 | <div class="wrap nosubsub"> |
---|
839 | <h1><?php esc_html_e( 'Erase Personal Data' ); ?></h1> |
---|
840 | <hr class="wp-header-end" /> |
---|
841 | |
---|
842 | <?php settings_errors(); ?> |
---|
843 | |
---|
844 | <form method="post" class="wp-privacy-request-form"> |
---|
845 | <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> |
---|
847 | |
---|
848 | <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> |
---|
850 | <input type="text" required class="regular-text" id="username_or_email_for_privacy_request" name="username_or_email_for_privacy_request" /> |
---|
851 | <?php submit_button( __( 'Send Request' ), 'secondary', 'submit', false ); ?> |
---|
852 | </div> |
---|
853 | <?php wp_nonce_field( 'personal-data-request' ); ?> |
---|
854 | <input type="hidden" name="action" value="add_remove_personal_data_request" /> |
---|
855 | <input type="hidden" name="type_of_action" value="remove_personal_data" /> |
---|
856 | </form> |
---|
857 | <hr /> |
---|
858 | |
---|
859 | <?php $requests_table->views(); ?> |
---|
860 | |
---|
861 | <form class="search-form wp-clearfix"> |
---|
862 | <?php $requests_table->search_box( __( 'Search Requests' ), 'requests' ); ?> |
---|
863 | <input type="hidden" name="page" value="remove_personal_data" /> |
---|
864 | <input type="hidden" name="filter-status" value="<?php echo isset( $_REQUEST['filter-status'] ) ? esc_attr( sanitize_text_field( $_REQUEST['filter-status'] ) ) : ''; ?>" /> |
---|
865 | <input type="hidden" name="orderby" value="<?php echo isset( $_REQUEST['orderby'] ) ? esc_attr( sanitize_text_field( $_REQUEST['orderby'] ) ) : ''; ?>" /> |
---|
866 | <input type="hidden" name="order" value="<?php echo isset( $_REQUEST['order'] ) ? esc_attr( sanitize_text_field( $_REQUEST['order'] ) ) : ''; ?>" /> |
---|
867 | </form> |
---|
868 | |
---|
869 | <form method="post"> |
---|
870 | <?php |
---|
871 | $requests_table->display(); |
---|
872 | $requests_table->embed_scripts(); |
---|
873 | ?> |
---|
874 | </form> |
---|
875 | </div> |
---|
876 | <?php |
---|
877 | } |
---|
878 | |
---|
879 | /** |
---|
880 | * Mark erasure requests as completed after processing is finished. |
---|
881 | * |
---|
882 | * This intercepts the Ajax responses to personal data eraser page requests, and |
---|
883 | * monitors the status of a request. Once all of the processing has finished, the |
---|
884 | * request is marked as completed. |
---|
885 | * |
---|
886 | * @since 4.9.6 |
---|
887 | * |
---|
888 | * @see wp_privacy_personal_data_erasure_page |
---|
889 | * |
---|
890 | * @param array $response The response from the personal data eraser for |
---|
891 | * the given page. |
---|
892 | * @param int $eraser_index The index of the personal data eraser. Begins |
---|
893 | * at 1. |
---|
894 | * @param string $email_address The email address of the user whose personal |
---|
895 | * data this is. |
---|
896 | * @param int $page The page of personal data for this eraser. |
---|
897 | * Begins at 1. |
---|
898 | * @param int $request_id The request ID for this personal data erasure. |
---|
899 | * @return array The filtered response. |
---|
900 | */ |
---|
901 | function wp_privacy_process_personal_data_erasure_page( $response, $eraser_index, $email_address, $page, $request_id ) { |
---|
902 | /* |
---|
903 | * If the eraser response is malformed, don't attempt to consume it; let it |
---|
904 | * pass through, so that the default Ajax processing will generate a warning |
---|
905 | * to the user. |
---|
906 | */ |
---|
907 | if ( ! is_array( $response ) ) { |
---|
908 | return $response; |
---|
909 | } |
---|
910 | |
---|
911 | if ( ! array_key_exists( 'done', $response ) ) { |
---|
912 | return $response; |
---|
913 | } |
---|
914 | |
---|
915 | if ( ! array_key_exists( 'items_removed', $response ) ) { |
---|
916 | return $response; |
---|
917 | } |
---|
918 | |
---|
919 | if ( ! array_key_exists( 'items_retained', $response ) ) { |
---|
920 | return $response; |
---|
921 | } |
---|
922 | |
---|
923 | if ( ! array_key_exists( 'messages', $response ) ) { |
---|
924 | return $response; |
---|
925 | } |
---|
926 | |
---|
927 | $request = wp_get_user_request_data( $request_id ); |
---|
928 | |
---|
929 | if ( ! $request || 'remove_personal_data' !== $request->action_name ) { |
---|
930 | wp_send_json_error( __( 'Invalid request ID when processing eraser data.' ) ); |
---|
931 | } |
---|
932 | |
---|
933 | /** This filter is documented in wp-admin/includes/ajax-actions.php */ |
---|
934 | $erasers = apply_filters( 'wp_privacy_personal_data_erasers', array() ); |
---|
935 | $is_last_eraser = count( $erasers ) === $eraser_index; |
---|
936 | $eraser_done = $response['done']; |
---|
937 | |
---|
938 | if ( ! $is_last_eraser || ! $eraser_done ) { |
---|
939 | return $response; |
---|
940 | } |
---|
941 | |
---|
942 | _wp_privacy_completed_request( $request_id ); |
---|
943 | |
---|
944 | /** |
---|
945 | * Fires immediately after a personal data erasure request has been marked completed. |
---|
946 | * |
---|
947 | * @since 4.9.6 |
---|
948 | * |
---|
949 | * @param int $request_id The privacy request post ID associated with this request. |
---|
950 | */ |
---|
951 | do_action( 'wp_privacy_personal_data_erased', $request_id ); |
---|
952 | |
---|
953 | return $response; |
---|
954 | } |
---|
955 | |
---|
956 | /** |
---|
957 | * Add requests pages. |
---|
958 | * |
---|
959 | * @since 4.9.6 |
---|
960 | * @access private |
---|
961 | */ |
---|
962 | function _wp_privacy_hook_requests_page() { |
---|
963 | add_submenu_page( 'tools.php', __( 'Export Personal Data' ), __( 'Export Personal Data' ), 'export_others_personal_data', 'export_personal_data', '_wp_personal_data_export_page' ); |
---|
964 | add_submenu_page( 'tools.php', __( 'Erase Personal Data' ), __( 'Erase Personal Data' ), 'erase_others_personal_data', 'remove_personal_data', '_wp_personal_data_removal_page' ); |
---|
965 | } |
---|
966 | |
---|
967 | /** |
---|
968 | * Add options for the privacy requests screens. |
---|
969 | * |
---|
970 | * @since 4.9.8 |
---|
971 | * @access private |
---|
972 | */ |
---|
973 | function _wp_privacy_requests_screen_options() { |
---|
974 | $args = array( |
---|
975 | 'option' => str_replace( 'tools_page_', '', get_current_screen()->id ) . '_requests_per_page', |
---|
976 | ); |
---|
977 | add_screen_option( 'per_page', $args ); |
---|
978 | } |
---|
979 | |
---|
980 | // TODO: move the following classes in new files. |
---|
981 | if ( ! class_exists( 'WP_List_Table' ) ) { |
---|
982 | require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' ); |
---|
983 | } |
---|
984 | |
---|
985 | /** |
---|
986 | * WP_Privacy_Requests_Table class. |
---|
987 | * |
---|
988 | * @since 4.9.6 |
---|
989 | */ |
---|
990 | abstract class WP_Privacy_Requests_Table extends WP_List_Table { |
---|
991 | |
---|
992 | /** |
---|
993 | * Action name for the requests this table will work with. Classes |
---|
994 | * which inherit from WP_Privacy_Requests_Table should define this. |
---|
995 | * |
---|
996 | * Example: 'export_personal_data'. |
---|
997 | * |
---|
998 | * @since 4.9.6 |
---|
999 | * |
---|
1000 | * @var string $request_type Name of action. |
---|
1001 | */ |
---|
1002 | protected $request_type = 'INVALID'; |
---|
1003 | |
---|
1004 | /** |
---|
1005 | * Post type to be used. |
---|
1006 | * |
---|
1007 | * @since 4.9.6 |
---|
1008 | * |
---|
1009 | * @var string $post_type The post type. |
---|
1010 | */ |
---|
1011 | protected $post_type = 'INVALID'; |
---|
1012 | |
---|
1013 | /** |
---|
1014 | * Get columns to show in the list table. |
---|
1015 | * |
---|
1016 | * @since 4.9.6 |
---|
1017 | * |
---|
1018 | * @return array Array of columns. |
---|
1019 | */ |
---|
1020 | public function get_columns() { |
---|
1021 | $columns = array( |
---|
1022 | 'cb' => '<input type="checkbox" />', |
---|
1023 | 'email' => __( 'Requester' ), |
---|
1024 | 'status' => __( 'Status' ), |
---|
1025 | 'created_timestamp' => __( 'Requested' ), |
---|
1026 | 'next_steps' => __( 'Next Steps' ), |
---|
1027 | ); |
---|
1028 | return $columns; |
---|
1029 | } |
---|
1030 | |
---|
1031 | /** |
---|
1032 | * Get a list of sortable columns. |
---|
1033 | * |
---|
1034 | * @since 4.9.6 |
---|
1035 | * |
---|
1036 | * @return array Default sortable columns. |
---|
1037 | */ |
---|
1038 | protected function get_sortable_columns() { |
---|
1039 | return array(); |
---|
1040 | } |
---|
1041 | |
---|
1042 | /** |
---|
1043 | * Default primary column. |
---|
1044 | * |
---|
1045 | * @since 4.9.6 |
---|
1046 | * |
---|
1047 | * @return string Default primary column name. |
---|
1048 | */ |
---|
1049 | protected function get_default_primary_column_name() { |
---|
1050 | return 'email'; |
---|
1051 | } |
---|
1052 | |
---|
1053 | /** |
---|
1054 | * Count number of requests for each status. |
---|
1055 | * |
---|
1056 | * @since 4.9.6 |
---|
1057 | * |
---|
1058 | * @return object Number of posts for each status. |
---|
1059 | */ |
---|
1060 | protected function get_request_counts() { |
---|
1061 | global $wpdb; |
---|
1062 | |
---|
1063 | $cache_key = $this->post_type . '-' . $this->request_type; |
---|
1064 | $counts = wp_cache_get( $cache_key, 'counts' ); |
---|
1065 | |
---|
1066 | if ( false !== $counts ) { |
---|
1067 | return $counts; |
---|
1068 | } |
---|
1069 | |
---|
1070 | $query = " |
---|
1071 | SELECT post_status, COUNT( * ) AS num_posts |
---|
1072 | FROM {$wpdb->posts} |
---|
1073 | WHERE post_type = %s |
---|
1074 | AND post_name = %s |
---|
1075 | GROUP BY post_status"; |
---|
1076 | |
---|
1077 | $results = (array) $wpdb->get_results( $wpdb->prepare( $query, $this->post_type, $this->request_type ), ARRAY_A ); |
---|
1078 | $counts = array_fill_keys( get_post_stati(), 0 ); |
---|
1079 | |
---|
1080 | foreach ( $results as $row ) { |
---|
1081 | $counts[ $row['post_status'] ] = $row['num_posts']; |
---|
1082 | } |
---|
1083 | |
---|
1084 | $counts = (object) $counts; |
---|
1085 | wp_cache_set( $cache_key, $counts, 'counts' ); |
---|
1086 | |
---|
1087 | return $counts; |
---|
1088 | } |
---|
1089 | |
---|
1090 | /** |
---|
1091 | * Get an associative array ( id => link ) with the list of views available on this table. |
---|
1092 | * |
---|
1093 | * @since 4.9.6 |
---|
1094 | * |
---|
1095 | * @return array Associative array of views in the format of $view_name => $view_markup. |
---|
1096 | */ |
---|
1097 | protected function get_views() { |
---|
1098 | $current_status = isset( $_REQUEST['filter-status'] ) ? sanitize_text_field( $_REQUEST['filter-status'] ) : ''; |
---|
1099 | $statuses = _wp_privacy_statuses(); |
---|
1100 | $views = array(); |
---|
1101 | $admin_url = admin_url( 'tools.php?page=' . $this->request_type ); |
---|
1102 | $counts = $this->get_request_counts(); |
---|
1103 | $total_requests = absint( array_sum( (array) $counts ) ); |
---|
1104 | |
---|
1105 | $current_link_attributes = empty( $current_status ) ? ' class="current" aria-current="page"' : ''; |
---|
1106 | $views['all'] = '<a href="' . esc_url( $admin_url ) . "\" $current_link_attributes>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%d)</span>', $total_requests, 'requests' ), number_format_i18n( $total_requests ) ) . '</a>'; |
---|
1107 | |
---|
1108 | foreach ( $statuses as $status => $label ) { |
---|
1109 | $current_link_attributes = $status === $current_status ? ' class="current" aria-current="page"' : ''; |
---|
1110 | $total_status_requests = absint( $counts->$status ); |
---|
1111 | $views[ $status ] = '<a href="' . esc_url( add_query_arg( 'filter-status', $status, $admin_url ) ) . "\" $current_link_attributes>" . sprintf( _nx( '%s <span class="count">(%d)</span>', '%s <span class="count">(%d)</span>', $total_status_requests, 'requests' ), esc_html( $label ), number_format_i18n( $total_status_requests ) ) . '</a>'; |
---|
1112 | } |
---|
1113 | |
---|
1114 | return $views; |
---|
1115 | } |
---|
1116 | |
---|
1117 | /** |
---|
1118 | * Get bulk actions. |
---|
1119 | * |
---|
1120 | * @since 4.9.6 |
---|
1121 | * |
---|
1122 | * @return array List of bulk actions. |
---|
1123 | */ |
---|
1124 | protected function get_bulk_actions() { |
---|
1125 | return array( |
---|
1126 | 'delete' => __( 'Remove' ), |
---|
1127 | 'resend' => __( 'Resend email' ), |
---|
1128 | ); |
---|
1129 | } |
---|
1130 | |
---|
1131 | /** |
---|
1132 | * Process bulk actions. |
---|
1133 | * |
---|
1134 | * @since 4.9.6 |
---|
1135 | */ |
---|
1136 | public function process_bulk_action() { |
---|
1137 | $action = $this->current_action(); |
---|
1138 | $request_ids = isset( $_REQUEST['request_id'] ) ? wp_parse_id_list( wp_unslash( $_REQUEST['request_id'] ) ) : array(); |
---|
1139 | |
---|
1140 | $count = 0; |
---|
1141 | |
---|
1142 | if ( $request_ids ) { |
---|
1143 | check_admin_referer( 'bulk-privacy_requests' ); |
---|
1144 | } |
---|
1145 | |
---|
1146 | switch ( $action ) { |
---|
1147 | case 'delete': |
---|
1148 | foreach ( $request_ids as $request_id ) { |
---|
1149 | if ( wp_delete_post( $request_id, true ) ) { |
---|
1150 | $count ++; |
---|
1151 | } |
---|
1152 | } |
---|
1153 | |
---|
1154 | add_settings_error( |
---|
1155 | 'bulk_action', |
---|
1156 | 'bulk_action', |
---|
1157 | /* translators: %d: number of requests */ |
---|
1158 | sprintf( _n( 'Deleted %d request', 'Deleted %d requests', $count ), $count ), |
---|
1159 | 'updated' |
---|
1160 | ); |
---|
1161 | break; |
---|
1162 | case 'resend': |
---|
1163 | foreach ( $request_ids as $request_id ) { |
---|
1164 | $resend = _wp_privacy_resend_request( $request_id ); |
---|
1165 | |
---|
1166 | if ( $resend && ! is_wp_error( $resend ) ) { |
---|
1167 | $count++; |
---|
1168 | } |
---|
1169 | } |
---|
1170 | |
---|
1171 | add_settings_error( |
---|
1172 | 'bulk_action', |
---|
1173 | 'bulk_action', |
---|
1174 | /* translators: %d: number of requests */ |
---|
1175 | sprintf( _n( 'Re-sent %d request', 'Re-sent %d requests', $count ), $count ), |
---|
1176 | 'updated' |
---|
1177 | ); |
---|
1178 | break; |
---|
1179 | } |
---|
1180 | } |
---|
1181 | |
---|
1182 | /** |
---|
1183 | * Prepare items to output. |
---|
1184 | * |
---|
1185 | * @since 4.9.6 |
---|
1186 | */ |
---|
1187 | public function prepare_items() { |
---|
1188 | global $wpdb; |
---|
1189 | |
---|
1190 | $primary = $this->get_primary_column_name(); |
---|
1191 | $this->_column_headers = array( |
---|
1192 | $this->get_columns(), |
---|
1193 | array(), |
---|
1194 | $this->get_sortable_columns(), |
---|
1195 | $primary, |
---|
1196 | ); |
---|
1197 | |
---|
1198 | $this->items = array(); |
---|
1199 | $posts_per_page = $this->get_items_per_page( $this->request_type . '_requests_per_page' ); |
---|
1200 | $args = array( |
---|
1201 | 'post_type' => $this->post_type, |
---|
1202 | 'post_name__in' => array( $this->request_type ), |
---|
1203 | 'posts_per_page' => $posts_per_page, |
---|
1204 | 'offset' => isset( $_REQUEST['paged'] ) ? max( 0, absint( $_REQUEST['paged'] ) - 1 ) * $posts_per_page : 0, |
---|
1205 | 'post_status' => 'any', |
---|
1206 | 's' => isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : '', |
---|
1207 | ); |
---|
1208 | |
---|
1209 | if ( ! empty( $_REQUEST['filter-status'] ) ) { |
---|
1210 | $filter_status = isset( $_REQUEST['filter-status'] ) ? sanitize_text_field( $_REQUEST['filter-status'] ) : ''; |
---|
1211 | $args['post_status'] = $filter_status; |
---|
1212 | } |
---|
1213 | |
---|
1214 | $requests_query = new WP_Query( $args ); |
---|
1215 | $requests = $requests_query->posts; |
---|
1216 | |
---|
1217 | foreach ( $requests as $request ) { |
---|
1218 | $this->items[] = wp_get_user_request_data( $request->ID ); |
---|
1219 | } |
---|
1220 | |
---|
1221 | $this->items = array_filter( $this->items ); |
---|
1222 | |
---|
1223 | $this->set_pagination_args( |
---|
1224 | array( |
---|
1225 | 'total_items' => $requests_query->found_posts, |
---|
1226 | 'per_page' => $posts_per_page, |
---|
1227 | ) |
---|
1228 | ); |
---|
1229 | } |
---|
1230 | |
---|
1231 | /** |
---|
1232 | * Checkbox column. |
---|
1233 | * |
---|
1234 | * @since 4.9.6 |
---|
1235 | * |
---|
1236 | * @param WP_User_Request $item Item being shown. |
---|
1237 | * @return string Checkbox column markup. |
---|
1238 | */ |
---|
1239 | public function column_cb( $item ) { |
---|
1240 | return sprintf( '<input type="checkbox" name="request_id[]" value="%1$s" /><span class="spinner"></span>', esc_attr( $item->ID ) ); |
---|
1241 | } |
---|
1242 | |
---|
1243 | /** |
---|
1244 | * Status column. |
---|
1245 | * |
---|
1246 | * @since 4.9.6 |
---|
1247 | * |
---|
1248 | * @param WP_User_Request $item Item being shown. |
---|
1249 | * @return string Status column markup. |
---|
1250 | */ |
---|
1251 | public function column_status( $item ) { |
---|
1252 | $status = get_post_status( $item->ID ); |
---|
1253 | $status_object = get_post_status_object( $status ); |
---|
1254 | |
---|
1255 | if ( ! $status_object || empty( $status_object->label ) ) { |
---|
1256 | return '-'; |
---|
1257 | } |
---|
1258 | |
---|
1259 | $timestamp = false; |
---|
1260 | |
---|
1261 | switch ( $status ) { |
---|
1262 | case 'request-confirmed': |
---|
1263 | $timestamp = $item->confirmed_timestamp; |
---|
1264 | break; |
---|
1265 | case 'request-completed': |
---|
1266 | $timestamp = $item->completed_timestamp; |
---|
1267 | break; |
---|
1268 | } |
---|
1269 | |
---|
1270 | echo '<span class="status-label status-' . esc_attr( $status ) . '">'; |
---|
1271 | echo esc_html( $status_object->label ); |
---|
1272 | |
---|
1273 | if ( $timestamp ) { |
---|
1274 | echo ' (' . $this->get_timestamp_as_date( $timestamp ) . ')'; |
---|
1275 | } |
---|
1276 | |
---|
1277 | echo '</span>'; |
---|
1278 | } |
---|
1279 | |
---|
1280 | /** |
---|
1281 | * Convert timestamp for display. |
---|
1282 | * |
---|
1283 | * @since 4.9.6 |
---|
1284 | * |
---|
1285 | * @param int $timestamp Event timestamp. |
---|
1286 | * @return string Human readable date. |
---|
1287 | */ |
---|
1288 | protected function get_timestamp_as_date( $timestamp ) { |
---|
1289 | if ( empty( $timestamp ) ) { |
---|
1290 | return ''; |
---|
1291 | } |
---|
1292 | |
---|
1293 | $time_diff = current_time( 'timestamp', true ) - $timestamp; |
---|
1294 | |
---|
1295 | if ( $time_diff >= 0 && $time_diff < DAY_IN_SECONDS ) { |
---|
1296 | /* translators: human readable timestamp */ |
---|
1297 | return sprintf( __( '%s ago' ), human_time_diff( $timestamp ) ); |
---|
1298 | } |
---|
1299 | |
---|
1300 | return date_i18n( get_option( 'date_format' ), $timestamp ); |
---|
1301 | } |
---|
1302 | |
---|
1303 | /** |
---|
1304 | * Default column handler. |
---|
1305 | * |
---|
1306 | * @since 4.9.6 |
---|
1307 | * |
---|
1308 | * @param WP_User_Request $item Item being shown. |
---|
1309 | * @param string $column_name Name of column being shown. |
---|
1310 | * @return string Default column output. |
---|
1311 | */ |
---|
1312 | public function column_default( $item, $column_name ) { |
---|
1313 | $cell_value = $item->$column_name; |
---|
1314 | |
---|
1315 | if ( in_array( $column_name, array( 'created_timestamp' ), true ) ) { |
---|
1316 | return $this->get_timestamp_as_date( $cell_value ); |
---|
1317 | } |
---|
1318 | |
---|
1319 | return $cell_value; |
---|
1320 | } |
---|
1321 | |
---|
1322 | /** |
---|
1323 | * Actions column. Overridden by children. |
---|
1324 | * |
---|
1325 | * @since 4.9.6 |
---|
1326 | * |
---|
1327 | * @param WP_User_Request $item Item being shown. |
---|
1328 | * @return string Email column markup. |
---|
1329 | */ |
---|
1330 | public function column_email( $item ) { |
---|
1331 | return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( array() ) ); |
---|
1332 | } |
---|
1333 | |
---|
1334 | /** |
---|
1335 | * Next steps column. Overridden by children. |
---|
1336 | * |
---|
1337 | * @since 4.9.6 |
---|
1338 | * |
---|
1339 | * @param WP_User_Request $item Item being shown. |
---|
1340 | */ |
---|
1341 | public function column_next_steps( $item ) {} |
---|
1342 | |
---|
1343 | /** |
---|
1344 | * Generates content for a single row of the table, |
---|
1345 | * |
---|
1346 | * @since 4.9.6 |
---|
1347 | * |
---|
1348 | * @param WP_User_Request $item The current item. |
---|
1349 | */ |
---|
1350 | public function single_row( $item ) { |
---|
1351 | $status = $item->status; |
---|
1352 | |
---|
1353 | echo '<tr id="request-' . esc_attr( $item->ID ) . '" class="status-' . esc_attr( $status ) . '">'; |
---|
1354 | $this->single_row_columns( $item ); |
---|
1355 | echo '</tr>'; |
---|
1356 | } |
---|
1357 | |
---|
1358 | /** |
---|
1359 | * Embed scripts used to perform actions. Overridden by children. |
---|
1360 | * |
---|
1361 | * @since 4.9.6 |
---|
1362 | */ |
---|
1363 | public function embed_scripts() {} |
---|
1364 | } |
---|
1365 | |
---|
1366 | /** |
---|
1367 | * WP_Privacy_Data_Export_Requests_Table class. |
---|
1368 | * |
---|
1369 | * @since 4.9.6 |
---|
1370 | */ |
---|
1371 | class WP_Privacy_Data_Export_Requests_Table extends WP_Privacy_Requests_Table { |
---|
1372 | /** |
---|
1373 | * Action name for the requests this table will work with. |
---|
1374 | * |
---|
1375 | * @since 4.9.6 |
---|
1376 | * |
---|
1377 | * @var string $request_type Name of action. |
---|
1378 | */ |
---|
1379 | protected $request_type = 'export_personal_data'; |
---|
1380 | |
---|
1381 | /** |
---|
1382 | * Post type for the requests. |
---|
1383 | * |
---|
1384 | * @since 4.9.6 |
---|
1385 | * |
---|
1386 | * @var string $post_type The post type. |
---|
1387 | */ |
---|
1388 | protected $post_type = 'user_request'; |
---|
1389 | |
---|
1390 | /** |
---|
1391 | * Actions column. |
---|
1392 | * |
---|
1393 | * @since 4.9.6 |
---|
1394 | * |
---|
1395 | * @param WP_User_Request $item Item being shown. |
---|
1396 | * @return string Email column markup. |
---|
1397 | */ |
---|
1398 | public function column_email( $item ) { |
---|
1399 | /** This filter is documented in wp-admin/includes/ajax-actions.php */ |
---|
1400 | $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() ); |
---|
1401 | $exporters_count = count( $exporters ); |
---|
1402 | $request_id = $item->ID; |
---|
1403 | $nonce = wp_create_nonce( 'wp-privacy-export-personal-data-' . $request_id ); |
---|
1404 | |
---|
1405 | $download_data_markup = '<div class="export-personal-data" ' . |
---|
1406 | 'data-exporters-count="' . esc_attr( $exporters_count ) . '" ' . |
---|
1407 | 'data-request-id="' . esc_attr( $request_id ) . '" ' . |
---|
1408 | 'data-nonce="' . esc_attr( $nonce ) . |
---|
1409 | '">'; |
---|
1410 | |
---|
1411 | $download_data_markup .= '<span class="export-personal-data-idle"><button type="button" class="button-link export-personal-data-handle">' . __( 'Download Personal Data' ) . '</button></span>' . |
---|
1412 | '<span style="display:none" class="export-personal-data-processing" >' . __( 'Downloading Data...' ) . '</span>' . |
---|
1413 | '<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>' . |
---|
1414 | '<span style="display:none" class="export-personal-data-failed">' . __( 'Download has failed.' ) . ' <button type="button" class="button-link">' . __( 'Retry' ) . '</button></span>'; |
---|
1415 | |
---|
1416 | $download_data_markup .= '</div>'; |
---|
1417 | |
---|
1418 | $row_actions = array( |
---|
1419 | 'download-data' => $download_data_markup, |
---|
1420 | ); |
---|
1421 | |
---|
1422 | return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( $row_actions ) ); |
---|
1423 | } |
---|
1424 | |
---|
1425 | /** |
---|
1426 | * Displays the next steps column. |
---|
1427 | * |
---|
1428 | * @since 4.9.6 |
---|
1429 | * |
---|
1430 | * @param WP_User_Request $item Item being shown. |
---|
1431 | */ |
---|
1432 | public function column_next_steps( $item ) { |
---|
1433 | $status = $item->status; |
---|
1434 | |
---|
1435 | switch ( $status ) { |
---|
1436 | case 'request-pending': |
---|
1437 | esc_html_e( 'Waiting for confirmation' ); |
---|
1438 | break; |
---|
1439 | case 'request-confirmed': |
---|
1440 | /** This filter is documented in wp-admin/includes/ajax-actions.php */ |
---|
1441 | $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() ); |
---|
1442 | $exporters_count = count( $exporters ); |
---|
1443 | $request_id = $item->ID; |
---|
1444 | $nonce = wp_create_nonce( 'wp-privacy-export-personal-data-' . $request_id ); |
---|
1445 | |
---|
1446 | echo '<div class="export-personal-data" ' . |
---|
1447 | 'data-send-as-email="1" ' . |
---|
1448 | 'data-exporters-count="' . esc_attr( $exporters_count ) . '" ' . |
---|
1449 | 'data-request-id="' . esc_attr( $request_id ) . '" ' . |
---|
1450 | 'data-nonce="' . esc_attr( $nonce ) . |
---|
1451 | '">'; |
---|
1452 | |
---|
1453 | ?> |
---|
1454 | <span class="export-personal-data-idle"><button type="button" class="button export-personal-data-handle"><?php _e( 'Email Data' ); ?></button></span> |
---|
1455 | <span style="display:none" class="export-personal-data-processing button updating-message" ><?php _e( 'Sending Email...' ); ?></span> |
---|
1456 | <span style="display:none" class="export-personal-data-success success-message" ><?php _e( 'Email sent.' ); ?></span> |
---|
1457 | <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> |
---|
1458 | <?php |
---|
1459 | |
---|
1460 | echo '</div>'; |
---|
1461 | break; |
---|
1462 | case 'request-failed': |
---|
1463 | submit_button( __( 'Retry' ), 'secondary', 'privacy_action_email_retry[' . $item->ID . ']', false ); |
---|
1464 | break; |
---|
1465 | case 'request-completed': |
---|
1466 | echo '<a href="' . esc_url( wp_nonce_url( add_query_arg( array( |
---|
1467 | 'action' => 'delete', |
---|
1468 | 'request_id' => array( $item->ID ), |
---|
1469 | ), admin_url( 'tools.php?page=export_personal_data' ) ), 'bulk-privacy_requests' ) ) . '" class="button">' . esc_html__( 'Remove request' ) . '</a>'; |
---|
1470 | break; |
---|
1471 | } |
---|
1472 | } |
---|
1473 | } |
---|
1474 | |
---|
1475 | /** |
---|
1476 | * WP_Privacy_Data_Removal_Requests_Table class. |
---|
1477 | * |
---|
1478 | * @since 4.9.6 |
---|
1479 | */ |
---|
1480 | class WP_Privacy_Data_Removal_Requests_Table extends WP_Privacy_Requests_Table { |
---|
1481 | /** |
---|
1482 | * Action name for the requests this table will work with. |
---|
1483 | * |
---|
1484 | * @since 4.9.6 |
---|
1485 | * |
---|
1486 | * @var string $request_type Name of action. |
---|
1487 | */ |
---|
1488 | protected $request_type = 'remove_personal_data'; |
---|
1489 | |
---|
1490 | /** |
---|
1491 | * Post type for the requests. |
---|
1492 | * |
---|
1493 | * @since 4.9.6 |
---|
1494 | * |
---|
1495 | * @var string $post_type The post type. |
---|
1496 | */ |
---|
1497 | protected $post_type = 'user_request'; |
---|
1498 | |
---|
1499 | /** |
---|
1500 | * Actions column. |
---|
1501 | * |
---|
1502 | * @since 4.9.6 |
---|
1503 | * |
---|
1504 | * @param WP_User_Request $item Item being shown. |
---|
1505 | * @return string Email column markup. |
---|
1506 | */ |
---|
1507 | public function column_email( $item ) { |
---|
1508 | $row_actions = array(); |
---|
1509 | |
---|
1510 | // Allow the administrator to "force remove" the personal data even if confirmation has not yet been received. |
---|
1511 | $status = $item->status; |
---|
1512 | if ( 'request-confirmed' !== $status ) { |
---|
1513 | /** This filter is documented in wp-admin/includes/ajax-actions.php */ |
---|
1514 | $erasers = apply_filters( 'wp_privacy_personal_data_erasers', array() ); |
---|
1515 | $erasers_count = count( $erasers ); |
---|
1516 | $request_id = $item->ID; |
---|
1517 | $nonce = wp_create_nonce( 'wp-privacy-erase-personal-data-' . $request_id ); |
---|
1518 | |
---|
1519 | $remove_data_markup = '<div class="remove-personal-data force-remove-personal-data" ' . |
---|
1520 | 'data-erasers-count="' . esc_attr( $erasers_count ) . '" ' . |
---|
1521 | 'data-request-id="' . esc_attr( $request_id ) . '" ' . |
---|
1522 | 'data-nonce="' . esc_attr( $nonce ) . |
---|
1523 | '">'; |
---|
1524 | |
---|
1525 | $remove_data_markup .= '<span class="remove-personal-data-idle"><button type="button" class="button-link remove-personal-data-handle">' . __( 'Force Erase Personal Data' ) . '</button></span>' . |
---|
1526 | '<span style="display:none" class="remove-personal-data-processing" >' . __( 'Erasing Data...' ) . '</span>' . |
---|
1527 | '<span style="display:none" class="remove-personal-data-failed">' . __( 'Force Erase has failed.' ) . ' <button type="button" class="button-link remove-personal-data-handle">' . __( 'Retry' ) . '</button></span>'; |
---|
1528 | |
---|
1529 | $remove_data_markup .= '</div>'; |
---|
1530 | |
---|
1531 | $row_actions = array( |
---|
1532 | 'remove-data' => $remove_data_markup, |
---|
1533 | ); |
---|
1534 | } |
---|
1535 | |
---|
1536 | return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( $row_actions ) ); |
---|
1537 | } |
---|
1538 | |
---|
1539 | /** |
---|
1540 | * Next steps column. |
---|
1541 | * |
---|
1542 | * @since 4.9.6 |
---|
1543 | * |
---|
1544 | * @param WP_User_Request $item Item being shown. |
---|
1545 | */ |
---|
1546 | public function column_next_steps( $item ) { |
---|
1547 | $status = $item->status; |
---|
1548 | |
---|
1549 | switch ( $status ) { |
---|
1550 | case 'request-pending': |
---|
1551 | esc_html_e( 'Waiting for confirmation' ); |
---|
1552 | break; |
---|
1553 | case 'request-confirmed': |
---|
1554 | /** This filter is documented in wp-admin/includes/ajax-actions.php */ |
---|
1555 | $erasers = apply_filters( 'wp_privacy_personal_data_erasers', array() ); |
---|
1556 | $erasers_count = count( $erasers ); |
---|
1557 | $request_id = $item->ID; |
---|
1558 | $nonce = wp_create_nonce( 'wp-privacy-erase-personal-data-' . $request_id ); |
---|
1559 | |
---|
1560 | echo '<div class="remove-personal-data" ' . |
---|
1561 | 'data-force-erase="1" ' . |
---|
1562 | 'data-erasers-count="' . esc_attr( $erasers_count ) . '" ' . |
---|
1563 | 'data-request-id="' . esc_attr( $request_id ) . '" ' . |
---|
1564 | 'data-nonce="' . esc_attr( $nonce ) . |
---|
1565 | '">'; |
---|
1566 | |
---|
1567 | ?> |
---|
1568 | <span class="remove-personal-data-idle"><button type="button" class="button remove-personal-data-handle"><?php _e( 'Erase Personal Data' ); ?></button></span> |
---|
1569 | <span style="display:none" class="remove-personal-data-processing button updating-message" ><?php _e( 'Erasing Data...' ); ?></span> |
---|
1570 | <span style="display:none" class="remove-personal-data-failed"><?php _e( 'Erasing Data has failed.' ); ?> <button type="button" class="button remove-personal-data-handle"><?php _e( 'Retry' ); ?></button></span> |
---|
1571 | <?php |
---|
1572 | |
---|
1573 | echo '</div>'; |
---|
1574 | |
---|
1575 | break; |
---|
1576 | case 'request-failed': |
---|
1577 | submit_button( __( 'Retry' ), 'secondary', 'privacy_action_email_retry[' . $item->ID . ']', false ); |
---|
1578 | break; |
---|
1579 | case 'request-completed': |
---|
1580 | echo '<a href="' . esc_url( wp_nonce_url( add_query_arg( array( |
---|
1581 | 'action' => 'delete', |
---|
1582 | 'request_id' => array( $item->ID ), |
---|
1583 | ), admin_url( 'tools.php?page=remove_personal_data' ) ), 'bulk-privacy_requests' ) ) . '" class="button">' . esc_html__( 'Remove request' ) . '</a>'; |
---|
1584 | break; |
---|
1585 | } |
---|
1586 | } |
---|
1587 | |
---|
1588 | } |
---|