Opened 8 years ago
Last modified 9 days ago
#44498 assigned enhancement
Make `_wp_personal_data_cleanup_requests()` run on cron
| Reported by: |
|
Owned by: |
|
|---|---|---|---|
| Milestone: | 7.1 | Priority: | normal |
| Severity: | normal | Version: | 4.9.6 |
| Component: | Privacy | Keywords: | has-patch has-test-info has-unit-tests |
| Focuses: | Cc: |
Description
When a data export or removal request is created, a user must confirm that request within x days. By default, this is 1 day (24 hours), but it can be changed using the user_request_key_expiration filter. If a user does not confirm the request within that time, it is marked as failed, and the request needs to be re-initiated.
Currently, requests are only marked as failed when the Export/Erase Personal Data screens are accessed. By default, only administrators can access this page, and will most likely do so very infrequently. Because of this, a cron may be more appropriate for marking requests as failed.
A posts_per_page => -1 query arg is also used to fetch expired requests, which could cause issues when a large number of requests have failed. Moving this action to a cron should cut down on the number of requests that need to be transitioned at a time.
Change History (12)
This ticket was mentioned in Slack in #core-privacy by desrosj. View the logs.
8 years ago
#4
@
2 months ago
Hey @desrosj
Thanks for the clear report — I’ve opened a Pull Request for review.
Additionally, I identified and fixed a timezone issue in _wp_personal_data_cleanup_requests() (wp-admin/includes/privacy-tools.php).
The query used 'column' => 'post_modified_gmt', while WP_Date_Query::build_mysql_datetime() generates timestamps in the site’s local timezone. This led to mismatched comparisons (local time vs UTC):
- Positive UTC offsets: expiry threshold shifts into the future → requests expire immediately
- Negative offsets: requests live longer than intended
This is subtle with a 24h window but becomes obvious with short expirations (e.g. 120 seconds used for my tests), where requests can fail instantly.
Thank you very much for your feedback.
This ticket was mentioned in Slack in #core by jorbin. View the logs.
2 weeks ago
@audrasjb commented on PR #11444:
2 weeks ago
#7
The PR looks good on my side. Some additional testing would be nice, too.
#9
@
2 weeks ago
- Keywords has-test-info added; needs-unit-tests removed
Patch testing report
Patch / PR tested
- https://github.com/WordPress/wordpress-develop/pull/11444
- trunk @ 6782f0eecc with PR diff applied
Environment
WordPress: 7.1-alpha-62161-src
MySQL: 8.4.9
OS: macOS 26.3.1
Browser: Chromium, desktop viewport
Local wordpress-develop @ http://localhost:8889
Steps
- Confirmed on trunk: no wp_privacy_personal_data_cleanup_requests cron event exists — only wp_privacy_delete_old_export_files is scheduled.
- Confirmed on trunk: privacy-tools.php uses 'column' => 'post_modified_gmt' in the date_query (timezone bug present).
- Created a test pending export request via WP-CLI and backdated post_modified to 2 days ago via SQL to simulate an expired request.
- Confirmed on trunk: the expired request stays request-pending — it is only transitioned to request-failed when an admin visits /wp-admin/export-personal-data.php (page visit triggers the cleanup).
- Applied PR #11444 (fetched as refs/pull/11444/head).
- Verified three code changes are present:
- privacy-tools.php: 'column' changed from post_modified_gmt to post_modified.
- functions.php: wp_schedule_personal_data_cleanup_requests() and wp_cron_personal_data_cleanup_requests() added.
- default-filters.php: both functions hooked to init and the cron event.
- Loaded a page to trigger init; confirmed wp_privacy_personal_data_cleanup_requests is now scheduled (daily recurrence).
- Created a new pending request and backdated it 2 days via SQL.
- Fired the cron event manually with wp cron event run — without visiting any admin page.
- Confirmed the request transitioned to request-failed via cron alone.
Results
- Cron event absent on trunk: pass — no wp_privacy_personal_data_cleanup_requests event found before patch.
- Timezone bug present on trunk: pass — post_modified_gmt confirmed in query.
- Cron event registered after patch: pass — wp_privacy_personal_data_cleanup_requests scheduled daily after first init.
- Cron cleanup without admin page visit: pass — expired request transitioned from request-pending to request-failed by firing the cron event directly, with no admin privacy page loaded.
- Backward compatibility: pass — existing synchronous cleanup on admin page visit continues to work as before.
Conclusion
PR #11444 correctly schedules _wp_personal_data_cleanup_requests() as a daily cron event and fixes the timezone mismatch in the expiry date query. Expired unconfirmed privacy requests are now cleaned up automatically without requiring an admin to visit the privacy management screens. Recommend commit.
@mukesh27 commented on PR #11444:
13 days ago
#10
@masteradhoc Seems like you AI agent did wrong things so that PHPCS get failed 😄
This ticket was mentioned in PR #12049 on WordPress/wordpress-develop by @nimeshatxecurify.
9 days ago
#11
- Keywords has-unit-tests added
This introduces wp_schedule_personal_data_cleanup_requests() to automatically transition expired personal data requests to a "failed" state via WP-Cron.
The update also fixes a timezone bug in _wp_personal_data_cleanup_requests() where using post_modified_gmt in a relative date query caused requests to expire at the wrong time on sites with a UTC offset. Switching to post_modified ensures the relative "seconds ago" comparison remains consistent with the site's local time.
Trac ticket: https://core.trac.wordpress.org/ticket/44498
PR Reference: https://github.com/WordPress/wordpress-develop/pull/11444
## Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Sonnet-4.6
Used for: Test suggestions; final implementation and tests were reviewed by me.
Great!