Cookie Consent: register WP personal-data exporter/eraser for the consent log#49852
Cookie Consent: register WP personal-data exporter/eraser for the consent log#49852chihsuan wants to merge 13 commits into
Conversation
Code Coverage SummaryThis PR did not change code coverage! That could be good or bad, depending on the situation. Everything covered before, and still is? Great! Nothing was covered before? Not so great. 🤷 |
|
Thank you for your PR! When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:
This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖 Follow this PR Review Process:
If you have questions about anything, reach out in #jetpack-developers for guidance! Premium Analytics plugin: No scheduled milestone found for this plugin. If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack. |
Gate items_removed/done on the actual $wpdb->query result so a failed UPDATE/DELETE no longer reports success and can't wedge core's erasure loop for >100-row subjects. Add delete-mode convergence, guest-row, and REST user_id-filter tests; fix stale base TestCase docblock.
There was a problem hiding this comment.
Pull request overview
Adds GDPR support to the cookie-consent package’s consent-log by wiring it into WordPress core’s personal data export/erasure tools, while also standardizing the schema naming (customer_id → user_id) and introducing the package’s first PHPUnit test suite.
Changes:
- Register a personal-data exporter and eraser for consent-log rows (export by email→user, erase via anonymize-by-default with optional hard delete).
- Rename consent-log schema + REST filtering from
customer_idtouser_id. - Add PHPUnit/WorDBless-based test scaffolding and coverage for exporter/eraser behavior and schema expectations.
Reviewed changes
Copilot reviewed 18 out of 19 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| projects/plugins/premium-analytics/composer.lock | Updates locked metadata for the cookie-consent path dependency, reflecting added dev tooling/scripts. |
| projects/plugins/premium-analytics/changelog/update-cookie-consent-lock | Changelog entry for the lockfile update. |
| projects/packages/cookie-consent/composer.json | Adds PHP test tooling (phpunit-select-config, test environment, polyfills) and test scripts. |
| projects/packages/cookie-consent/.gitattributes | Excludes tests/phpunit config from production builds. |
| projects/packages/cookie-consent/changelog/add-consent-log-privacy-exporter-eraser | Changelog entry for privacy exporter/eraser and schema rename. |
| projects/packages/cookie-consent/src/class-consent-log-controller.php | Boots privacy integration and renames schema/REST filtering to user_id; exposes table name for reuse. |
| projects/packages/cookie-consent/src/class-consent-log-privacy.php | New privacy exporter/eraser implementation for consent-log rows. |
| projects/packages/cookie-consent/tests/.phpcs.dir.xml | Enables Jetpack test PHPCS ruleset for the new test suite. |
| projects/packages/cookie-consent/tests/php/bootstrap.php | Initializes the Jetpack test environment (sqlite/WorDBless) for this package. |
| projects/packages/cookie-consent/tests/php/class-testcase.php | Shared base TestCase and DB helpers for consent-log tests. |
| projects/packages/cookie-consent/tests/php/Scaffold_Test.php | Smoke test confirming the test environment is wired correctly. |
| projects/packages/cookie-consent/tests/php/Consent_Log_Schema_Test.php | Verifies fresh-install schema uses user_id (not customer_id). |
| projects/packages/cookie-consent/tests/php/Consent_Log_Privacy_Exporter_Test.php | Tests exporter behavior (unknown email, user match, pagination, guest rows). |
| projects/packages/cookie-consent/tests/php/Consent_Log_Privacy_Eraser_Test.php | Tests eraser behavior (anonymize default, delete mode, convergence, guest rows). |
| projects/packages/cookie-consent/tests/php/Consent_Log_Controller_Rest_Test.php | Tests REST filtering behavior for user_id and ensures customer_id is ignored. |
| projects/packages/cookie-consent/phpunit.8.xml.dist | PHPUnit config for older runners. |
| projects/packages/cookie-consent/phpunit.9.xml.dist | PHPUnit config for older runners. |
| projects/packages/cookie-consent/phpunit.11.xml.dist | PHPUnit config for newer runners. |
| projects/packages/cookie-consent/phpunit.12.xml.dist | PHPUnit config for newer runners. |
| add_action( 'rest_api_init', array( $instance, 'register_routes' ) ); | ||
| add_action( self::CLEANUP_HOOK, array( $instance, 'cleanup_expired_logs' ) ); | ||
|
|
||
| Consent_Log_Privacy::init(); | ||
|
|
| private static function get_rows( $user_id, $page ) { | ||
| global $wpdb; | ||
| $table = Consent_Log_Controller::get_table_name(); | ||
| $offset = ( max( 1, $page ) - 1 ) * self::PER_PAGE; | ||
| // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared | ||
| return $wpdb->get_results( | ||
| $wpdb->prepare( | ||
| "SELECT * FROM {$table} WHERE user_id = %d ORDER BY id LIMIT %d OFFSET %d", | ||
| $user_id, | ||
| self::PER_PAGE, | ||
| $offset | ||
| ), | ||
| ARRAY_A | ||
| ); | ||
| // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared | ||
| } |
Fixes WOOA7S-1563
Proposed changes
The cookie-consent log stores a visitor's IP address and WordPress user ID but registered no personal-data exporter/eraser, so a site owner had no way to fulfil a GDPR data-subject (export/erasure) request against it. This is a legally-blocking gap for a GDPR-targeted feature.
Why
How
Consent_Log_Privacyclass registerswp_privacy_personal_data_exportersandwp_privacy_personal_data_erasers, matching rows by email → user ID and paginating 100 rows per page. It's booted fromConsent_Log_Controller::init().items_removed+items_retainedaccordingly. Ajetpack_cookie_consent_erase_modefilter lets a site opt into hard deletion.What
customer_idcolumn touser_id(the value isget_current_user_id(); this package is plugin-agnostic and the old WooCommerce-flavoured name was misleading). The package is unreleased, so there is no runtime migration — a fresh install creates theuser_idcolumn directly. See "Reviewers with a pre-rename install" below if you tested an earlier build.Known limitation: guest rows (
user_id = 0, no email stored) are out of scope for core's email-keyed tools; that data is covered by the existing 30-day retention cleanup.Related product discussion/links
Does this pull request change what data or activity we track or use?
No new data is collected. This PR adds the ability to export and erase existing consent-log data via WordPress' privacy tools, and renames an existing column (
customer_id→user_id). The eraser's default mode anonymizes (clears IP, detaches the user) rather than deleting, retaining an anonymized consent record for accountability. This is a privacy-positive change.Testing instructions
Manually verified on chi.jurassic.tube, and covered by the package's PHPUnit suite (
cd projects/packages/cookie-consent && composer phpunit→ 11 tests passing).On a site with the package active and at least one consent-log row for a logged-in user:
user_idset to 0).add_filter( 'jetpack_cookie_consent_erase_mode', fn() => 'delete' );and repeat step 2; verify the matched rows are deleted.user_id = 0) untouched (documented limitation).