Skip to content

Guard the API surface pp-hosts depends on - #790

Draft
ilicfilip wants to merge 1 commit into
developfrom
filip/pp-hosts-contract-test
Draft

ilicfilip wants to merge 1 commit into
developfrom
filip/pp-hosts-contract-test

Conversation

@ilicfilip

@ilicfilip ilicfilip commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

What this does

Progress Planner now reaches users only through pp-hosts, where it's a Composer dependency. This PR adds a contract test: it fails CI when a PP change removes or breaks something pp-hosts uses.

  • tests/contract/pp-hosts-contract.json lists the PP API surface pp-hosts depends on. It's generated in pp-hosts by bin/build-pp-contract.php; don't edit it by hand. It covers:
    • hooks pp-hosts listens to
    • parent classes it extends: overridden methods, used properties and constants
    • progress_planner()->get_*() services and the methods called on them
    • constants
    • dashboard widget IDs
    • assets
  • tests/contract/class-pp-hosts-contract-checker.php checks PP against that list using reflection and source scans. It needs no WordPress and no database.
  • tests/phpunit/test-pp-hosts-contract.php runs it as part of the normal PHPUnit suite, so it's covered by phpunit.yml.
  • tests/contract/check-pp-hosts-contract.php is the CLI version. The pp-hosts integration runner uses it.
  • CLAUDE.md covers branch roles, how the contract works, and what to do when it fails.

Three breakages that already exist are listed under known_issues. They're reported but don't fail the test. They're pp-hosts bugs, fixed on the pp-hosts side:

  • progress_planner_dashboard_sidebar is never fired.
  • The progress_planner_show_onboarding filter was removed in f82660b.
  • page-widgets/badge-streak-content.css never shipped.

Companion PR: ProgressPlanner/pp-hosts#150, which has the generator, the integration runner and the docs.

Testing

  • The CLI checker passes against v1.10.0/develop and against the locked 1.9.1 (2e1f332).
  • Planted breaks in a scratch copy were all caught: a renamed progress_planner_admin_widgets hook, an extra parameter on Widget::render(), a renamed Branding::get_branding_id(), and a deleted prpl-gauge.js.
  • The integration runner in pp-hosts passes with the pp-hosts branch (1.10.1, 3dd9278).
  • PHPCS is clean on the new files.
  • Not run locally: the PHPUnit wrapper, because the WP test DB isn't set up locally. This PR's CI run covers it.

🤖 Generated with Claude Code

Progress Planner reaches users as a Composer dependency of pp-hosts, so a
change that is harmless here can break there: a renamed hook, a removed
service method, a parent class that stops providing what a subclass
overrides. Nothing in this repo noticed, because nothing here knows what
pp-hosts uses.

pp-hosts-contract.json lists that surface -- hooks, parent classes with
their overridden methods and used properties, progress_planner()->get_*()
services and the methods called on them, constants, dashboard widget IDs
and assets. It is generated in pp-hosts, not written here, so it stays
honest about what is actually depended on rather than what someone
remembered to record.

Two ways to run it. The PHPUnit test runs in the normal suite on every
PR. The CLI checker runs without WordPress or a database, which is what
the pp-hosts integration runner calls with a contract generated from the
branch under test.

When it fails the answer is usually to keep the old API and deprecate it.
If the break is intended, pp-hosts changes in the same release and the
contract is regenerated there.

Passes against 1.10.1, with three documented known issues carried over
from pp-hosts: two hooks it still listens for that PP no longer fires,
and one stylesheet that only ever existed on a reverted branch.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@github-actions

Copy link
Copy Markdown
Contributor

Test on Playground
Test this pull request on the Playground
or download the zip

@github-actions

Copy link
Copy Markdown
Contributor

🔍 WordPress Plugin Check Report

⚠️ Status: Passed with warnings

📊 Report

🎯 Total Issues ❌ Errors ⚠️ Warnings
11 0 11

⚠️ Warnings (11)

📁 CLAUDE.md (1 warning)
📍 Line 🔖 Check 💬 Message
0 unexpected_markdown_file Unexpected markdown file "CLAUDE.md" detected in plugin root. Only specific markdown files are expected in production plugins.
📁 classes/suggested-tasks/data-collector/class-unpublished-content.php (1 warning)
📍 Line 🔖 Check 💬 Message
103 WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in Using exclusionary parameters, like post__not_in, in calls to get_posts() should be done with caution, see https://docs.wpvip.com/databases/optimize-queries/using-post__not_in/ for more information.
📁 classes/suggested-tasks/providers/class-content-review.php (4 warnings)
📍 Line 🔖 Check 💬 Message
232 WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in Using exclusionary parameters, like post__not_in, in calls to get_posts() should be done with caution, see https://docs.wpvip.com/databases/optimize-queries/using-post__not_in/ for more information.
377 WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in Using exclusionary parameters, like post__not_in, in calls to get_posts() should be done with caution, see https://docs.wpvip.com/databases/optimize-queries/using-post__not_in/ for more information.
381 WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in Using exclusionary parameters, like post__not_in, in calls to get_posts() should be done with caution, see https://docs.wpvip.com/databases/optimize-queries/using-post__not_in/ for more information.
388 WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in Using exclusionary parameters, like post__not_in, in calls to get_posts() should be done with caution, see https://docs.wpvip.com/databases/optimize-queries/using-post__not_in/ for more information.
📁 classes/activities/class-query.php (2 warnings)
📍 Line 🔖 Check 💬 Message
71 PluginCheck.Security.DirectDB.UnescapedDBParameter Unescaped parameter $table_name used in $wpdb->query()\n$table_name assigned unsafely at line 58.
163 PluginCheck.Security.DirectDB.UnescapedDBParameter Unescaped parameter $where_args used in $wpdb->get_results()\n$where_args assigned unsafely at line 153.
📁 classes/suggested-tasks/data-collector/class-yoast-orphaned-content.php (1 warning)
📍 Line 🔖 Check 💬 Message
111 PluginCheck.Security.DirectDB.UnescapedDBParameter Unescaped parameter $query used in $wpdb->get_row()\n$query assigned unsafely at line 98.
📁 classes/suggested-tasks/data-collector/class-terms-without-description.php (1 warning)
📍 Line 🔖 Check 💬 Message
108 PluginCheck.Security.DirectDB.UnescapedDBParameter Unescaped parameter $query used in $wpdb->get_results()\n$query assigned unsafely at line 106.
📁 classes/suggested-tasks/data-collector/class-terms-without-posts.php (1 warning)
📍 Line 🔖 Check 💬 Message
120 PluginCheck.Security.DirectDB.UnescapedDBParameter Unescaped parameter $query used in $wpdb->get_results()\n$query assigned unsafely at line 118.

🤖 Generated by WordPress Plugin Check Action • Learn more about Plugin Check

@github-actions

Copy link
Copy Markdown
Contributor

✅ Code Coverage Report

Metric Value
Total Coverage 34.27% 📉
Base Coverage 34.27%
Difference 📈 0.00%

⚠️ Coverage below recommended 40% threshold

🎉 Great job maintaining/improving code coverage!

ℹ️ About this report
  • All tests run in a single job with Xdebug coverage
  • Security tests excluded from coverage to prevent output issues
  • Coverage calculated from line coverage percentages

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.

1 participant