Make WordPress Core

Ticket #43438: 43438.2.diff

File 43438.2.diff, 17.8 KB (added by allendav, 7 years ago)

Updated patch to target privacy.php page instead

  • src/wp-admin/admin-ajax.php

     
    129129        'get-post-thumbnail-html',
    130130        'get-community-events',
    131131        'edit-theme-plugin-file',
     132        'wp-privacy-export-personal-data',
    132133);
    133134
    134135// Deprecated
  • src/wp-admin/includes/ajax-actions.php

     
    43264326                );
    43274327        }
    43284328}
     4329
     4330function wp_ajax_wp_privacy_export_personal_data() {
     4331        $email_address = $_POST['email'];
     4332        $exporter_index = $_POST['exporter'];
     4333        $page = $_POST['page'];
     4334
     4335        $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() );
     4336
     4337        if ( ! is_email( $email_address ) ) {
     4338                wp_send_json_error( 'a valid email address must be given' );
     4339        }
     4340
     4341        if ( $exporter_index < 0 ) {
     4342                wp_send_json_error( 'exporter index cannot be negative' );
     4343        }
     4344
     4345        if ( $exporter_index > count( $exporters ) - 1 ) {
     4346                wp_send_json_error( 'exporter index out of range' );
     4347        }
     4348
     4349        if ( $page < 0 ) {
     4350                wp_send_json_error( 'page index cannot be negative' );
     4351        }
     4352
     4353        $response = call_user_func( $exporters[ $exporter_index ]['callback'], $email_address, $page );
     4354
     4355        wp_send_json_success( $response );
     4356}
  • src/wp-admin/privacy.php

     
    1616// "Borrow" xfn.js for now so we don't have to create new files.
    1717// wp_enqueue_script( 'xfn' );
    1818
     19$title = __( 'Privacy Tools' );
     20
    1921$action = isset( $_POST['action'] ) ? $_POST['action'] : '';
    2022
     23$doing_personal_data_export_for_email = '';
     24
    2125if ( ! empty( $action ) ) {
    2226        check_admin_referer( $action );
    2327
     
    2428        if ( 'set-privacy-page' === $action ) {
    2529                $privacy_policy_page_id = isset( $_POST['page_for_privacy_policy'] ) ? (int) $_POST['page_for_privacy_policy'] : 0;
    2630                update_option( 'wp_page_for_privacy_policy', $privacy_policy_page_id );
    27 
    2831                add_settings_error(
    2932                        'page_for_privacy_policy',
    3033                        'page_for_privacy_policy',
     
    5760                                'updated'
    5861                        );
    5962                }
     63        } elseif ( 'export-personal-data' === $action ) {
     64                $username_or_email_address = isset( $_POST['username_or_email_to_export'] ) ? $_POST['username_or_email_to_export'] : '';
     65                $username_or_email_address = sanitize_text_field( $username_or_email_address );
     66
     67                if ( ! is_email( $username_or_email_address ) ) {
     68                        $user = get_user_by( 'login', $username_or_email_address );
     69                        if ( ! $user instanceof WP_User ) {
     70                                add_settings_error(
     71                                        'username_or_email_to_export',
     72                                        'username_or_email_to_export',
     73                                        __( 'Unable to export personal data. Username not recognized.' ),
     74                                        'error'
     75                                );
     76                        } else {
     77                                $doing_personal_data_export_for_email = $user->user_email;
     78                        }
     79                } else {
     80                        $doing_personal_data_export_for_email = $username_or_email_address;
     81                }
     82
     83                if ( ! empty( $doing_personal_data_export_for_email ) ) {
     84                        $title = __( 'Export Personal Data' );
     85                }
    6086        }
    6187}
    6288
    63 // If a privacy policy page ID is available, make sure the page actually exists. If not, display a warning
    64 $privacy_policy_page_exists = false;
    65 $privacy_policy_page_id = (int) get_option( 'wp_page_for_privacy_policy' );
     89if ( empty( $doing_personal_data_export_for_email ) ) {
     90        // If a privacy policy page ID is available, make sure the page actually exists. If not, display a warning
     91        $privacy_policy_page_exists = false;
     92        $privacy_policy_page_id = (int) get_option( 'wp_page_for_privacy_policy' );
    6693
    67 if ( ! empty( $privacy_policy_page_id ) ) {
    68                 $privacy_policy_page = get_post( $privacy_policy_page_id );
    69                 if ( ! $privacy_policy_page instanceof WP_Post ) {
    70                         add_settings_error(
    71                                 'page_for_privacy_policy',
    72                                 'page_for_privacy_policy',
    73                                 __( 'The currently selected privacy policy page does not exist. Please create or select new page.' ),
    74                                 'warning'
    75                         );
    76                 } else {
    77                         if ( 'trash' === $privacy_policy_page->post_status ) {
     94        if ( ! empty( $privacy_policy_page_id ) ) {
     95                        $privacy_policy_page = get_post( $privacy_policy_page_id );
     96                        if ( ! $privacy_policy_page instanceof WP_Post ) {
    7897                                add_settings_error(
    7998                                        'page_for_privacy_policy',
    8099                                        'page_for_privacy_policy',
    81                                         sprintf(
    82                                                 __( 'The currently selected privacy policy page is in the trash. Please create or select new privacy policy page or <a href="%s">restore the current page</a>.' ),
    83                                                 'edit.php?post_status=trash&post_type=page'
    84                                         ),
    85                                         'error'
     100                                        __( 'The currently selected privacy policy page does not exist. Please create or select new page.' ),
     101                                        'warning'
    86102                                );
    87103                        } else {
    88                                 $privacy_policy_page_exists = true;
     104                                if ( 'trash' === $privacy_policy_page->post_status ) {
     105                                        add_settings_error(
     106                                                'page_for_privacy_policy',
     107                                                'page_for_privacy_policy',
     108                                                sprintf(
     109                                                        __( 'The currently selected privacy policy page is in the trash. Please create or select new privacy policy page or <a href="%s">restore the current page</a>.' ),
     110                                                        'edit.php?post_status=trash&post_type=page'
     111                                                ),
     112                                                'error'
     113                                        );
     114                                } else {
     115                                        $privacy_policy_page_exists = true;
     116                                }
    89117                        }
    90                 }
    91 }
     118        }
    92119
    93 $title = __( 'Privacy Tools' );
     120        get_current_screen()->add_help_tab( array(
     121                'id'      => 'privacy',
     122                'title'   => __( 'Privacy' ),
     123                'content' => '<p>' . __( 'This page provides tools with which you can manage your user\'s personal data and site\'s privacy policy.' ) . '</p>',
     124        ) );
    94125
    95 get_current_screen()->add_help_tab( array(
    96         'id'      => 'privacy',
    97         'title'   => __( 'Privacy' ),
    98         'content' => '<p>' . __( 'This page provides tools with which you can manage your user\'s personal data and site\'s privacy policy.' ) . '</p>',
    99 ) );
     126        get_current_screen()->set_help_sidebar(
     127                '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
     128                '<p>' . __( '<a href="#">Documentation on privacy</a>' ) . '</p>'
     129        );
     130}
    100131
    101 get_current_screen()->set_help_sidebar(
    102         '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
    103         '<p>' . __( '<a href="#">Documentation on privacy</a>' ) . '</p>'
    104 );
    105 
    106132require_once( ABSPATH . 'wp-admin/admin-header.php' );
    107133
    108134?>
     
    109135<div class="wrap">
    110136        <h1><?php echo esc_html( $title ); ?></h1>
    111137        <?php settings_errors(); ?>
     138        <?php
    112139
    113         <h2 class="title"><?php _e( 'Privacy policy page' ); ?></h2>
    114         <table class="form-table">
     140        // If we have an email address, bootstrap the exporter
     141        if ( ! empty( $doing_personal_data_export_for_email ) ) {
     142                if ( $username_or_email_address === $doing_personal_data_export_for_email ) {
     143                        $heading = sprintf(
     144                                __( 'Exporting personal data for %s' ),
     145                                $doing_personal_data_export_for_email
     146                        );
     147                } else {
     148                        $heading = sprintf(
     149                                __( 'Exporting personal data for %1$s (%2$s)' ),
     150                                $doing_personal_data_export_for_email,
     151                                $username_or_email_address
     152                        );
     153                }
     154                ?>
     155                <p>
     156                        <?php echo esc_html( $heading ); ?>
     157                </p>
     158
     159                <div id="exporters-container">
     160                        <ul id="exporter-list">
     161                        </ul>
     162                        <table class="wp-list-table widefat striped" id="exported-data-table">
     163                                <tr>
     164                                        <th><?php _e( 'Name' ); ?></th>
     165                                        <th><?php _e( 'Value' ); ?></th>
     166                                </tr>
     167                        </table>
     168                </div>
     169
    115170                <?php
     171                // Build the array of exporters and emit it as an array accessible to javascript along with a nonce
     172                $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() );
    116173
    117                 if ( $privacy_policy_page_exists ) {
    118                         $edit_href = add_query_arg(
    119                                 array(
    120                                         'post'  => $privacy_policy_page_id,
    121                                         'action' => 'edit',
    122                                 ),
    123                                 admin_url( 'post.php' )
    124                         );
    125                         $view_href = get_permalink( $privacy_policy_page_id );
    126 
    127                         ?>
    128                         <tr>
    129                                 <th colspan="2">
    130                                         <?php
    131                                         printf(
    132                                                 __( '<a href="%1$s">Edit</a> or <a href="%2$s">view</a> your privacy policy.' ),
    133                                                 $edit_href,
    134                                                 $view_href
    135                                         );
    136                                         ?>
    137                                 </th>
    138                         </tr>
    139                         <?php
     174                $exporter_names = array();
     175                foreach ( ( array ) $exporters as $exporter ) {
     176                        $exporter_names[] = $exporter['exporter_friendly_name'];
    140177                }
    141178
    142179                ?>
    143                 <tr>
    144                         <th scope="row">
     180
     181                <!-- scripts for the exporter -->
     182
     183                <script>
     184                        ( function( $ ) {
     185                                $( document ).ready( function() {
     186                                        var exportForEmail = <?php echo json_encode( $doing_personal_data_export_for_email ); ?>;
     187                                        var exporterNames = <?php echo json_encode( $exporter_names ); ?>;
     188                                        var successMessage = "<?php echo esc_attr( __( 'Export completed successfully' ) ); ?>";
     189                                        var failureMessage = "<?php echo esc_attr( __( 'A failure occurred during export' ) ); ?>";
     190
     191                                        function on_exports_done_success() {
     192                                                $( '#exporters-container' ).append( '<p>' + successMessage + '</p>' );
     193                                        }
     194
     195                                        function on_export_failure( textStatus, error ) {
     196                                                $( '#exporters-container' ).append( '<p>' + failureMessage + '</p>' );
     197                                                $( '#exporters-container' ).append( '<p>' + textStatus + '</p>' );
     198                                        }
     199
     200                                        function do_next_export( exporterIndex, pageIndex ) {
     201                                                $.ajax( {
     202                                                        url: ajaxurl,
     203                                                        data: {
     204                                                                action: 'wp-privacy-export-personal-data',
     205                                                                email: exportForEmail,
     206                                                                exporter: exporterIndex,
     207                                                                page: pageIndex
     208                                                        },
     209                                                        method: 'post'
     210                                                } ).done( function( response ) {
     211                                                        var responseData = response.data;
     212                                                        for ( var dataIndex = 0; dataIndex < responseData.data.length; dataIndex++ ) {
     213                                                                $( '#exported-data-table' ).append( '<tr><td>' + responseData.data[ dataIndex ].name + '</td><td>' + responseData.data[ dataIndex ].value + '</td></tr>' );
     214                                                        }
     215                                                        if ( ! responseData.done ) {
     216                                                                setTimeout( do_next_export( exporterIndex, pageIndex + 1 ) );
     217                                                        } else {
     218                                                                if ( exporterIndex < exporterNames.length - 1 ) {
     219                                                                        setTimeout( do_next_export( exporterIndex + 1, 0 ) );
     220                                                                } else {
     221                                                                        on_exports_done_success();
     222                                                                }
     223                                                        }
     224                                                } ).fail( function( jqxhr, textStatus, error ) {
     225                                                        on_export_failure( textStatus, error );
     226                                                } );
     227                                        }
     228
     229                                        // And now, let's begin
     230                                        do_next_export( 0, 0 );
     231                                } )
     232                        } ) ( jQuery );
     233                </script>
     234
     235                <p>
     236                        <a href="privacy.php"><?php esc_html_e( 'Return to privacy tools' ); ?></a>
     237                </p>
     238                <?php
     239        } else {
     240                // No email address to export for? Then just display the privacy tools form table
     241                ?>
     242                <h2 class="title"><?php _e( 'Privacy policy page' ); ?></h2>
     243                <table class="form-table">
    145244                        <?php
    146245
    147246                        if ( $privacy_policy_page_exists ) {
    148                                 _e( 'Select another page for your privacy policy' );
    149                         } else {
    150                                 _e( 'Select an existing privacy policy page' );
     247                                $edit_href = add_query_arg(
     248                                        array(
     249                                                'post'  => $privacy_policy_page_id,
     250                                                'action' => 'edit',
     251                                        ),
     252                                        admin_url( 'post.php' )
     253                                );
     254                                $view_href = get_permalink( $privacy_policy_page_id );
     255
     256                                ?>
     257                                <tr>
     258                                        <th colspan="2">
     259                                                <?php
     260                                                printf(
     261                                                        __( '<a href="%1$s">Edit</a> or <a href="%2$s">view</a> your privacy policy.' ),
     262                                                        $edit_href,
     263                                                        $view_href
     264                                                );
     265                                                ?>
     266                                        </th>
     267                                </tr>
     268                                <?php
    151269                        }
    152270
    153271                        ?>
    154                         </th>
    155                         <td id="front-static-pages">
    156                                 <form method="post" action="">
    157                                         <?php wp_nonce_field( 'set-privacy-page' ); ?>
    158                                         <input type="hidden" name="action" value="set-privacy-page" />
    159                                         <fieldset>
    160                                                 <legend class="screen-reader-text"><span><?php _e( 'Select your privacy policy page.' ); ?></span></legend>
    161                                                 <label for="page_for_privacy_policy">
    162                                                         <?php wp_dropdown_pages(
    163                                                                 array(
    164                                                                         'name'              => 'page_for_privacy_policy',
    165                                                                         'show_option_none'  => __( '&mdash; Select &mdash;' ),
    166                                                                         'option_none_value' => '0',
    167                                                                         'selected'          => $privacy_policy_page_id,
    168                                                                         'post_status'       => array( 'draft', 'publish' ),
    169                                                                 )
    170                                                         );
    171                                                         ?>
    172                                                 </label>
    173                                         </fieldset>
    174                                                 <?php submit_button( __( 'Set Page' ) ); ?>
    175                                 </form>
    176                         </td>
    177                 </tr>
    178                 <?php
     272                        <tr>
     273                                <th scope="row">
     274                                <?php
    179275
    180                 if ( ! $privacy_policy_page_exists ) {
     276                                if ( $privacy_policy_page_exists ) {
     277                                        _e( 'Select another page for your privacy policy' );
     278                                } else {
     279                                        _e( 'Select an existing privacy policy page' );
     280                                }
     281
     282                                ?>
     283                                </th>
     284                                <td id="privacy-policy-page">
     285                                        <form method="post" action="">
     286                                                <?php wp_nonce_field( 'set-privacy-page' ); ?>
     287                                                <input type="hidden" name="action" value="set-privacy-page" />
     288                                                <fieldset>
     289                                                        <legend class="screen-reader-text"><span><?php _e( 'Select your privacy policy page.' ); ?></span></legend>
     290                                                        <label for="page_for_privacy_policy">
     291                                                                <?php wp_dropdown_pages(
     292                                                                        array(
     293                                                                                'name'              => 'page_for_privacy_policy',
     294                                                                                'show_option_none'  => __( '&mdash; Select &mdash;' ),
     295                                                                                'option_none_value' => '0',
     296                                                                                'selected'          => $privacy_policy_page_id,
     297                                                                                'post_status'       => array( 'draft', 'publish' ),
     298                                                                        )
     299                                                                );
     300                                                                ?>
     301                                                        </label>
     302                                                </fieldset>
     303                                                        <?php submit_button( __( 'Set Page' ) ); ?>
     304                                        </form>
     305                                </td>
     306                        </tr>
     307                        <?php
     308
     309                        if ( ! $privacy_policy_page_exists ) {
     310                                ?>
     311                                <tr>
     312                                        <th scope="row"><?php _e( 'Create new page for your privacy policy' ); ?></th>
     313                                        <td>
     314                                                <form method="post" action="">
     315                                                        <input type="hidden" name="action" value="create-privacy-page" />
     316                                                        <?php wp_nonce_field( 'create-privacy-page' ); ?>
     317                                                        <?php submit_button( __( 'Create Page' ) ); ?>
     318                                                </form>
     319                                        </td>
     320                                </tr>
     321                                <?php
     322                        }
    181323                        ?>
     324                </table>
     325
     326                <h2 class="title"><?php _e( 'Personal Data Management' ); ?></h2>
     327                <table class="form-table">
    182328                        <tr>
    183                                 <th scope="row"><?php _e( 'Create new page for your privacy policy' ); ?></th>
    184                                 <td>
     329                                <th scope="row"><?php _e( 'Export personal data' ); ?></th>
     330                                <td id="export-personal-data-form-container">
    185331                                        <form method="post" action="">
    186                                                 <input type="hidden" name="action" value="create-privacy-page" />
    187                                                 <?php wp_nonce_field( 'create-privacy-page' ); ?>
    188                                                 <?php submit_button( __( 'Create Page' ) ); ?>
     332                                                <input type="hidden" name="action" value="export-personal-data" />
     333                                                <?php wp_nonce_field( 'export-personal-data' ); ?>
     334                                                <fieldset>
     335                                                        <legend class="screen-reader-text"><span><?php _e( 'Enter the username or email address of the user whose personal data you wish to export' ); ?></span></legend>
     336                                                        <label for="username_or_email_to_export">
     337                                                                <input type="text" class="regular-text" name="username_or_email_to_export" />
     338                                                        </label>
     339                                                        <p class="description"><?php _e( 'The username or email address of the user whose personal data you wish to export' ); ?></p>
     340                                                </fieldset>
     341                                                <?php submit_button( __( 'Begin Export' ) ); ?>
    189342                                        </form>
    190343                                </td>
    191344                        </tr>
    192                         <?php
    193                 }
    194 
    195                 ?>
    196         </table>
     345                </table>
     346                <?php
     347        }
     348        ?>
    197349</div>
    198350
    199351<?php
  • src/wp-includes/comment.php

     
    32743274
    32753275        return get_comment( $comment_id );
    32763276}
     3277
     3278/**
     3279 * Registers the personal data exporter for comments
     3280 *
     3281 * @param array   $exporters   An array of personal data exporters.
     3282 * @return array  An array of personal data exporters.
     3283 */
     3284function wp_register_comment_personal_data_exporter( $exporters ) {
     3285        $exporters[] = array(
     3286                'exporter_friendly_name' => __( 'WordPress Comments' ),
     3287                'callback' => 'wp_comments_personal_data_exporter'
     3288        );
     3289
     3290        return $exporters;
     3291}
     3292
     3293/**
     3294 * Finds and exports data which could be used to identify a person from comments assocated with an email address.
     3295 *
     3296 * @param string  $email  The comment author email address.
     3297 * @param int     $page   Comment page.
     3298 * @return array  An array of personal data in name value pairs
     3299 */
     3300function wp_comments_personal_data_exporter( $email_address, $page ) {
     3301
     3302        $personal_data = array();
     3303        $email_address = trim( strtolower( $email_address ) );
     3304
     3305        // TODO - actually use the page parameter to avoid fetching all the comments at once
     3306        // that will be a no-no on sites with lots of comments
     3307
     3308        // TODO - pass the email address to get_comments if possible to be most performant
     3309
     3310        $comments = get_comments(
     3311                array(
     3312                        'order_by' => 'comment_ID',
     3313                        'order' => 'ASC'
     3314                )
     3315        );
     3316
     3317        $comment_personal_data_props = array(
     3318                'comment_author'       => __( 'Comment Author' ),
     3319                'comment_author_email' => __( 'Comment Author Email' ),
     3320                'comment_author_url'   => __( 'Comment Author URL' ),
     3321                'comment_author_IP'    => __( 'Comment Author IP' ),
     3322                'comment_agent'        => __( 'Comment Agent' )
     3323        );
     3324
     3325        foreach ( (array) $comments as $comment ) {
     3326                $comment_author_email = trim( strtolower( $comment->comment_author_email ) );
     3327                if ( $comment_author_email === $email_address ) {
     3328                        foreach ( (array) $comment_personal_data_props as $key => $description ) {
     3329                                $value = $comment->$key;
     3330                                if ( ! empty( $value ) ) {
     3331                                        $name = sprintf(
     3332                                                __( 'Comment %d : %s' ),
     3333                                                $comment->comment_ID,
     3334                                                $description
     3335                                        );
     3336                                        $personal_data[] = array(
     3337                                                'name'  => $name,
     3338                                                'value' => $value
     3339                                        );
     3340                                }
     3341                        }
     3342                }
     3343        }
     3344
     3345        return array(
     3346                'data' => $personal_data,
     3347                'done' => true,
     3348        );
     3349}
  • src/wp-includes/default-filters.php

     
    328328add_action( 'do_pings', 'do_all_pings', 10, 1 );
    329329add_action( 'do_robots', 'do_robots' );
    330330add_action( 'set_comment_cookies', 'wp_set_comment_cookies', 10, 3 );
     331add_filter( 'wp_privacy_personal_data_exporters', 'wp_register_comment_personal_data_exporter', 10 );
    331332add_action( 'sanitize_comment_cookies', 'sanitize_comment_cookies' );
    332333add_action( 'admin_print_scripts', 'print_emoji_detection_script' );
    333334add_action( 'admin_print_scripts', 'print_head_scripts', 20 );