fix(release): restore v2.0.0 code dropped by revert+merge - #20
Merged
Merged
Conversation
BREAKING: each consumer plugin now owns its own database table, object-cache
group, and REST route prefix. AccessControlManager requires a second
constructor argument $table_slug (^[a-z0-9_]{1,32}$). Existing v1.x
consumers that pass only the providers filter tag will fail with
ArgumentCountError on upgrade.
Previously every consumer wrote into one shared {prefix}wpb_access_control
table and registered the same /wpb-ac/v1/... routes — two plugins on the
same WordPress install would collide on rules, on cached payloads (single
wpb_access_control cache group), and on REST handlers (last-loaded-wins).
Migration:
// PHP bootstrap
$manager = new AccessControlManager(
'my_plugin_access_control_providers',
'my_plugin' // slug; pick one per plugin
);
// wpbAcConfig / React props
wp_localize_script( 'wpb-ac-ui', 'wpbAcConfig', [
'pluginSlug' => 'my_plugin', // NEW
// …existing fields…
] );
// REST URLs: /wpb-ac/v1/rules/... → /wpb-ac/v1/{slug}/rules/...
Optional one-off SQL copy from {prefix}wpb_access_control to the new
per-consumer table; see README's "Upgrading from 1.x" section. The
library does NOT auto-migrate — it doesn't know which namespaces each
consumer owns.
Files:
- src/Slug.php — new helper, Slug::sanitize() validates ^[a-z0-9_]{1,32}$
and throws \InvalidArgumentException on invalid input.
- src/Database/Rule/RuleTable.php — constructor accepts $table_slug;
derives $name and $db_version_key per instance; removes hardcoded
defaults.
- src/Database/Rule/RuleQuery.php — constructor accepts $table_slug;
derives $table_name and $cache_group; replaces single static
$table_setup flag with per-slug registry; folds slug into the
transient_key hash so cache cannot collide across consumers.
- src/AccessControlManager.php — second required constructor arg
$table_slug; new get_table_slug() getter; passes the slug into
RuleQuery + RulesController.
- src/RestApi/RulesController.php — accepts slug; every register_rest_route
call now uses '/{slug}/rules/…', '/{slug}/providers', '/{slug}/users',
'/{slug}/namespaces/{namespace}'.
- js/AccessControl.js + js/components/UserSearchPanel.js + js/index.js —
new required pluginSlug prop / wpbAcConfig field; every apiFetch URL
carries the slug segment. Auto-render path bails with a clear console
error when pluginSlug is missing.
- tests: new SlugTest (17 cases covering accept/reject + error message
shape), new RuleQueryConstructorTest (8 cases asserting slug-driven
table_name / cache_group / two-instance isolation + slug validation
propagation through the ctor), 2 new register_routes tests in
RulesControllerTest (slug prefix on all four route groups + distinct
prefix per slug). Existing tests untouched — Brain Monkey suites use
newInstanceWithoutConstructor / disableOriginalConstructor / partial
mocks, so the new required ctor arg is transparent to them.
PHPUnit: 190 tests / 267 assertions all green (was 160/218). JS assets
rebuilt via wp-scripts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
PR #19 merged `feat/per-consumer-tables` into `main`, but the merge brought only the README docs — the entire v2.0.0 source tree was missing afterward. Root cause: the branch was never rebased after the v2.0.0 revert (#18), so Git treated the v2.0.0 code as already-merged and skipped it.
After PR #19 landed on `c8694a3`, `main` had a README describing per-consumer tables, slug-scoped REST routes, and `Slug::sanitize()` — none of which existed in the code.
What this PR does
Cherry-picks `2d7e48b` (the original v2.0.0 squashed commit) onto current `main`. That single commit re-introduces:
The README auto-merged cleanly — "Two Plugins on One Site" and "Upgrading from 1.x" sections (already on main from #19) are preserved alongside the slug-aware code examples re-added by this commit.
Verification
```sh
Before this PR (on main)
ls src/Slug.php # No such file or directory
grep table_slug src/AccessControlManager.php # no matches
After this PR
ls src/Slug.php # exists
grep -c table_slug src/AccessControlManager.php # 9
```
After merge
Tag `v2.0.0` on the resulting main commit and publish the GitHub release.
🤖 Generated with Claude Code