WordPress Privacy System Overview
WordPress includes a comprehensive privacy and GDPR compliance system introduced in version 4.9.6. This system enables sites to handle personal data requests from users, including data export and erasure (right to be forgotten).
Core Concepts
Personal Data Requests
WordPress handles two types of privacy-related requests:
| Request Type | Action Name | Description |
|---|---|---|
| Export Personal Data | export_personal_data |
Exports all personal data associated with an email address |
| Erase Personal Data | remove_personal_data |
Anonymizes or deletes personal data associated with an email address |
Request Workflow
- Request Creation – Admin or user initiates a request via the privacy tools
- Email Verification – A confirmation email is sent to the user’s email address
- User Confirmation – User clicks the confirmation link to verify ownership
- Admin Notification – Site admin receives notification of the confirmed request
- Request Processing – Admin processes the export or erasure
- User Notification – User receives notification when their request is fulfilled
Request Statuses
Requests are stored as a custom post type (user_request) with these statuses:
| Status | Description |
|---|---|
request-pending |
Awaiting user email confirmation |
request-confirmed |
User confirmed, awaiting admin processing |
request-failed |
Email sending failed |
request-completed |
Request has been fulfilled |
Personal Data Exporters
The export system uses a plugin-based architecture. Exporters are registered via the wp_privacy_personal_data_exporters filter.
Built-in Exporters
| Exporter ID | Friendly Name | Source |
|---|---|---|
wordpress-user |
WordPress User | user.php |
wordpress-comments |
WordPress Comments | comment.php |
wordpress-media |
WordPress Media | media.php |
Exporter Callback Format
function my_exporter_callback( $email_address, $page = 1 ) {
return array(
'data' => array(
array(
'group_id' => 'my-group',
'group_label' => 'My Data Group',
'group_description' => 'Description of this data group.',
'item_id' => 'item-123',
'data' => array(
array(
'name' => 'Field Name',
'value' => 'Field Value',
),
),
),
),
'done' => true, // false if more pages exist
);
}
Registering a Custom Exporter
add_filter( 'wp_privacy_personal_data_exporters', function( $exporters ) {
$exporters['my-plugin'] = array(
'exporter_friendly_name' => 'My Plugin Data',
'callback' => 'my_plugin_personal_data_exporter',
);
return $exporters;
} );
Personal Data Erasers
Erasers handle anonymization or deletion of personal data. Registered via wp_privacy_personal_data_erasers filter.
Built-in Erasers
| Eraser ID | Friendly Name | Source |
|---|---|---|
wordpress-comments |
WordPress Comments | comment.php |
Note: WordPress does not include an eraser for user accounts or media by default, as deletion may have wider implications.
Eraser Callback Format
function my_eraser_callback( $email_address, $page = 1 ) {
return array(
'items_removed' => true, // Were items actually removed?
'items_retained' => false, // Were items retained (couldn't delete)?
'messages' => array(), // Messages to include in results
'done' => true, // false if more pages exist
);
}
Registering a Custom Eraser
add_filter( 'wp_privacy_personal_data_erasers', function( $erasers ) {
$erasers['my-plugin'] = array(
'eraser_friendly_name' => 'My Plugin Data',
'callback' => 'my_plugin_personal_data_eraser',
);
return $erasers;
} );
Data Anonymization
WordPress provides helper functions for consistent data anonymization:
// Anonymize different data types
wp_privacy_anonymize_data( 'email' ); // Returns: '[email protected]'
wp_privacy_anonymize_data( 'url' ); // Returns: 'https://site.invalid'
wp_privacy_anonymize_data( 'ip', $ip ); // Returns anonymized IP
wp_privacy_anonymize_data( 'date' ); // Returns: '0000-00-00 00:00:00'
wp_privacy_anonymize_data( 'text' ); // Returns: '[deleted]'
wp_privacy_anonymize_data( 'longtext' ); // Returns longer deletion message
Privacy Policy Page
WordPress supports designating a Privacy Policy page:
// Get the privacy policy URL
$url = get_privacy_policy_url();
// Display the privacy policy link
the_privacy_policy_link( 'Before text ', ' After text' );
// Get link markup
$link = get_the_privacy_policy_link( '<span>', '</span>' );
The privacy policy page ID is stored in the wp_page_for_privacy_policy option.
Export File Management
Personal data exports are stored as files in wp-content/uploads/wp-personal-data-exports/.
- Files include a cryptographically secure random string in the filename
- Files are automatically deleted after 3 days via cron job
- The
wp_privacy_export_expirationfilter can modify the expiration time
Admin Screens
The privacy system adds two admin screens:
| Screen | URL | Purpose |
|---|---|---|
| Export Personal Data | /wp-admin/export-personal-data.php |
Manage export requests |
| Erase Personal Data | /wp-admin/erase-personal-data.php |
Manage erasure requests |
GDPR Compliance Notes
While WordPress provides the technical infrastructure for GDPR compliance, site owners are responsible for:
- Privacy Policy – Creating and maintaining an appropriate privacy policy
- Data Inventory – Understanding what personal data is collected
- Consent – Obtaining proper consent for data collection
- Third Parties – Ensuring plugins and themes also comply
- Processing Requests – Responding to data requests within required timeframes
Related Files
| File | Contents |
|---|---|
wp-includes/class-wp-user-request.php |
WP_User_Request class |
wp-includes/user.php |
Request handling functions |
wp-includes/functions.php |
Anonymization and export utilities |
wp-includes/comment.php |
Comment exporter/eraser |
wp-includes/media.php |
Media exporter |
wp-includes/link-template.php |
Privacy policy link functions |
wp-includes/default-filters.php |
Hook registrations |
Version History
| Version | Changes |
|---|---|
| 4.9.6 | Initial privacy system introduced |
| 5.4.0 | Added Community Events Location and Session Tokens to user export |
| 5.7.0 | Added $status parameter to wp_create_user_request() |
| 5.8.0 | Deprecated some email content filters, added new ones |
| 6.2.0 | Added privacy-policy rel attribute to policy links |
| 6.8.0 | Confirmation keys now use wp_fast_hash() instead of phpass |