418 delete_user_setting('default_password_nag'); |
460 delete_user_setting('default_password_nag'); |
419 update_user_option($user_ID, 'default_password_nag', false, true); |
461 update_user_option($user_ID, 'default_password_nag', false, true); |
420 } |
462 } |
421 } |
463 } |
422 |
464 |
423 add_action('admin_notices', 'default_password_nag'); |
|
424 |
|
425 /** |
465 /** |
426 * @since 2.8.0 |
466 * @since 2.8.0 |
|
467 * |
|
468 * @global string $pagenow |
427 */ |
469 */ |
428 function default_password_nag() { |
470 function default_password_nag() { |
429 global $pagenow; |
471 global $pagenow; |
430 // Short-circuit it. |
472 // Short-circuit it. |
431 if ( 'profile.php' == $pagenow || ! get_user_option('default_password_nag') ) |
473 if ( 'profile.php' == $pagenow || ! get_user_option('default_password_nag') ) |
432 return; |
474 return; |
433 |
475 |
434 echo '<div class="error default-password-nag">'; |
476 echo '<div class="error default-password-nag">'; |
435 echo '<p>'; |
477 echo '<p>'; |
436 echo '<strong>' . __('Notice:') . '</strong> '; |
478 echo '<strong>' . __('Notice:') . '</strong> '; |
437 _e('You’re using the auto-generated password for your account. Would you like to change it to something easier to remember?'); |
479 _e('You’re using the auto-generated password for your account. Would you like to change it?'); |
438 echo '</p><p>'; |
480 echo '</p><p>'; |
439 printf( '<a href="%s">' . __('Yes, take me to my profile page') . '</a> | ', get_edit_profile_url() . '#password' ); |
481 printf( '<a href="%s">' . __('Yes, take me to my profile page') . '</a> | ', get_edit_profile_url() . '#password' ); |
440 printf( '<a href="%s" id="default-password-nag-no">' . __('No thanks, do not remind me again') . '</a>', '?default_password_nag=0' ); |
482 printf( '<a href="%s" id="default-password-nag-no">' . __('No thanks, do not remind me again') . '</a>', '?default_password_nag=0' ); |
441 echo '</p></div>'; |
483 echo '</p></div>'; |
442 } |
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 |
|
1104 $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>'; |
|
1106 |
|
1107 foreach ( $statuses as $status => $label ) { |
|
1108 $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>'; |
|
1110 } |
|
1111 |
|
1112 return $views; |
|
1113 } |
|
1114 |
|
1115 /** |
|
1116 * Get bulk actions. |
|
1117 * |
|
1118 * @since 4.9.6 |
|
1119 * |
|
1120 * @return array List of bulk actions. |
|
1121 */ |
|
1122 protected function get_bulk_actions() { |
|
1123 return array( |
|
1124 'delete' => __( 'Remove' ), |
|
1125 'resend' => __( 'Resend email' ), |
|
1126 ); |
|
1127 } |
|
1128 |
|
1129 /** |
|
1130 * Process bulk actions. |
|
1131 * |
|
1132 * @since 4.9.6 |
|
1133 */ |
|
1134 public function process_bulk_action() { |
|
1135 $action = $this->current_action(); |
|
1136 $request_ids = isset( $_REQUEST['request_id'] ) ? wp_parse_id_list( wp_unslash( $_REQUEST['request_id'] ) ) : array(); |
|
1137 |
|
1138 $count = 0; |
|
1139 |
|
1140 if ( $request_ids ) { |
|
1141 check_admin_referer( 'bulk-privacy_requests' ); |
|
1142 } |
|
1143 |
|
1144 switch ( $action ) { |
|
1145 case 'delete': |
|
1146 foreach ( $request_ids as $request_id ) { |
|
1147 if ( wp_delete_post( $request_id, true ) ) { |
|
1148 $count ++; |
|
1149 } |
|
1150 } |
|
1151 |
|
1152 add_settings_error( |
|
1153 'bulk_action', |
|
1154 'bulk_action', |
|
1155 /* translators: %d: number of requests */ |
|
1156 sprintf( _n( 'Deleted %d request', 'Deleted %d requests', $count ), $count ), |
|
1157 'updated' |
|
1158 ); |
|
1159 break; |
|
1160 case 'resend': |
|
1161 foreach ( $request_ids as $request_id ) { |
|
1162 $resend = _wp_privacy_resend_request( $request_id ); |
|
1163 |
|
1164 if ( $resend && ! is_wp_error( $resend ) ) { |
|
1165 $count++; |
|
1166 } |
|
1167 } |
|
1168 |
|
1169 add_settings_error( |
|
1170 'bulk_action', |
|
1171 'bulk_action', |
|
1172 /* translators: %d: number of requests */ |
|
1173 sprintf( _n( 'Re-sent %d request', 'Re-sent %d requests', $count ), $count ), |
|
1174 'updated' |
|
1175 ); |
|
1176 break; |
|
1177 } |
|
1178 } |
|
1179 |
|
1180 /** |
|
1181 * Prepare items to output. |
|
1182 * |
|
1183 * @since 4.9.6 |
|
1184 */ |
|
1185 public function prepare_items() { |
|
1186 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 |
|
1196 $this->items = array(); |
|
1197 $posts_per_page = $this->get_items_per_page( $this->request_type . '_requests_per_page' ); |
|
1198 $args = array( |
|
1199 'post_type' => $this->post_type, |
|
1200 'post_name__in' => array( $this->request_type ), |
|
1201 'posts_per_page' => $posts_per_page, |
|
1202 'offset' => isset( $_REQUEST['paged'] ) ? max( 0, absint( $_REQUEST['paged'] ) - 1 ) * $posts_per_page : 0, |
|
1203 'post_status' => 'any', |
|
1204 's' => isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : '', |
|
1205 ); |
|
1206 |
|
1207 if ( ! empty( $_REQUEST['filter-status'] ) ) { |
|
1208 $filter_status = isset( $_REQUEST['filter-status'] ) ? sanitize_text_field( $_REQUEST['filter-status'] ) : ''; |
|
1209 $args['post_status'] = $filter_status; |
|
1210 } |
|
1211 |
|
1212 $requests_query = new WP_Query( $args ); |
|
1213 $requests = $requests_query->posts; |
|
1214 |
|
1215 foreach ( $requests as $request ) { |
|
1216 $this->items[] = wp_get_user_request_data( $request->ID ); |
|
1217 } |
|
1218 |
|
1219 $this->items = array_filter( $this->items ); |
|
1220 |
|
1221 $this->set_pagination_args( |
|
1222 array( |
|
1223 'total_items' => $requests_query->found_posts, |
|
1224 'per_page' => $posts_per_page, |
|
1225 ) |
|
1226 ); |
|
1227 } |
|
1228 |
|
1229 /** |
|
1230 * Checkbox column. |
|
1231 * |
|
1232 * @since 4.9.6 |
|
1233 * |
|
1234 * @param WP_User_Request $item Item being shown. |
|
1235 * @return string Checkbox column markup. |
|
1236 */ |
|
1237 public function column_cb( $item ) { |
|
1238 return sprintf( '<input type="checkbox" name="request_id[]" value="%1$s" /><span class="spinner"></span>', esc_attr( $item->ID ) ); |
|
1239 } |
|
1240 |
|
1241 /** |
|
1242 * Status column. |
|
1243 * |
|
1244 * @since 4.9.6 |
|
1245 * |
|
1246 * @param WP_User_Request $item Item being shown. |
|
1247 * @return string Status column markup. |
|
1248 */ |
|
1249 public function column_status( $item ) { |
|
1250 $status = get_post_status( $item->ID ); |
|
1251 $status_object = get_post_status_object( $status ); |
|
1252 |
|
1253 if ( ! $status_object || empty( $status_object->label ) ) { |
|
1254 return '-'; |
|
1255 } |
|
1256 |
|
1257 $timestamp = false; |
|
1258 |
|
1259 switch ( $status ) { |
|
1260 case 'request-confirmed': |
|
1261 $timestamp = $item->confirmed_timestamp; |
|
1262 break; |
|
1263 case 'request-completed': |
|
1264 $timestamp = $item->completed_timestamp; |
|
1265 break; |
|
1266 } |
|
1267 |
|
1268 echo '<span class="status-label status-' . esc_attr( $status ) . '">'; |
|
1269 echo esc_html( $status_object->label ); |
|
1270 |
|
1271 if ( $timestamp ) { |
|
1272 echo ' (' . $this->get_timestamp_as_date( $timestamp ) . ')'; |
|
1273 } |
|
1274 |
|
1275 echo '</span>'; |
|
1276 } |
|
1277 |
|
1278 /** |
|
1279 * Convert timestamp for display. |
|
1280 * |
|
1281 * @since 4.9.6 |
|
1282 * |
|
1283 * @param int $timestamp Event timestamp. |
|
1284 * @return string Human readable date. |
|
1285 */ |
|
1286 protected function get_timestamp_as_date( $timestamp ) { |
|
1287 if ( empty( $timestamp ) ) { |
|
1288 return ''; |
|
1289 } |
|
1290 |
|
1291 $time_diff = current_time( 'timestamp', true ) - $timestamp; |
|
1292 |
|
1293 if ( $time_diff >= 0 && $time_diff < DAY_IN_SECONDS ) { |
|
1294 /* translators: human readable timestamp */ |
|
1295 return sprintf( __( '%s ago' ), human_time_diff( $timestamp ) ); |
|
1296 } |
|
1297 |
|
1298 return date_i18n( get_option( 'date_format' ), $timestamp ); |
|
1299 } |
|
1300 |
|
1301 /** |
|
1302 * Default column handler. |
|
1303 * |
|
1304 * @since 4.9.6 |
|
1305 * |
|
1306 * @param WP_User_Request $item Item being shown. |
|
1307 * @param string $column_name Name of column being shown. |
|
1308 * @return string Default column output. |
|
1309 */ |
|
1310 public function column_default( $item, $column_name ) { |
|
1311 $cell_value = $item->$column_name; |
|
1312 |
|
1313 if ( in_array( $column_name, array( 'created_timestamp' ), true ) ) { |
|
1314 return $this->get_timestamp_as_date( $cell_value ); |
|
1315 } |
|
1316 |
|
1317 return $cell_value; |
|
1318 } |
|
1319 |
|
1320 /** |
|
1321 * Actions column. Overridden by children. |
|
1322 * |
|
1323 * @since 4.9.6 |
|
1324 * |
|
1325 * @param WP_User_Request $item Item being shown. |
|
1326 * @return string Email column markup. |
|
1327 */ |
|
1328 public function column_email( $item ) { |
|
1329 return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( array() ) ); |
|
1330 } |
|
1331 |
|
1332 /** |
|
1333 * Next steps column. Overridden by children. |
|
1334 * |
|
1335 * @since 4.9.6 |
|
1336 * |
|
1337 * @param WP_User_Request $item Item being shown. |
|
1338 */ |
|
1339 public function column_next_steps( $item ) {} |
|
1340 |
|
1341 /** |
|
1342 * Generates content for a single row of the table, |
|
1343 * |
|
1344 * @since 4.9.6 |
|
1345 * |
|
1346 * @param WP_User_Request $item The current item. |
|
1347 */ |
|
1348 public function single_row( $item ) { |
|
1349 $status = $item->status; |
|
1350 |
|
1351 echo '<tr id="request-' . esc_attr( $item->ID ) . '" class="status-' . esc_attr( $status ) . '">'; |
|
1352 $this->single_row_columns( $item ); |
|
1353 echo '</tr>'; |
|
1354 } |
|
1355 |
|
1356 /** |
|
1357 * Embed scripts used to perform actions. Overridden by children. |
|
1358 * |
|
1359 * @since 4.9.6 |
|
1360 */ |
|
1361 public function embed_scripts() {} |
|
1362 } |
|
1363 |
|
1364 /** |
|
1365 * WP_Privacy_Data_Export_Requests_Table class. |
|
1366 * |
|
1367 * @since 4.9.6 |
|
1368 */ |
|
1369 class WP_Privacy_Data_Export_Requests_Table extends WP_Privacy_Requests_Table { |
|
1370 /** |
|
1371 * Action name for the requests this table will work with. |
|
1372 * |
|
1373 * @since 4.9.6 |
|
1374 * |
|
1375 * @var string $request_type Name of action. |
|
1376 */ |
|
1377 protected $request_type = 'export_personal_data'; |
|
1378 |
|
1379 /** |
|
1380 * Post type for the requests. |
|
1381 * |
|
1382 * @since 4.9.6 |
|
1383 * |
|
1384 * @var string $post_type The post type. |
|
1385 */ |
|
1386 protected $post_type = 'user_request'; |
|
1387 |
|
1388 /** |
|
1389 * Actions column. |
|
1390 * |
|
1391 * @since 4.9.6 |
|
1392 * |
|
1393 * @param WP_User_Request $item Item being shown. |
|
1394 * @return string Email column markup. |
|
1395 */ |
|
1396 public function column_email( $item ) { |
|
1397 /** This filter is documented in wp-admin/includes/ajax-actions.php */ |
|
1398 $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() ); |
|
1399 $exporters_count = count( $exporters ); |
|
1400 $request_id = $item->ID; |
|
1401 $nonce = wp_create_nonce( 'wp-privacy-export-personal-data-' . $request_id ); |
|
1402 |
|
1403 $download_data_markup = '<div class="export-personal-data" ' . |
|
1404 'data-exporters-count="' . esc_attr( $exporters_count ) . '" ' . |
|
1405 'data-request-id="' . esc_attr( $request_id ) . '" ' . |
|
1406 'data-nonce="' . esc_attr( $nonce ) . |
|
1407 '">'; |
|
1408 |
|
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>' . |
|
1410 '<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>' . |
|
1412 '<span style="display:none" class="export-personal-data-failed">' . __( 'Download has failed.' ) . ' <button type="button" class="button-link">' . __( 'Retry' ) . '</button></span>'; |
|
1413 |
|
1414 $download_data_markup .= '</div>'; |
|
1415 |
|
1416 $row_actions = array( |
|
1417 'download-data' => $download_data_markup, |
|
1418 ); |
|
1419 |
|
1420 return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( $row_actions ) ); |
|
1421 } |
|
1422 |
|
1423 /** |
|
1424 * Displays the next steps column. |
|
1425 * |
|
1426 * @since 4.9.6 |
|
1427 * |
|
1428 * @param WP_User_Request $item Item being shown. |
|
1429 */ |
|
1430 public function column_next_steps( $item ) { |
|
1431 $status = $item->status; |
|
1432 |
|
1433 switch ( $status ) { |
|
1434 case 'request-pending': |
|
1435 esc_html_e( 'Waiting for confirmation' ); |
|
1436 break; |
|
1437 case 'request-confirmed': |
|
1438 /** This filter is documented in wp-admin/includes/ajax-actions.php */ |
|
1439 $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() ); |
|
1440 $exporters_count = count( $exporters ); |
|
1441 $request_id = $item->ID; |
|
1442 $nonce = wp_create_nonce( 'wp-privacy-export-personal-data-' . $request_id ); |
|
1443 |
|
1444 echo '<div class="export-personal-data" ' . |
|
1445 'data-send-as-email="1" ' . |
|
1446 'data-exporters-count="' . esc_attr( $exporters_count ) . '" ' . |
|
1447 'data-request-id="' . esc_attr( $request_id ) . '" ' . |
|
1448 'data-nonce="' . esc_attr( $nonce ) . |
|
1449 '">'; |
|
1450 |
|
1451 ?> |
|
1452 <span class="export-personal-data-idle"><button type="button" class="button export-personal-data-handle"><?php _e( 'Email Data' ); ?></button></span> |
|
1453 <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> |
|
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> |
|
1456 <?php |
|
1457 |
|
1458 echo '</div>'; |
|
1459 break; |
|
1460 case 'request-failed': |
|
1461 submit_button( __( 'Retry' ), 'secondary', 'privacy_action_email_retry[' . $item->ID . ']', false ); |
|
1462 break; |
|
1463 case 'request-completed': |
|
1464 echo '<a href="' . esc_url( wp_nonce_url( add_query_arg( array( |
|
1465 'action' => 'delete', |
|
1466 'request_id' => array( $item->ID ), |
|
1467 ), admin_url( 'tools.php?page=export_personal_data' ) ), 'bulk-privacy_requests' ) ) . '" class="button">' . esc_html__( 'Remove request' ) . '</a>'; |
|
1468 break; |
|
1469 } |
|
1470 } |
|
1471 } |
|
1472 |
|
1473 /** |
|
1474 * WP_Privacy_Data_Removal_Requests_Table class. |
|
1475 * |
|
1476 * @since 4.9.6 |
|
1477 */ |
|
1478 class WP_Privacy_Data_Removal_Requests_Table extends WP_Privacy_Requests_Table { |
|
1479 /** |
|
1480 * Action name for the requests this table will work with. |
|
1481 * |
|
1482 * @since 4.9.6 |
|
1483 * |
|
1484 * @var string $request_type Name of action. |
|
1485 */ |
|
1486 protected $request_type = 'remove_personal_data'; |
|
1487 |
|
1488 /** |
|
1489 * Post type for the requests. |
|
1490 * |
|
1491 * @since 4.9.6 |
|
1492 * |
|
1493 * @var string $post_type The post type. |
|
1494 */ |
|
1495 protected $post_type = 'user_request'; |
|
1496 |
|
1497 /** |
|
1498 * Actions column. |
|
1499 * |
|
1500 * @since 4.9.6 |
|
1501 * |
|
1502 * @param WP_User_Request $item Item being shown. |
|
1503 * @return string Email column markup. |
|
1504 */ |
|
1505 public function column_email( $item ) { |
|
1506 $row_actions = array(); |
|
1507 |
|
1508 // Allow the administrator to "force remove" the personal data even if confirmation has not yet been received. |
|
1509 $status = $item->status; |
|
1510 if ( 'request-confirmed' !== $status ) { |
|
1511 /** This filter is documented in wp-admin/includes/ajax-actions.php */ |
|
1512 $erasers = apply_filters( 'wp_privacy_personal_data_erasers', array() ); |
|
1513 $erasers_count = count( $erasers ); |
|
1514 $request_id = $item->ID; |
|
1515 $nonce = wp_create_nonce( 'wp-privacy-erase-personal-data-' . $request_id ); |
|
1516 |
|
1517 $remove_data_markup = '<div class="remove-personal-data force-remove-personal-data" ' . |
|
1518 'data-erasers-count="' . esc_attr( $erasers_count ) . '" ' . |
|
1519 'data-request-id="' . esc_attr( $request_id ) . '" ' . |
|
1520 'data-nonce="' . esc_attr( $nonce ) . |
|
1521 '">'; |
|
1522 |
|
1523 $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>' . |
|
1524 '<span style="display:none" class="remove-personal-data-processing" >' . __( 'Erasing Data...' ) . '</span>' . |
|
1525 '<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>'; |
|
1526 |
|
1527 $remove_data_markup .= '</div>'; |
|
1528 |
|
1529 $row_actions = array( |
|
1530 'remove-data' => $remove_data_markup, |
|
1531 ); |
|
1532 } |
|
1533 |
|
1534 return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( $row_actions ) ); |
|
1535 } |
|
1536 |
|
1537 /** |
|
1538 * Next steps column. |
|
1539 * |
|
1540 * @since 4.9.6 |
|
1541 * |
|
1542 * @param WP_User_Request $item Item being shown. |
|
1543 */ |
|
1544 public function column_next_steps( $item ) { |
|
1545 $status = $item->status; |
|
1546 |
|
1547 switch ( $status ) { |
|
1548 case 'request-pending': |
|
1549 esc_html_e( 'Waiting for confirmation' ); |
|
1550 break; |
|
1551 case 'request-confirmed': |
|
1552 /** This filter is documented in wp-admin/includes/ajax-actions.php */ |
|
1553 $erasers = apply_filters( 'wp_privacy_personal_data_erasers', array() ); |
|
1554 $erasers_count = count( $erasers ); |
|
1555 $request_id = $item->ID; |
|
1556 $nonce = wp_create_nonce( 'wp-privacy-erase-personal-data-' . $request_id ); |
|
1557 |
|
1558 echo '<div class="remove-personal-data" ' . |
|
1559 'data-force-erase="1" ' . |
|
1560 'data-erasers-count="' . esc_attr( $erasers_count ) . '" ' . |
|
1561 'data-request-id="' . esc_attr( $request_id ) . '" ' . |
|
1562 'data-nonce="' . esc_attr( $nonce ) . |
|
1563 '">'; |
|
1564 |
|
1565 ?> |
|
1566 <span class="remove-personal-data-idle"><button type="button" class="button remove-personal-data-handle"><?php _e( 'Erase Personal Data' ); ?></button></span> |
|
1567 <span style="display:none" class="remove-personal-data-processing button updating-message" ><?php _e( 'Erasing Data...' ); ?></span> |
|
1568 <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> |
|
1569 <?php |
|
1570 |
|
1571 echo '</div>'; |
|
1572 |
|
1573 break; |
|
1574 case 'request-failed': |
|
1575 submit_button( __( 'Retry' ), 'secondary', 'privacy_action_email_retry[' . $item->ID . ']', false ); |
|
1576 break; |
|
1577 case 'request-completed': |
|
1578 echo '<a href="' . esc_url( wp_nonce_url( add_query_arg( array( |
|
1579 'action' => 'delete', |
|
1580 'request_id' => array( $item->ID ), |
|
1581 ), admin_url( 'tools.php?page=remove_personal_data' ) ), 'bulk-privacy_requests' ) ) . '" class="button">' . esc_html__( 'Remove request' ) . '</a>'; |
|
1582 break; |
|
1583 } |
|
1584 } |
|
1585 |
|
1586 } |