Skip to content

feat(plugin-repo): Add privacy policy content check#1291

Open
faisalahammad wants to merge 3 commits into
WordPress:trunkfrom
faisalahammad:feature/1249-privacy-policy-content-check
Open

feat(plugin-repo): Add privacy policy content check#1291
faisalahammad wants to merge 3 commits into
WordPress:trunkfrom
faisalahammad:feature/1249-privacy-policy-content-check

Conversation

@faisalahammad

@faisalahammad faisalahammad commented May 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements the feature requested in #1249.

WordPress.org guidelines require that every plugin which collects, uses, stores, or passes personal data to a third party must suggest privacy policy text to site administrators using wp_add_privacy_policy_content(). In practice, the vast majority of plugins that handle personal data do not implement this.

This PR adds a new Privacy_Policy_Check (static file check) that detects common personal-data-handling signals and warns if wp_add_privacy_policy_content() is absent.

How it works

The check scans all PHP files in the plugin for signals that indicate potential personal data handling:

Signal Rationale
wp_remote_post() Transmitting data to external services
wp_remote_get() Fetching from external URLs (analytics, tracking)
setcookie() Setting cookies that may track users
$_COOKIE Reading cookie data
wp_set_auth_cookie() Authentication cookie handling

If any signal is found and wp_add_privacy_policy_content() is not called anywhere in the plugin, a single warning (severity 5) is emitted on the plugin's main file with a link to the WordPress privacy developer docs.

Plugins with no signals are completely unaffected — the check stays silent.

Design decisions

  • Warning, not error — the presence of these API calls doesn't guarantee personal data is being mishandled; it's a strong enough signal to inform authors but not block submission
  • One warning per plugin — avoids noise by stopping after the first matched signal
  • Early exit — checks for wp_add_privacy_policy_content() first; if present, skips all signal scanning
  • Conservative signals — only high-confidence indicators (remote posts/gets, cookies) are included, not noisy ones like raw $_POST/$_GET

Files changed

  • includes/Checker/Checks/Plugin_Repo/Privacy_Policy_Check.php — new check class
  • includes/Checker/Default_Check_Repository.php — register as privacy_policy
  • docs/checks.md — add row to the checks table
  • tests/phpunit/tests/Checker/Checks/Privacy_Policy_Check_Tests.php — 3 test cases
  • tests/phpunit/testdata/plugins/test-plugin-privacy-policy-with-errors/ — has signal, no privacy call → triggers warning
  • tests/phpunit/testdata/plugins/test-plugin-privacy-policy-without-errors/ — has signal + wp_add_privacy_policy_content() → clean
  • tests/phpunit/testdata/plugins/test-plugin-privacy-policy-no-signals/ — no signals → clean

Testing

Manually verified against Mailchimp for WordPress (mc4wp) — correctly fires the missing_privacy_policy_content warning on mailchimp-for-wp.php.

Verified against Akismet (which properly calls wp_add_privacy_policy_content()) — no warning produced.

Closes #1249

Open WordPress Playground Preview

Add a new Privacy_Policy_Check that warns when a plugin uses
personal-data-handling APIs but does not call
wp_add_privacy_policy_content().

WordPress.org guidelines require plugins that collect, store,
or transmit personal data to a third party to suggest privacy
policy text to site administrators via this function.

The check scans PHP files for signals indicating potential personal
data handling:
- wp_remote_post() / wp_remote_get() (external data transmission)
- setcookie() / $_COOKIE (cookie-based tracking)
- wp_set_auth_cookie() (authentication cookies)

If any signal is detected and wp_add_privacy_policy_content() is
not called anywhere in the plugin, a single warning is emitted on
the plugin's main file pointing to the official WordPress privacy
developer documentation.

Plugins with no signals are completely unaffected by this check.

Fixes WordPress#1249
@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: faisalahammad <faisalahammad@git.wordpress.org>
Co-authored-by: davidperezgar <davidperez@git.wordpress.org>
Co-authored-by: masteradhoc <masteradhoc@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

The plugin description contained wp_add_privacy_policy_content()
with parentheses, which caused the check's detection regex to
match the comment string and return early as if the function was
already implemented — producing no warning and failing the test.

The description now reads 'does not register privacy policy
content' which avoids the false positive without changing the
intent of the test fixture.
@davidperezgar

Copy link
Copy Markdown
Member

Thanks for the PR! I'm reviewing.

@davidperezgar

Copy link
Copy Markdown
Member

Thanks for the PR! The intent makes sense, but I think this needs one more pass before merging.

The check currently scans raw PHP file contents with regexes, so it matches function names in comments and strings as if they were real code. That creates both false negatives and false positives:

  • A comment like // TODO: call wp_add_privacy_policy_content() later will make the check return early, even if the plugin never actually calls the function.
  • A comment or example string containing wp_remote_post() will trigger the warning, even if the plugin does not actually make a remote request.

This also affects the current “without errors” fixture, because the plugin header description contains wp_add_privacy_policy_content() before the real call is reached.

Could we update the detection to ignore comments and strings, for example by using token_get_all() and only matching actual function calls / variable usage in code tokens? It would also be good to add explicit tests for function names appearing only in comments or strings, both for wp_add_privacy_policy_content() and for the signal patterns.

Replace regex scanning with token_get_all() so function names and
variables in comments and string literals no longer trigger false
positives or hide real signals.

Add fixtures and tests for comment-only and string-only mentions.
@faisalahammad

Copy link
Copy Markdown
Contributor Author

Thanks for the review. Good catch on the regex.

I moved the detection from regex to token parsing with token_get_all(). Now it only looks at real PHP tokens, so function names or variables that show up inside comments or string literals are not matched anymore. This fixes both the false positives (a comment mentioning the function would mark it as present and hide the warning) and keeps real calls detected.

What changed:

  • Function calls are matched on T_STRING followed by (, with a guard so method calls and definitions (->, ::, function, new) are skipped. ?-> is handled too, guarded behind defined() so it stays PHP 7.4 safe.
  • $_COOKIE is matched as a T_VARIABLE token, not text.
  • Added two fixtures: one with the privacy function name only inside a comment, one only inside a string. Both also have a real signal, so the test proves the warning still fires while the comment/string mention is ignored.

All checks pass locally: PHPUnit, PHPCS (WordPress + PHPCompatibility), and PHPStan.

Pushed in d025f52.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Privacy: Check that plugins handling personal data call wp_add_privacy_policy_content()

2 participants