Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 78 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,17 @@ The library owns its own database table (managed by **BerlinDB**), ships WordPre
2. [Installation](#installation)
3. [PHP Setup](#php-setup)
4. [Complete Integration Example](#complete-integration-example)
5. [Checking Access](#checking-access)
6. [React Component UI](#react-component-ui)
7. [Reading & Writing Rules (PHP)](#reading--writing-rules-php)
8. [REST API](#rest-api)
9. [Events](#events)
10. [Custom Providers](#custom-providers)
11. [Built-in Providers](#built-in-providers)
12. [Important Notes](#important-notes)
13. [Database Table Reference](#database-table-reference)
5. [Two Plugins on One Site](#two-plugins-on-one-site)
6. [Checking Access](#checking-access)
7. [React Component UI](#react-component-ui)
8. [Reading & Writing Rules (PHP)](#reading--writing-rules-php)
9. [REST API](#rest-api)
10. [Events](#events)
11. [Custom Providers](#custom-providers)
12. [Built-in Providers](#built-in-providers)
13. [Important Notes](#important-notes)
14. [Database Table Reference](#database-table-reference)
15. [Upgrading from 1.x](#upgrading-from-1x)

---

Expand Down Expand Up @@ -212,6 +214,73 @@ add_action( 'template_redirect', function () use ( $manager ) {

---

## Two Plugins on One Site

The whole reason `$table_slug` exists: when two consumer plugins embed this
library on the same WordPress install, each gets its **own** table, cache
group, transient keys, and REST routes. They cannot collide. Pick a distinct
slug per plugin — that is the only coordination required between them.

### Plugin A — `mcp-server`

```php
// Bootstrap
$manager = new AccessControlManager(
'mcp_server_access_control_providers',
'mcp' // → wp_mcp_access_control
);

// React config
wp_localize_script( 'wpb-ac-ui', 'wpbAcConfig', [
'pluginSlug' => 'mcp',
'namespace' => 'mcp/v1',
'resourceKey' => 'server',
'restApiRoot' => get_rest_url(),
'nonce' => wp_create_nonce( 'wp_rest' ),
] );
```

### Plugin B — `abilities-manager`

```php
// Bootstrap
$manager = new AccessControlManager(
'abilities_manager_access_control_providers',
'abilities' // → wp_abilities_access_control
);

// React config
wp_localize_script( 'wpb-ac-ui', 'wpbAcConfig', [
'pluginSlug' => 'abilities',
'namespace' => 'abilities/v1',
'resourceKey' => 'editor-panel',
'restApiRoot' => get_rest_url(),
'nonce' => wp_create_nonce( 'wp_rest' ),
] );
```

### What you actually get

| Surface | Plugin A (`mcp`) | Plugin B (`abilities`) |
|---|---|---|
| Table | `{prefix}mcp_access_control` | `{prefix}abilities_access_control` |
| Cache group | `wpb_ac_mcp` | `wpb_ac_abilities` |
| Schema version option | `wpb_ac_mcp_db_version` | `wpb_ac_abilities_db_version` |
| REST routes | `/wpb-ac/v1/mcp/...` | `/wpb-ac/v1/abilities/...` |
| Providers filter tag | `mcp_server_access_control_providers` | `abilities_manager_access_control_providers` |

Both managers can call `$manager->register_rest_api()` in the same request;
the slug-scoped paths mean WordPress registers two distinct sets of routes
instead of clobbering each other.

> **Picking a slug.** Must match `^[a-z0-9_]{1,32}$` — lowercase ASCII
> letters, digits, and underscores; 1 to 32 characters. Invalid slugs
> throw `\InvalidArgumentException` at construction time, never reaching
> SQL. Recommend using your plugin's `composer.json` name (or a short
> form of it) so the slug is stable and obviously yours.

---

## Checking Access

```php
Expand Down
Loading