Skip to content

Add support for the new meta.public flag - #10

Merged
swissspidy merged 6 commits into
mainfrom
claude/ability-command-issue-review-qe4bvi
Aug 9, 2026
Merged

Add support for the new meta.public flag#10
swissspidy merged 6 commits into
mainfrom
claude/ability-command-issue-review-qe4bvi

Conversation

@swissspidy

@swissspidy swissspidy commented Aug 9, 2026

Copy link
Copy Markdown
Member

Fixes #9.

WordPress 7.1 introduces meta.public as the high-level client exposure setting, with channel-specific flags taking precedence. Core resolves the cascade at registration, so show_in_rest already reports effective REST exposure — but meta.public itself was invisible, and there was no way to tell whether REST exposure came from the high-level flag or the channel flag.

What changed

  • public is an optional field on list and a default field on get, ordered before show_in_rest.
  • --public / --no-public filter on list.
  • meta is an optional field on get, rendering raw metadata as JSON.
  • Inline docs updated on the class docblock, list, and get — these generate the command reference pages, so they land here.

Nothing reimplements the precedence rules, and list still reports every registered ability regardless of exposure. WP-CLI runs with full trust; these are display and filter concerns, not access control.

Design decisions

public renders 1/0, not tri-state

Open question 1 asked whether public should render 1/0/empty the way readonly and friends do through format_annotation(). It can't, and shouldn't pretend to. WP_Ability::prepare_properties() always materializes the flag:

$args['meta']['show_in_rest'] = $args['meta']['show_in_rest'] ?? $args['meta']['public'] ?? self::DEFAULT_SHOW_IN_REST;
$args['meta']['public']       = $args['meta']['public'] ?? self::DEFAULT_PUBLIC;   // false

Core's own tests pin this down — test_meta_public_defaults_to_false_when_unset asserts the key is always present in get_meta(), test_meta_public_null_is_treated_as_unset collapses explicit null to false, and anything non-boolean throws. "Never declared" and "declared false" are indistinguishable by the time the command sees the ability, so an empty rendering could only ever mean "old WordPress", which is misleading.

The REST controller draws the same line: annotations are typed array( 'boolean', 'null' ), public is typed 'boolean'. format_annotation() exists because $default_annotations are null; public isn't in that category. It uses the same one-liner show_in_rest already does, which also keeps 6.9/7.0 sane where meta is unvalidated free-form.

Documentation only for the 6.9/7.0 gap — no runtime note

Open question 2 asked whether a WP_CLI::debug() note is worth it on versions where the flag is inert. It isn't. The ## AVAILABLE FIELDS docs on both list and get state that public has no effect before 7.1 and may therefore disagree with show_in_rest, and that is where someone puzzled by the output actually looks — --debug is not a flag you reach for before you know something is wrong.

An earlier revision of this PR added a once-per-run debug note; it was removed in 49800b1. It could only ever fire on 6.9 and 7.0, so it was dead code by construction, and cost a version check plus a pass over the displayed items on every run to say something the docs already say.

meta is optional on get, not default

Open question 3 proposed mirroring wp ability category get, where meta is a default field. This diverges deliberately: on 7.1 ability meta is {annotations, show_in_rest, public} plus channel keys, so a default column would duplicate five fields already rendered as their own rows, every call, on top of two JSON schema blobs. Category meta is default because a category has three other fields and meta is its only extensibility surface.

Optional still keeps the escape hatch — meta.mcp.public and friends have no field of their own, and Core treats nested channel meta as first-class (_wp_get_abilities_match_meta() matches nested arrays; array( 'mcp' => array( 'public' => true ) ) is the documented example). Worth noting mcp is not a Core-defined channel, which argues for a generic raw dump over any channel-specific field. Rendering matches Ability_Category_Command::format_category_for_get() exactly. Not added to list, where a JSON blob per row would wreck table output.

The exposure filters are plain flags

[--public] and [--show-in-rest] are declared as boolean flags rather than =<bool> params. Utils\get_flag_value() returns true for --public, false for --no-public, and null when absent, so each filter is a direct boolean comparison — no parsing, no validation code, no options block.

Earlier revisions of this PR tried a hand-rolled parse_bool_filter() (621cd5c, dc3d2db) and then declarative options: true/false (2db8a66). Both are gone as of d2a444b; the flag form is how WP-CLI models booleans and needs none of it.

Behavior change

--show-in-rest previously took a value: --show-in-rest=true / =false. It is now a flag, so those forms become --show-in-rest / --no-show-in-rest. Since flag-type params do not validate their values, an old-style --show-in-rest=true is accepted and then matches nothing rather than erroring — worth knowing if the released form is considered load-bearing.

That also fixes a latent bug in the old parsing: filter_var() with FILTER_NULL_ON_FAILURE returned null for an unparseable value and the guard then skipped the comparison entirely, so --show-in-rest=bogus silently became a no-op and listed every registered ability.

