Make WordPress Core


Ignore:
Timestamp:
05/01/2018 11:41:37 PM (8 years ago)
Author:
SergeyBiryukov
Message:

Privacy: add new wp-admin screens for exporting and removing of personal data.

Props melchoyce, mikejolley, allendav, xkon.
Merges [42967] to the 4.9 branch.
See #43481.

Location:
branches/4.9
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/4.9

  • branches/4.9/src/wp-admin/includes/user.php

    r41686 r43071  
    539539%%s' ), wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ), home_url(), wp_specialchars_decode( translate_user_role( $role['name'] ) ) );
    540540}
     541
     542/**
     543 * Get action description from the name.
     544 *
     545 * @since 5.0.0
     546 * @access private
     547 *
     548 * @return string
     549 */
     550function _wp_privacy_action_description( $request_type ) {
     551        switch ( $request_type ) {
     552                case 'user_export_request':
     553                        return __( 'Export Personal Data' );
     554                case 'user_remove_request':
     555                        return __( 'Remove Personal Data' );
     556        }
     557}
     558
     559/**
     560 * Log a request and send to the user.
     561 *
     562 * @since 5.0.0
     563 * @access private
     564 *
     565 * @param string $email_address Email address sending the request to.
     566 * @param string $action Action being requested.
     567 * @param string $description Description of request.
     568 * @return bool|WP_Error depending on success.
     569 */
     570function _wp_privacy_create_request( $email_address, $action, $description ) {
     571        $user_id = 0;
     572        $user    = get_user_by( 'email', $email_address );
     573
     574        if ( $user ) {
     575                $user_id = $user->ID;
     576        }
     577
     578        $privacy_request_id = wp_insert_post( array(
     579                'post_author'   => $user_id,
     580                'post_status'   => 'request-pending',
     581                'post_type'     => $action,
     582                'post_date'     => current_time( 'mysql', false ),
     583                'post_date_gmt' => current_time( 'mysql', true ),
     584        ), true );
     585
     586        if ( is_wp_error( $privacy_request_id ) ) {
     587                return $privacy_request_id;
     588        }
     589
     590        update_post_meta( $privacy_request_id, '_user_email', $email_address );
     591        update_post_meta( $privacy_request_id, '_action_name', $action );
     592        update_post_meta( $privacy_request_id, '_confirmed_timestamp', false );
     593
     594        return wp_send_account_verification_key( $email_address, $action, $description, array(
     595                'privacy_request_id' => $privacy_request_id,
     596        ) );
     597}
     598
     599/**
     600 * Resend an existing request and return the result.
     601 *
     602 * @since 5.0.0
     603 * @access private
     604 *
     605 * @param int $privacy_request_id Request ID.
     606 * @return bool|WP_Error
     607 */
     608function _wp_privacy_resend_request( $privacy_request_id ) {
     609        $privacy_request_id = absint( $privacy_request_id );
     610        $privacy_request    = get_post( $privacy_request_id );
     611
     612        if ( ! $privacy_request || ! in_array( $privacy_request->post_type, _wp_privacy_action_request_types(), true ) ) {
     613                return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) );
     614        }
     615
     616        $email_address = get_post_meta( $privacy_request_id, '_user_email', true );
     617        $action        = get_post_meta( $privacy_request_id, '_action_name', true );
     618        $description   = _wp_privacy_action_description( $action );
     619        $result        = wp_send_account_verification_key( $email_address, $action, $description, array(
     620                'privacy_request_id' => $privacy_request_id,
     621        ) );
     622
     623        if ( is_wp_error( $result ) ) {
     624                return $result;
     625        } elseif ( ! $result ) {
     626                return new WP_Error( 'privacy_request_error', __( 'Unable to initiate confirmation request.' ) );
     627        }
     628
     629        wp_update_post( array(
     630                'ID'            => $privacy_request_id,
     631                'post_status'   => 'request-pending',
     632                'post_date'     => current_time( 'mysql', false ),
     633                'post_date_gmt' => current_time( 'mysql', true ),
     634        ) );
     635
     636        return true;
     637}
     638
     639/**
     640 * Marks a request as completed by the admin and logs the datetime.
     641 *
     642 * @since 5.0.0
     643 * @access private
     644 *
     645 * @param int $privacy_request_id Request ID.
     646 * @return bool|WP_Error
     647 */
     648function _wp_privacy_completed_request( $privacy_request_id ) {
     649        $privacy_request_id = absint( $privacy_request_id );
     650        $privacy_request    = get_post( $privacy_request_id );
     651
     652        if ( ! $privacy_request || ! in_array( $privacy_request->post_type, _wp_privacy_action_request_types(), true ) ) {
     653                return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) );
     654        }
     655
     656        wp_update_post( array(
     657                'ID'          => $privacy_request_id,
     658                'post_status' => 'request-completed',
     659        ) );
     660
     661        update_post_meta( $privacy_request_id, '_completed_timestamp', time() );
     662}
     663
     664/**
     665 * Handle list table actions.
     666 *
     667 * @since 5.0.0
     668 * @access private
     669 */
     670function _wp_personal_data_handle_actions() {
     671        if ( isset( $_POST['export_personal_data_email_retry'] ) ) { // WPCS: input var ok.
     672                check_admin_referer( 'bulk-privacy_requests' );
     673
     674                $request_id = absint( current( array_keys( (array) wp_unslash( $_POST['export_personal_data_email_retry'] ) ) ) ); // WPCS: input var ok, sanitization ok.
     675                $result     = _wp_privacy_resend_request( $request_id );
     676
     677                if ( is_wp_error( $result ) ) {
     678                        add_settings_error(
     679                                'export_personal_data_email_retry',
     680                                'export_personal_data_email_retry',
     681                                $result->get_error_message(),
     682                                'error'
     683                        );
     684                } else {
     685                        add_settings_error(
     686                                'export_personal_data_email_retry',
     687                                'export_personal_data_email_retry',
     688                                __( 'Confirmation request re-resent successfully.' ),
     689                                'updated'
     690                        );
     691                }
     692
     693        } elseif ( isset( $_POST['export_personal_data_email_send'] ) ) { // WPCS: input var ok.
     694                check_admin_referer( 'bulk-privacy_requests' );
     695
     696                $request_id = absint( current( array_keys( (array) wp_unslash( $_POST['export_personal_data_email_send'] ) ) ) ); // WPCS: input var ok, sanitization ok.
     697                $result     = false;
     698
     699                /**
     700                 * TODO: Email the data to the user here.
     701                 */
     702
     703                if ( is_wp_error( $result ) ) {
     704                        add_settings_error(
     705                                'export_personal_data_email_send',
     706                                'export_personal_data_email_send',
     707                                $result->get_error_message(),
     708                                'error'
     709                        );
     710                } else {
     711                        _wp_privacy_completed_request( $request_id );
     712                        add_settings_error(
     713                                'export_personal_data_email_send',
     714                                'export_personal_data_email_send',
     715                                __( 'Personal data was sent to the user successfully.' ),
     716                                'updated'
     717                        );
     718                }
     719
     720        } elseif ( isset( $_POST['action'] ) ) {
     721                $action = isset( $_POST['action'] ) ? sanitize_key( wp_unslash( $_POST['action'] ) ) : ''; // WPCS: input var ok, CSRF ok.
     722
     723                switch ( $action ) {
     724                        case 'add_export_personal_data_request':
     725                        case 'add_remove_personal_data_request':
     726                                check_admin_referer( 'personal-data-request' );
     727
     728                                if ( ! isset( $_POST['type_of_action'], $_POST['username_or_email_to_export'] ) ) { // WPCS: input var ok.
     729                                        add_settings_error(
     730                                                'action_type',
     731                                                'action_type',
     732                                                __( 'Invalid action.' ),
     733                                                'error'
     734                                        );
     735                                }
     736                                $action_type               = sanitize_text_field( wp_unslash( $_POST['type_of_action'] ) ); // WPCS: input var ok.
     737                                $username_or_email_address = sanitize_text_field( wp_unslash( $_POST['username_or_email_to_export'] ) ); // WPCS: input var ok.
     738                                $email_address             = '';
     739
     740                                if ( ! in_array( $action_type, _wp_privacy_action_request_types(), true ) ) {
     741                                        add_settings_error(
     742                                                'action_type',
     743                                                'action_type',
     744                                                __( 'Invalid action.' ),
     745                                                'error'
     746                                        );
     747                                }
     748
     749                                if ( ! is_email( $username_or_email_address ) ) {
     750                                        $user = get_user_by( 'login', $username_or_email_address );
     751                                        if ( ! $user instanceof WP_User ) {
     752                                                add_settings_error(
     753                                                        'username_or_email_to_export',
     754                                                        'username_or_email_to_export',
     755                                                        __( 'Unable to add export request. A valid email address or username must be supplied.' ),
     756                                                        'error'
     757                                                );
     758                                        } else {
     759                                                $email_address = $user->user_email;
     760                                        }
     761                                } else {
     762                                        $email_address = $username_or_email_address;
     763                                }
     764
     765                                if ( ! empty( $email_address ) ) {
     766                                        $result = _wp_privacy_create_request( $email_address, $action_type, _wp_privacy_action_description( $action_type ) );
     767
     768                                        if ( is_wp_error( $result ) ) {
     769                                                add_settings_error(
     770                                                        'username_or_email_to_export',
     771                                                        'username_or_email_to_export',
     772                                                        $result->get_error_message(),
     773                                                        'error'
     774                                                );
     775                                        } elseif ( ! $result ) {
     776                                                add_settings_error(
     777                                                        'username_or_email_to_export',
     778                                                        'username_or_email_to_export',
     779                                                        __( 'Unable to initiate confirmation request.' ),
     780                                                        'error'
     781                                                );
     782                                        } else {
     783                                                add_settings_error(
     784                                                        'username_or_email_to_export',
     785                                                        'username_or_email_to_export',
     786                                                        __( 'Confirmation request initiated successfully.' ),
     787                                                        'updated'
     788                                                );
     789                                        }
     790                                }
     791                                break;
     792                }
     793        }
     794}
     795
     796/**
     797 * Personal data export.
     798 *
     799 * @since 5.0.0
     800 * @access private
     801 */
     802function _wp_personal_data_export_page() {
     803        if ( ! current_user_can( 'manage_options' ) ) {
     804                wp_die( esc_html__( 'Sorry, you are not allowed to manage privacy on this site.' ) );
     805        }
     806
     807        _wp_personal_data_handle_actions();
     808
     809        $requests_table = new WP_Privacy_Data_Export_Requests_Table( array(
     810                'plural'   => 'privacy_requests',
     811                'singular' => 'privacy_request',
     812        ) );
     813        $requests_table->process_bulk_action();
     814        $requests_table->prepare_items();
     815        ?>
     816        <div class="wrap nosubsub">
     817                <h1><?php esc_html_e( 'Export Personal Data' ); ?></h1>
     818                <hr class="wp-header-end" />
     819
     820                <?php settings_errors(); ?>
     821
     822                <form method="post" class="wp-privacy-request-form">
     823                        <h2><?php esc_html_e( 'Add Data Export Request' ); ?></h2>
     824                        <p><?php esc_html_e( 'An email will be sent to the user at this email address asking them to verify the request.' ); ?></p>
     825
     826                        <div class="wp-privacy-request-form-field">
     827                                <label for="username_or_email_to_export"><?php esc_html_e( 'Username or email address' ); ?></label>
     828                                <input type="text" required class="regular-text" id="username_or_email_to_export" name="username_or_email_to_export" />
     829                                <?php submit_button( __( 'Send Request' ), 'secondary', 'submit', false ); ?>
     830                        </div>
     831                        <?php wp_nonce_field( 'personal-data-request' ); ?>
     832                        <input type="hidden" name="action" value="add_export_personal_data_request" />
     833                        <input type="hidden" name="type_of_action" value="user_export_request" />
     834                </form>
     835                <hr />
     836
     837                <?php $requests_table->views(); ?>
     838
     839                <form class="search-form wp-clearfix">
     840                        <?php $requests_table->search_box( __( 'Search Requests' ), 'requests' ); ?>
     841                        <input type="hidden" name="page" value="export_personal_data" />
     842                        <input type="hidden" name="filter-status" value="<?php echo isset( $_REQUEST['filter-status'] ) ? esc_attr( sanitize_text_field( $_REQUEST['filter-status'] ) ) : ''; ?>" />
     843                        <input type="hidden" name="orderby" value="<?php echo isset( $_REQUEST['orderby'] ) ? esc_attr( sanitize_text_field( $_REQUEST['orderby'] ) ) : ''; ?>" />
     844                        <input type="hidden" name="order" value="<?php echo isset( $_REQUEST['order'] ) ? esc_attr( sanitize_text_field( $_REQUEST['order'] ) ) : ''; ?>" />
     845                </form>
     846
     847                <form method="post">
     848                        <?php
     849                        $requests_table->display();
     850                        $requests_table->embed_scripts();
     851                        ?>
     852                </form>
     853        </div>
     854        <?php
     855}
     856
     857/**
     858 * Personal data anonymization.
     859 *
     860 * @since 5.0.0
     861 * @access private
     862 */
     863function _wp_personal_data_removal_page() {
     864        if ( ! current_user_can( 'manage_options' ) ) {
     865                wp_die( esc_html__( 'Sorry, you are not allowed to manage privacy on this site.' ) );
     866        }
     867
     868        _wp_personal_data_handle_actions();
     869
     870        $requests_table = new WP_Privacy_Data_Removal_Requests_Table( array(
     871                'plural'   => 'privacy_requests',
     872                'singular' => 'privacy_request',
     873        ) );
     874        $requests_table->process_bulk_action();
     875        $requests_table->prepare_items();
     876        ?>
     877        <div class="wrap nosubsub">
     878                <h1><?php esc_html_e( 'Remove Personal Data' ); ?></h1>
     879                <hr class="wp-header-end" />
     880
     881                <?php settings_errors(); ?>
     882
     883                <form method="post" class="wp-privacy-request-form">
     884                        <h2><?php esc_html_e( 'Add Data Removal Request' ); ?></h2>
     885                        <p><?php esc_html_e( 'An email will be sent to the user at this email address asking them to verify the request.' ); ?></p>
     886
     887                        <div class="wp-privacy-request-form-field">
     888                                <label for="username_or_email_to_export"><?php esc_html_e( 'Username or email address' ); ?></label>
     889                                <input type="text" required class="regular-text" id="username_or_email_to_export" name="username_or_email_to_export" />
     890                                <?php submit_button( __( 'Send Request' ), 'secondary', 'submit', false ); ?>
     891                        </div>
     892                        <?php wp_nonce_field( 'personal-data-request' ); ?>
     893                        <input type="hidden" name="action" value="add_remove_personal_data_request" />
     894                        <input type="hidden" name="type_of_action" value="user_remove_request" />
     895                </form>
     896                <hr />
     897
     898                <?php $requests_table->views(); ?>
     899
     900                <form class="search-form wp-clearfix">
     901                        <?php $requests_table->search_box( __( 'Search Requests' ), 'requests' ); ?>
     902                        <input type="hidden" name="page" value="export_personal_data" />
     903                        <input type="hidden" name="filter-status" value="<?php echo isset( $_REQUEST['filter-status'] ) ? esc_attr( sanitize_text_field( $_REQUEST['filter-status'] ) ) : ''; ?>" />
     904                        <input type="hidden" name="orderby" value="<?php echo isset( $_REQUEST['orderby'] ) ? esc_attr( sanitize_text_field( $_REQUEST['orderby'] ) ) : ''; ?>" />
     905                        <input type="hidden" name="order" value="<?php echo isset( $_REQUEST['order'] ) ? esc_attr( sanitize_text_field( $_REQUEST['order'] ) ) : ''; ?>" />
     906                </form>
     907
     908                <form method="post">
     909                        <?php
     910                        $requests_table->display();
     911                        $requests_table->embed_scripts();
     912                        ?>
     913                </form>
     914        </div>
     915        <?php
     916}
     917
     918/**
     919 * Add requests pages.
     920 *
     921 * @since 5.0.0
     922 * @access private
     923 */
     924function _wp_privacy_hook_requests_page() {
     925        add_submenu_page( 'tools.php', __( 'Export Personal Data' ), __( 'Export Personal Data' ), 'manage_options', 'export_personal_data', '_wp_personal_data_export_page' );
     926        add_submenu_page( 'tools.php', __( 'Remove Personal Data' ), __( 'Remove Personal Data' ), 'manage_options', 'remove_personal_data', '_wp_personal_data_removal_page' );
     927}
     928
     929// TODO: move the following classes in new files.
     930if ( ! class_exists( 'WP_List_Table' ) ) {
     931        require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
     932}
     933
     934/**
     935 * WP_Privacy_Requests_Table class.
     936 */
     937abstract class WP_Privacy_Requests_Table extends WP_List_Table {
     938
     939        /**
     940         * Action name for the requests this table will work with. Classes
     941         * which inherit from WP_Privacy_Requests_Table should define this.
     942         * e.g. 'user_export_request'
     943         *
     944         * @since 5.0.0
     945         *
     946         * @var string $request_type Name of action.
     947         */
     948        protected $request_type = 'INVALID';
     949
     950        /**
     951         * Get columns to show in the list table.
     952         *
     953         * @since 5.0.0
     954         *
     955         * @param array Array of columns.
     956         */
     957        public function get_columns() {
     958                $columns = array(
     959                        'cb'         => '<input type="checkbox" />',
     960                        'email'      => __( 'Requester' ),
     961                        'status'     => __( 'Status' ),
     962                        'requested'  => __( 'Requested' ),
     963                        'next_steps' => __( 'Next Steps' ),
     964                );
     965                return $columns;
     966        }
     967
     968        /**
     969         * Get a list of sortable columns.
     970         *
     971         * @since 5.0.0
     972         *
     973         * @return array
     974         */
     975        protected function get_sortable_columns() {
     976                return array();
     977        }
     978
     979        /**
     980         * Default primary column.
     981         *
     982         * @since 5.0.0
     983         *
     984         * @return string
     985         */
     986        protected function get_default_primary_column_name() {
     987                return 'email';
     988        }
     989
     990        /**
     991         * Get an associative array ( id => link ) with the list
     992         * of views available on this table.
     993         *
     994         * @since 5.0.0
     995         *
     996         * @return array
     997         */
     998        protected function get_views() {
     999                $current_status = isset( $_REQUEST['filter-status'] ) ? sanitize_text_field( $_REQUEST['filter-status'] ): '';
     1000                $statuses       = _wp_privacy_statuses();
     1001                $views          = array();
     1002                $admin_url      = admin_url( 'tools.php?page=' . $this->request_type );
     1003                $counts         = wp_count_posts( $this->request_type );
     1004
     1005                $current_link_attributes = empty( $current_status ) ? ' class="current" aria-current="page"' : '';
     1006                $views['all']            = '<a href="' . esc_url( $admin_url ) . "\" $current_link_attributes>" . esc_html__( 'All' ) . ' (' . absint( array_sum( (array) $counts ) ) . ')</a>';
     1007
     1008                foreach ( $statuses as $status => $label ) {
     1009                        $current_link_attributes = $status === $current_status ? ' class="current" aria-current="page"' : '';
     1010                        $views[ $status ]        = '<a href="' . esc_url( add_query_arg( 'filter-status', $status, $admin_url ) ) . "\" $current_link_attributes>" . esc_html( $label ) . ' (' . absint( $counts->$status ) . ')</a>';
     1011                }
     1012
     1013                return $views;
     1014        }
     1015
     1016        /**
     1017         * Get bulk actions.
     1018         *
     1019         * @since 5.0.0
     1020         *
     1021         * @return array
     1022         */
     1023        protected function get_bulk_actions() {
     1024                return array(
     1025                        'delete' => __( 'Remove' ),
     1026                        'resend' => __( 'Resend email' ),
     1027                );
     1028        }
     1029
     1030        /**
     1031         * Process bulk actions.
     1032         *
     1033         * @since 5.0.0
     1034         */
     1035        public function process_bulk_action() {
     1036                $action      = $this->current_action();
     1037                $request_ids = isset( $_REQUEST['request_id'] ) ? wp_parse_id_list( wp_unslash( $_REQUEST['request_id'] ) ) : array(); // WPCS: input var ok, CSRF ok.
     1038
     1039                if ( $request_ids ) {
     1040                        check_admin_referer( 'bulk-privacy_requests' );
     1041                }
     1042
     1043                switch ( $action ) {
     1044                        case 'delete':
     1045                                $count = 0;
     1046
     1047                                foreach ( $request_ids as $request_id ) {
     1048                                        if ( wp_delete_post( $request_id, true ) ) {
     1049                                                $count ++;
     1050                                        }
     1051                                }
     1052
     1053                                add_settings_error(
     1054                                        'bulk_action',
     1055                                        'bulk_action',
     1056                                        sprintf( _n( 'Deleted %d request', 'Deleted %d requests', $count ), $count ),
     1057                                        'updated'
     1058                                );
     1059                                break;
     1060                        case 'resend':
     1061                                $count = 0;
     1062
     1063                                foreach ( $request_ids as $request_id ) {
     1064                                        if ( _wp_privacy_resend_request( $request_id ) ) {
     1065                                                $count ++;
     1066                                        }
     1067                                }
     1068
     1069                                add_settings_error(
     1070                                        'bulk_action',
     1071                                        'bulk_action',
     1072                                        sprintf( _n( 'Re-sent %d request', 'Re-sent %d requests', $count ), $count ),
     1073                                        'updated'
     1074                                );
     1075                                break;
     1076                }
     1077        }
     1078
     1079        /**
     1080         * Prepare items to output.
     1081         *
     1082         * @since 5.0.0
     1083         */
     1084        public function prepare_items() {
     1085                global $wpdb;
     1086
     1087                $primary               = $this->get_primary_column_name();
     1088                $this->_column_headers = array(
     1089                        $this->get_columns(),
     1090                        array(),
     1091                        $this->get_sortable_columns(),
     1092                        $primary,
     1093                );
     1094
     1095                $this->items    = array();
     1096                $posts_per_page = 20;
     1097                $args           = array(
     1098                        'post_type'      => $this->request_type,
     1099                        'posts_per_page' => $posts_per_page,
     1100                        'offset'         => isset( $_REQUEST['paged'] ) ? max( 0, absint( $_REQUEST['paged'] ) - 1 ) * $posts_per_page: 0,
     1101                        'post_status'    => 'any',
     1102                );
     1103
     1104                if ( ! empty( $_REQUEST['filter-status'] ) ) {
     1105                        $filter_status       = isset( $_REQUEST['filter-status'] ) ? sanitize_text_field( $_REQUEST['filter-status'] ) : '';
     1106                        $args['post_status'] = $filter_status;
     1107                }
     1108
     1109                if ( ! empty( $_REQUEST['s'] ) ) {
     1110                        $args['meta_query'] = array(
     1111                                $name_query,
     1112                                'relation'  => 'AND',
     1113                                array(
     1114                                        'key'     => '_user_email',
     1115                                        'value'   => isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ): '',
     1116                                        'compare' => 'LIKE'
     1117                                ),
     1118                        );
     1119                }
     1120
     1121                $privacy_requests_query = new WP_Query( $args );
     1122                $privacy_requests       = $privacy_requests_query->posts;
     1123
     1124                foreach ( $privacy_requests as $privacy_request ) {
     1125                        $this->items[] = array(
     1126                                'request_id' => $privacy_request->ID,
     1127                                'user_id'    => $privacy_request->post_author,
     1128                                'email'      => get_post_meta( $privacy_request->ID, '_user_email', true ),
     1129                                'action'     => get_post_meta( $privacy_request->ID, '_action_name', true ),
     1130                                'requested'  => strtotime( $privacy_request->post_date_gmt ),
     1131                                'confirmed'  => get_post_meta( $privacy_request->ID, '_confirmed_timestamp', true ),
     1132                                'completed'  => get_post_meta( $privacy_request->ID, '_completed_timestamp', true ),
     1133                        );
     1134                }
     1135
     1136                $this->set_pagination_args(
     1137                        array(
     1138                                'total_items' => $privacy_requests_query->found_posts,
     1139                                'per_page'    => $posts_per_page,
     1140                        )
     1141                );
     1142        }
     1143
     1144        /**
     1145         * Checkbox column.
     1146         *
     1147         * @since 5.0.0
     1148         *
     1149         * @param array $item Item being shown.
     1150         * @return string
     1151         */
     1152        public function column_cb( $item ) {
     1153                return sprintf( '<input type="checkbox" name="request_id[]" value="%1$s" /><span class="spinner"></span>', esc_attr( $item['request_id'] ) );
     1154        }
     1155
     1156        /**
     1157         * Status column.
     1158         *
     1159         * @since 5.0.0
     1160         *
     1161         * @param array $item Item being shown.
     1162         * @return string
     1163         */
     1164        public function column_status( $item ) {
     1165                $status        = get_post_status( $item['request_id'] );
     1166                $status_object = get_post_status_object( $status );
     1167
     1168                if ( ! $status_object || empty( $status_object->label ) ) {
     1169                        return '-';
     1170                }
     1171
     1172                $timestamp = false;
     1173
     1174                switch ( $status ) {
     1175                        case 'request-confirmed':
     1176                                $timestamp = $item['confirmed'];
     1177                                break;
     1178                        case 'request-completed':
     1179                                $timestamp = $item['completed'];
     1180                                break;
     1181                }
     1182
     1183                echo '<span class="status-label status-' . esc_attr( $status ) . '">';
     1184                echo esc_html( $status_object->label );
     1185
     1186                if ( $timestamp ) {
     1187                        echo ' (' . $this->get_timestamp_as_date( $timestamp ) . ')';
     1188                }
     1189
     1190                echo '</span>';
     1191        }
     1192
     1193        /**
     1194         * Convert timestamp for display.
     1195         *
     1196         * @since 5.0.0
     1197         *
     1198         * @param int $timestamp Event timestamp.
     1199         * @return string
     1200         */
     1201        protected function get_timestamp_as_date( $timestamp ) {
     1202                if ( empty( $timestamp ) ) {
     1203                        return '';
     1204                }
     1205
     1206                $time_diff = current_time( 'timestamp', true ) - $timestamp;
     1207
     1208                if ( $time_diff >= 0 && $time_diff < DAY_IN_SECONDS ) {
     1209                        return sprintf( __( '%s ago' ), human_time_diff( $timestamp ) );
     1210                }
     1211
     1212                return date_i18n( get_option( 'date_format' ), $timestamp );
     1213        }
     1214
     1215        /**
     1216         * Default column handler.
     1217         *
     1218         * @since 5.0.0
     1219         *
     1220         * @param array $item         Item being shown.
     1221         * @param string $column_name Name of column being shown.
     1222         * @return string
     1223         */
     1224        public function column_default( $item, $column_name ) {
     1225                $cell_value = $item[ $column_name ];
     1226
     1227                if ( in_array( $column_name, array( 'requested' ), true ) ) {
     1228                        return $this->get_timestamp_as_date( $cell_value );
     1229                }
     1230
     1231                return $cell_value;
     1232        }
     1233
     1234        /**
     1235         * Actions column. Overriden by children.
     1236         *
     1237         * @since 5.0.0
     1238         *
     1239         * @param array $item Item being shown.
     1240         * @return string
     1241         */
     1242        public function column_email( $item ) {
     1243                return sprintf( '%1$s %2$s', $item['email'], $this->row_actions( array() ) );
     1244        }
     1245
     1246        /**
     1247         * Next steps column. Overriden by children.
     1248         *
     1249         * @since 5.0.0
     1250         *
     1251         * @param array $item Item being shown.
     1252         */
     1253        public function column_next_steps( $item ) {}
     1254
     1255        /**
     1256         * Generates content for a single row of the table
     1257         *
     1258         * @since 5.0.0
     1259         *
     1260         * @param object $item The current item
     1261         */
     1262        public function single_row( $item ) {
     1263                $status = get_post_status( $item['request_id'] );
     1264
     1265                echo '<tr class="status-' . esc_attr( $status ) . '">';
     1266                $this->single_row_columns( $item );
     1267                echo '</tr>';
     1268        }
     1269
     1270        /**
     1271         * Embed scripts used to perform actions. Overriden by children.
     1272         *
     1273         * @since 5.0.0
     1274         */
     1275        public function embed_scripts() {}
     1276}
     1277
     1278/**
     1279 * WP_Privacy_Data_Export_Requests_Table class.
     1280 *
     1281 * @since 5.0.0
     1282 */
     1283class WP_Privacy_Data_Export_Requests_Table extends WP_Privacy_Requests_Table {
     1284        /**
     1285         * Action name for the requests this table will work with. Classes
     1286         * which inherit from WP_Privacy_Requests_Table should define this.
     1287         * e.g. 'user_export_request'
     1288         *
     1289         * @since 5.0.0
     1290         *
     1291         * @var string $request_type Name of action.
     1292         */
     1293        protected $request_type = 'user_export_request';
     1294
     1295        /**
     1296         * Actions column.
     1297         *
     1298         * @since 5.0.0
     1299         *
     1300         * @param array $item Item being shown.
     1301         * @return string
     1302         */
     1303        public function column_email( $item ) {
     1304                $row_actions = array(
     1305                        'download_data' => __( 'Download Personal Data' ),
     1306                );
     1307
     1308                return sprintf( '%1$s %2$s', $item['email'], $this->row_actions( $row_actions ) );
     1309        }
     1310
     1311        /**
     1312         * Next steps column.
     1313         *
     1314         * @since 5.0.0
     1315         *
     1316         * @param array $item Item being shown.
     1317         */
     1318        public function column_next_steps( $item ) {
     1319                $status = get_post_status( $item['request_id'] );
     1320
     1321                switch ( $status ) {
     1322                        case 'request-pending':
     1323                                esc_html_e( 'Waiting for confirmation' );
     1324                                break;
     1325                        case 'request-confirmed':
     1326                                // TODO Complete in follow on patch.
     1327                                break;
     1328                        case 'request-failed':
     1329                                submit_button( __( 'Retry' ), 'secondary', 'export_personal_data_email_retry[' . $item['request_id'] . ']', false );
     1330                                break;
     1331                        case 'request-completed':
     1332                                echo '<a href="' . esc_url( wp_nonce_url( add_query_arg( array(
     1333                                        'action' => 'delete',
     1334                                        'request_id' => array( $item['request_id'] )
     1335                                ), admin_url( 'tools.php?page=export_personal_data' ) ), 'bulk-privacy_requests' ) ) . '">' . esc_html__( 'Remove request' ) . '</a>';
     1336                                break;
     1337                }
     1338        }
     1339}
     1340
     1341/**
     1342 * WP_Privacy_Data_Removal_Requests_Table class.
     1343 *
     1344         * @since 5.0.0
     1345 */
     1346class WP_Privacy_Data_Removal_Requests_Table extends WP_Privacy_Requests_Table {
     1347        /**
     1348         * Action name for the requests this table will work with. Classes
     1349         * which inherit from WP_Privacy_Requests_Table should define this.
     1350         * e.g. 'user_remove_request'
     1351         *
     1352         * @since 5.0.0
     1353         *
     1354         * @var string $request_type Name of action.
     1355         */
     1356        protected $request_type = 'user_remove_request';
     1357
     1358        /**
     1359         * Actions column.
     1360         *
     1361         * @since 5.0.0
     1362         *
     1363         * @param array $item Item being shown.
     1364         * @return string
     1365         */
     1366        public function column_email( $item ) {
     1367                $row_actions = array(
     1368                        // TODO Complete in follow on patch.
     1369                        'remove_data' => __( 'Remove Personal Data' ),
     1370                );
     1371
     1372                // If we have a user ID, include a delete user action.
     1373                if ( ! empty( $item['user_id'] ) ) {
     1374                        // TODO Complete in follow on patch.
     1375                        $row_actions['delete_user'] = __( 'Delete User' );
     1376                }
     1377
     1378                return sprintf( '%1$s %2$s', $item['email'], $this->row_actions( $row_actions ) );
     1379        }
     1380
     1381        /**
     1382         * Next steps column.
     1383         *
     1384         * @since 5.0.0
     1385         *
     1386         * @param array $item Item being shown.
     1387         */
     1388        public function column_next_steps( $item ) {
     1389        }
     1390
     1391}
Note: See TracChangeset for help on using the changeset viewer.