WordPress 7.1 adds `meta.public` as the general signal that an ability is intended for external clients. For REST, `show_in_rest` still wins when it is explicitly set. A careless search and replace can expose an ability to more clients than intended or hide one that an integration needs.
Use this for plugins, agency integrations, MCP adapters, REST clients, or custom administration tools that register WordPress abilities and need a controlled WordPress 7.1 upgrade.
Quick answer
Inventory every registered ability and classify its exposure intent before changing metadata. Use `public: true` when the ability is generally meant for external clients, keep `show_in_rest` when REST is the only intended channel, preserve explicit false values, and retest discovery plus execution with allowed and denied users.
What to check first
- List each ability name, execute callback, permission callback, current `show_in_rest` value, consumer, and data sensitivity.
- Classify whether the ability is internal, REST-only, generally public to clients, or public with a channel-specific opt-out.
- Test the resolution order `show_in_rest ?? public ?? false`, including explicit false and null values.
- Compare REST discovery before and after the metadata change using authenticated users with different capabilities.
- Confirm every external integration applies its own channel rule without overwriting an explicit opt-out.
Diagnostic table
Use this table to keep the work practical. It connects the symptom to evidence and a verification step.
| Action | Evidence to collect | How to verify |
| Build the ability inventory | List each ability name, execute callback, permission callback, current `show_in_rest` value, consumer, and data sensitivity. | Abilities with no exposure metadata remain unavailable through REST and resolve `public` to false. |
| Assign exposure intent | Classify whether the ability is internal, REST-only, generally public to clients, or public with a channel-specific opt-out. | An explicit `show_in_rest: false` overrides `public: true` without being treated as missing. |
| Apply explicit metadata | Test the resolution order `show_in_rest ?? public ?? false`, including explicit false and null values. | REST-only abilities stay out of clients that inherit only the general public flag. |
| Test discovery by channel | Compare REST discovery before and after the metadata change using authenticated users with different capabilities. | Unauthorized users cannot execute a discoverable ability, and allowed users receive the expected narrow result. |
Test scenarios to run
Run the same controlled fixture across these branches. Record the expected result before the test so a surprising response is visible immediately.
| Scenario | Fixture | Expected result |
| Internal ability | No exposure metadata and an authenticated administrator | Not listed through REST and no behavior change |
| Generally public ability | public true with an allowed editor | Listed for inheriting clients and executable only when permission passes |
| REST opt-out | public true plus show_in_rest false | Visible to general clients that allow it but absent from REST |
| REST-only ability | public false plus show_in_rest true | Listed through REST and not inherited as generally public |
Why this usually happens
- Older registrations expressed exposure one channel at a time, so intent was duplicated across integrations.
- A truthy-value check can lose the difference between explicit false and an unset value.
- Teams sometimes confuse discoverability metadata with the permission check that authorizes execution.
Field notes
- Record the exact WordPress build and MCP adapter version because client support can arrive on a different release schedule.
- Keep a before-and-after discovery export so reviewers can see which ability names became visible.
- Treat abilities that export users, mutate orders, or change settings as high-risk even when their labels look harmless.
Useful command or data shape
Adapt paths, IDs, and privacy handling to the site before running commands or storing data on production.
'meta' => array(
'public' => true,
'show_in_rest' => false,
),
// Effective public: true
// Effective REST exposure: false
// permission_callback still decides execution.
Safe fix order
Do the work in a sequence that makes each result easy to prove. Stop if a step produces new evidence that changes the incident scope.
- Build the ability inventory
- Assign exposure intent
- Apply explicit metadata
- Test discovery by channel
- Verify authorization separately
Decision rule
Do not ship the migration until every newly visible ability has an identified client, an explicit permission callback, denied-user coverage, and a written reason for exposure.
What to tell the client or owner
Give the developer the ability name, old metadata, proposed metadata, client, authenticated role, expected discovery state, expected execution result, and captured REST response.
Production verification checklist
- Abilities with no exposure metadata remain unavailable through REST and resolve `public` to false.
- An explicit `show_in_rest: false` overrides `public: true` without being treated as missing.
- REST-only abilities stay out of clients that inherit only the general public flag.
- Unauthorized users cannot execute a discoverable ability, and allowed users receive the expected narrow result.
Mistakes to avoid
- Do not replace every `show_in_rest` value with `public` without classifying the intended clients.
- Do not use the public flag as an authorization boundary.
- Do not test only an administrator account.
- Do not expose raw user, order, credential, or environment data without a minimum-data review.
Questions teams ask during testing
Must existing plugins migrate immediately?
No. Existing channel-specific registrations continue to work. Migrate when the broader public intent is accurate and tested.
Does `public: true` make an ability anonymous?
No. Exposure and discovery do not replace `permission_callback` or authentication.
What happens when both flags are present?
The explicit channel flag wins for that channel. For REST, `show_in_rest` takes precedence over `public`.
When HandL WP should help
Bring in HandL WP when an Abilities API migration touches customer data, order actions, AI agents, REST clients, or several plugins. We can build the inventory, test exposure and permissions, and document the release gate.
If this is active on a production site, review a WordPress 7.1 plugin upgrade.
Related HandL WP guides
Use these related guides when the same issue touches tracking, security, checkout, or crawler visibility.
Helpful references