Notes

  • The issue's background is slightly off. It says an ability written against 7.1 "produces identical CLI output on every supported version". For the current command it's the opposite: an ability declaring only meta.public => true renders show_in_rest 1 on 7.1 and show_in_rest 0 on 6.9/7.0, so output already tracked reachability. Adding the public field is what creates the divergent-looking output, which the field documentation now covers.
  • wp_get_abilities( $args ) is deliberately not used. 7.1 added declarative filtering and array( 'meta' => array( 'public' => true ) ) looks like the obvious implementation. It's a trap: on 6.9/7.0 the function takes no parameters, PHP silently discards extra args to userland functions, and the command would return the entire unfiltered registry while claiming to have filtered. Filtering stays in the command loop.
  • README.md is untouchedregenerate-readme.yml handles it on merge to main.
  • These fields serialize as strings in JSON ("public":"1"), matching the existing readonly/show_in_rest convention rather than fixing it here.

Testing

Three scenarios added to features/ability.feature: public seeding show_in_rest, explicit show_in_rest => false winning over public => true, --public / --no-public filtering, and raw meta showing an mcp channel key while staying out of default output. The exposure scenarios are tagged @require-wp-7.1; the meta one works on 6.9 and is tagged accordingly. The existing show_in_rest filter scenario switches to the flag form.

No other existing scenario changes behavior — every table and JSON assertion in the file is containment-style, and every exact STDOUT should be: is a single --field= value.

@swissspidy
swissspidy requested a review from a team as a code owner August 9, 2026 11:11
Copilot AI lite review requested due to automatic review settings August 9, 2026 11:11
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The ability command now exposes public metadata, validates visibility filters, supports raw metadata inspection, and documents version-dependent behavior. Acceptance scenarios cover output, filtering, precedence, invalid values, and nested metadata.

Changes

Ability metadata visibility and filtering

Layer / File(s) Summary
Metadata output and documentation
src/Ability_Command.php
List and get output now include formatted public metadata. Get output also supports raw JSON metadata. Documentation and examples describe these fields and their semantics.
Visibility filter validation and behavior
src/Ability_Command.php
The --public and --show-in-rest filters now use shared boolean validation. List filtering uses formatted public metadata.
Acceptance coverage
features/ability.feature
Scenarios validate filter errors, visibility output, public-status filtering, metadata precedence, and raw metadata inspection.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: brianhenryie, ernilambar, janw-me

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes satisfy issue #9 by adding public fields, filtering, raw metadata output, documentation, validation, and effective exposure handling.
Out of Scope Changes check ✅ Passed The changes remain within issue #9 and the stated objectives; no unrelated code changes are identified.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the pull request's primary change: support for the new meta.public flag.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/ability-command-issue-review-qe4bvi

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Aug 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 72.72727% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/Ability_Command.php 72.72% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

coderabbitai[bot]

This comment was marked as resolved.

claude added 2 commits August 9, 2026 11:14
`filter_var()` with `FILTER_NULL_ON_FAILURE` returns null for an
unparseable value such as `--show-in-rest=bogus`. The guard then skipped
the comparison entirely, so the filter silently became a no-op and the
command listed every registered ability. Asking to filter and receiving
the full set back is worse than an error.

Extract the parsing into `parse_bool_filter()` and fail with a clear
message instead. `true`/`false`/`1`/`0`/`yes`/`no`, the bare flag, and
`--no-show-in-rest` all keep working as before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0162D8GNP2TsQyHUQKNoQv3a
WordPress 7.1 introduces `meta.public` as the high-level client exposure
setting, with channel-specific flags taking precedence. Core resolves the
cascade at registration, so `show_in_rest` already reports effective REST
exposure -- but `meta.public` itself was invisible, and there was no way
to tell whether REST exposure came from the high-level flag or the
channel flag.

Add `public` as an optional field on `list` and a default field on `get`,
ordered before `show_in_rest`, plus a `--public=` filter on `list`.

Add `meta` as an optional field on `get`, rendering the raw metadata as
JSON the way `wp ability category get` already does. It is the only way
to inspect channel-specific settings such as `mcp.public`, which no
dedicated field covers.

Nothing here reimplements the precedence rules, and `list` keeps
reporting every registered ability regardless of exposure. WP-CLI runs
with full trust; these flags are display and filter concerns, not access
control.

Fixes #9

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0162D8GNP2TsQyHUQKNoQv3a
@swissspidy
swissspidy force-pushed the claude/ability-command-issue-review-qe4bvi branch from 6c2fe89 to b6922ba Compare August 9, 2026 11:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds WP-CLI support for the new WordPress 7.1 meta.public ability flag so operators can see and filter on the high-level client exposure setting (and optionally inspect raw meta for channel-specific settings).

