Skip to content

Comments: Add a capabilities object to comment types#52

Open
adamsilverstein wants to merge 5 commits into
feature/register-comment-typefrom
feature/comment-type-caps
Open

Comments: Add a capabilities object to comment types#52
adamsilverstein wants to merge 5 commits into
feature/register-comment-typefrom
feature/comment-type-caps

Conversation

@adamsilverstein

@adamsilverstein adamsilverstein commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Description

Adds a capabilities object to comment types, modeled on WP_Post_Type and get_post_type_capabilities(). Registered comment types can now describe their own read/edit/delete/moderate capabilities, which is a prerequisite for per-type permission handling on the #35214 tracking ticket (and for exposing capabilities through the REST endpoint).

What it adds

  • A capability_type registration argument (default 'comment'; may be an array like array( 'story', 'stories' ) for an explicit plural).
  • A capabilities registration argument to override individual generated capabilities.
  • A WP_Comment_Type::$cap object, built by the new get_comment_type_capabilities() helper.
register_comment_type( 'review', array( 'capability_type' => 'review' ) );

$obj = get_comment_type_object( 'review' );
$obj->cap->edit_comments;      // 'edit_reviews'
$obj->cap->moderate_comments;  // 'moderate_reviews'
$obj->cap->edit_comment;       // 'edit_review' (meta cap)

Non-breaking by design

Within this PR the capabilities are advisory metadata only: map_meta_cap() is left unchanged here, so this PR on its own causes no behavior change to comment moderation or editing. The built-in comment type resolves to the existing edit_comment (meta) and moderate_comments (primitive) capabilities, so current behavior is preserved exactly.

Wiring these capabilities into map_meta_cap() enforcement was deliberately split out so the capability model could be reviewed before touching the live permission path. That follow-up now exists: the next PR in the stack (#55) enforces these capabilities in map_meta_cap() and rewrites the capability docblocks to describe the live model.

Scope / boundary

Stacked on WordPress#12311 (the register_comment_type() API) and targets that branch; it will be retargeted to trunk once WordPress#12311 lands. Complements the REST endpoint (#51, also stacked on WordPress#12311) and the default_excluded_comment_types query filter (WordPress#12310 / #65537).

Testing

$ phpunit --group comment
OK (590 tests, 1459 assertions)

Capability/meta-cap suites also pass unchanged (753 tests), confirming no enforcement-path regression. PHPCS and PHPStan are clean on the changed files.

Review updates

  • The docs now state that with the default capability_type most of the generated primitive capabilities exist in no default role; consumers should check the meta capabilities with a comment ID and let map_meta_cap() resolve them.
  • get_comment_type_capabilities() gained a per-capability @return reference and a note that it normalizes capability_type as a side effect.

See #35214.

@github-actions

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props adamsilverstein.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 48e42292-d8bd-4fcc-ad18-62bbff5acc74

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/comment-type-caps

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.

@adamsilverstein

Copy link
Copy Markdown
Owner Author

Follow-up: capability enforcement via map_meta_cap()

This PR intentionally keeps the cap object advisory. Proposing the lowest-risk path to actual enforcement, mirroring register_post_type():

  • Opt-in. Default capability_type => 'comment' stays byte-for-byte identical (editing still derives from the parent post's edit_post; moderation still uses the moderate_comments primitive). Only types declaring a non-default capability_type / explicit capabilities route through the new handling.
  • Map, don't grant. New per-type meta caps (read_comment / edit_comment / delete_comment / moderate_comment) map to the type's primitives via map_meta_cap(); sites grant the primitives to roles, exactly as with custom post types. No role (admin included) is silently locked out because the default path is unchanged.
  • Stage the call-site rerouting (edit → moderation → delete) instead of one audit-heavy change, so each surface gets a focused security review.

One question to settle before coding: do custom comment types keep deriving edit permission from the parent post, or get a permission boundary independent of it? That is the substantive design fork (the comment:19 concern). Happy to write this up on Trac #35214 if the direction looks right.

Give `WP_Comment_Type` a `cap` object built from new `capability_type` and
`capabilities` registration arguments, modeled on `WP_Post_Type` and
`get_post_type_capabilities()`. A new `get_comment_type_capabilities()` helper
builds the capability strings from the `capability_type` base (default
'comment'), so a registered type can describe its own read, edit, delete, and
moderate capabilities.

This is advisory metadata only: `map_meta_cap()` is intentionally not changed,
so there is no behavior change. The built-in `comment` type resolves to the
existing `edit_comment` and `moderate_comments` capabilities, preserving current
behavior. Enforcing per-type capabilities through `map_meta_cap()` is left to a
follow-up so the capability model can be agreed on first.

See #35214.
Cover the new `capability_type`/`capabilities` arguments and the
`get_comment_type_capabilities()` helper: default and custom capability types,
array capability types with explicit plurals, the `capabilities` override, that
the input `capabilities` array is not retained as a property, and that the
built-in `comment` type stays backward compatible with the existing core
capabilities.

See #35214.
The existing tests spot-checked individual generated capabilities;
read_comment, moderate_comment, and delete_comments were never asserted.
Add a test pinning the complete meta and primitive capability set built
by get_comment_type_capabilities() from a string base, plus a direct
test of the array capability_type form (explicit plural).

See #35214.
@adamsilverstein adamsilverstein force-pushed the feature/comment-type-caps branch from d2ee949 to c4978f3 Compare June 25, 2026 06:32
…e-caps

# Conflicts:
#	src/wp-includes/class-wp-comment-type.php
#	src/wp-includes/comment.php
#	tests/phpunit/tests/comment/types.php
- Document that with the default 'comment' capability_type, most
  generated primitive capabilities exist in no default role and are not
  consulted by the default mapping: consumers should check meta
  capabilities with a comment ID, not the primitives.
- Add the per-capability @return reference to
  get_comment_type_capabilities() (mirroring the post type version) and
  note that it normalizes the passed object's capability_type as a side
  effect.
- Type WP_Comment_Type::$capability_type as string: set_props()
  collapses the array registration form to the singular base.
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