Changes:

  • Adds public as a listable field (and default get field) plus a --public=<bool> filter on wp ability list.
  • Adds optional raw meta output on wp ability get and emits a one-time debug note on WP < 7.1 when public is declared but inert.
  • Extends Behat coverage for public, filtering, raw meta inspection, and invalid boolean filter rejection.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/Ability_Command.php Implements the new public field/filter, optional meta output, boolean filter parsing, and the WP<7.1 debug note.
features/ability.feature Adds Behat scenarios covering public output/precedence, filtering, raw meta inspection, and invalid boolean values.
Suppressed comments (1)

src/Ability_Command.php:713

  • format_ability_for_get() always calls $ability->get_meta() (and later JSON-encodes it) even though meta is documented as an optional field and is not included in $this->get_fields (the default output fields). This adds avoidable work on every wp ability get call and can be noticeable if abilities carry large meta arrays.
	/**
	 * Formats an ability for get output.
	 *
	 * @param WP_Ability $ability The ability object.
	 * @return array<string,mixed>

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/Ability_Command.php Outdated
`FILTER_VALIDATE_BOOLEAN` treats an empty string as a valid `false`, so
`--public=` and `--show-in-rest=` slipped past the new validation and
quietly applied a false filter -- the same footgun the validation was
added to close. Reject the empty value before parsing.

The error message also claimed only `true` and `false` were accepted
while the parser takes the full `FILTER_VALIDATE_BOOLEAN` set. List what
is actually accepted rather than narrowing the parser, since `1`/`0` and
`yes`/`no` are conventional in WP-CLI flags.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0162D8GNP2TsQyHUQKNoQv3a
@swissspidy swissspidy added this to the 1.0.3 milestone Aug 9, 2026
@swissspidy swissspidy added the command:ability Related to 'ability' command label Aug 9, 2026
The `## AVAILABLE FIELDS` docs on both `list` and `get` already state that
`public` has no effect before WordPress 7.1 and that it may therefore
disagree with `show_in_rest`. That is where someone puzzled by the output
will look; `WP_CLI::debug()` output only appears under `--debug`, which
is not a flag you reach for when you do not yet know something is wrong.

The helper also had a finite life by construction -- it could only ever
fire on 6.9 and 7.0 -- while costing a version check and a pass over the
displayed items on every run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0162D8GNP2TsQyHUQKNoQv3a

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Ability_Command.php`:
- Line 700: Update the ability output handling in src/Ability_Command.php at
lines 700-700 and 725-725, covering the paths used by wp ability list and wp
ability get. Add a once-per-command guard that inspects the raw meta.public
value and emits a debug notice before the public field is output; preserve the
existing public value conversion and ensure the notice is emitted only once
across both affected sites.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2d0fc88d-b57d-49ec-b9dd-18faf21b2114

📥 Commits

Reviewing files that changed from the base of the PR and between 6c2fe89 and 49800b1.

📒 Files selected for processing (2)
  • features/ability.feature
  • src/Ability_Command.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • features/ability.feature

Comment thread src/Ability_Command.php
claude added 2 commits August 9, 2026 15:26
Declaring `options: true/false` on `--public` and `--show-in-rest` lets
WP-CLI reject bad values in `Subcommand::validate_args()` before the
command runs, which is how `--format` in this same command already works.
That covers everything `parse_bool_filter()` was doing by hand, including
the empty-value case, so the helper and `filter_var()` both go away.

The accepted set narrows to `true` and `false`. `1`/`0`, `yes`/`no`,
`on`/`off` and the `--no-` prefix are no longer accepted -- `--no-public`
in particular now errors, since WP-CLI's loose `in_array()` check does
not match boolean false against the options list. The bare `--public`
form does still pass validation as boolean true, so the comparison
handles it explicitly rather than silently matching nothing.

Errors now come from WP-CLI in its standard form:

    Error: Parameter errors:
     Invalid value specified for 'public' (...)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0162D8GNP2TsQyHUQKNoQv3a
`[--public]` and `[--show-in-rest]` are boolean flags, which is how
WP-CLI models these. `Utils\get_flag_value()` then returns true for
`--public`, false for `--no-public`, and null when absent, so the filter
is a direct boolean comparison with no parsing, no validation code, and
no `options` block in the synopsis.

Removes the invalid-value scenario along with the parsing it covered, and
switches the existing `--show-in-rest=true|false` scenario to the flag
form.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0162D8GNP2TsQyHUQKNoQv3a
@swissspidy
swissspidy merged commit 2daaf82 into main Aug 9, 2026
50 of 51 checks passed
@swissspidy
swissspidy deleted the claude/ability-command-issue-review-qe4bvi branch August 9, 2026 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

command:ability Related to 'ability' command

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for new meta.public flag

3 participants