Repository navigation
Comments: Enforce registered comment type capabilities in map_meta_cap() (Trac #35214) - #55
adamsilverstein wants to merge 14 commits into
Conversation
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.
…ap()`. The capabilities object added for comment types was advisory only; `map_meta_cap()` knew a single comment cap (`edit_comment`, derived from the parent post) and all moderation ran through a bare `moderate_comments` primitive check. Wire the cap object into `map_meta_cap()` so a registered type can enforce its own permissions, supporting both models: - Types using the default `comment` capability model are unchanged. Their mapped `edit_comment` is the generic meta cap, so editing and deletion still derive from the comment's parent post and moderation still requires the global `moderate_comments` primitive. - A type that opts into its own `capability_type`/`capabilities` is gated by its own primitives (e.g. `moderate_reviews`, `edit_others_reviews`), mirroring how registered post types map `edit_post`. Caps are mapped, not granted: sites assign the primitives to roles, so nothing is silently escalated or locked out. Generalize the `edit_comment` case and add `delete_comment` and `moderate_comment` meta caps. `read_comment` is deferred: the cap object has no read primitive and approved comments are publicly readable, so gating reads needs its own design. See #35214.
Cover both capability models in `map_meta_cap()`: the default `comment` model still derives edit/delete from the parent post (including the orphaned comment fallback) and moderation from `moderate_comments`, while a type with an independent `capability_type` is gated by its own primitives with no fallback to the default caps. Register `delete_comment` and `moderate_comment` in the meta-capability coverage list. See #35214.
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. Props Bot commandsYou can trigger Props Bot actions by commenting on this PR:
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the
|
d2ee949 to
c4978f3
Compare
…ature/comment-type-cap-enforcement # Conflicts: # tests/phpunit/tests/comment/types.php
current_user_can( 'edit_review', $comment_id ) - the idiom developers know from custom post types, and the exact names the capability object advertises - previously fell through map_meta_cap()'s default case to a literal primitive check that ignored the comment ID and the own/others split. Mirror _post_type_meta_capabilities(): remember each type's custom edit_comment/delete_comment/moderate_comment names and translate them in the default case. read_comment is deliberately excluded until a corresponding case exists. - Guard against claiming names already registered as post type meta capabilities (those take precedence); reject with _doing_it_wrong(). - Remove a type's translations in unregister_comment_type(), mirroring the post type cleanup, and reset the registry between tests. - Consolidate the three map_meta_cap() comment cases into one fall-through block with a single, documented model-detection point (overriding a singular meta capability opts that action into the independent model), and note that the independent model deliberately ignores the parent post. - Rewrite the 'advisory only' capability docblocks from the caps PR to describe the live model, including the mixed-model and empty capability_type footguns, and add map_meta_cap()'s @SInCE entry. - Tests: legacy empty-string types across all three meta caps, orphaned independent comments, invalid and missing IDs, anonymous own/others, array capability_type end to end, single-override model flips, register/unregister fallback, trashed parents, custom-name translation, and the post type collision guard.
…p-enforcement # Conflicts: # tests/phpunit/includes/abstract-testcase.php
…p-enforcement # Conflicts: # tests/phpunit/includes/abstract-testcase.php
The registration API ships in 7.2.0, so the new meta capabilities and helper carried the wrong @SInCE and _doing_it_wrong() versions. The inline comments and property docs also restated the capability model at length; they now say what a reader needs and leave the rationale to the ticket.
Matches the typing used across the rest of the comment type tests and keeps the file clean under PHPStan level 10.
A plugin passing a non-string value in the 'capabilities' argument made _comment_type_meta_capabilities() use it as an array key, which throws a TypeError on PHP 8. Only string names are stored now, and only the three translatable meta capabilities are read, so the helper takes the merged array directly instead of a cast object. Also corrects the @SInCE and _doing_it_wrong() versions to 7.2.0 and drops the docblock note that said map_meta_cap() resolves only edit_comment, which this branch makes untrue.
…p-enforcement # Conflicts: # src/wp-includes/class-wp-comment-type.php # src/wp-includes/comment.php
Trunk is in the 7.2 beta, so these additions can no longer ship in 7.2.0.
Stack: Custom Comment Types (#35214)
register_comment_type()registration API/wp/v2/comment-typesendpointmap_meta_cap()(this PR)render_callbackdisplay callbackis_pingping groupingdefault_excluded_comment_typesfilterwp_update_comment_counts()recount helperWordPress#12311 and WordPress#12310 are on WordPress/wordpress-develop; the rest are fork PRs targeting their parent branch and will retarget to trunk as their base lands.
Claude dug through the cap mapping again and wrote this up:
Trac ticket: https://core.trac.wordpress.org/ticket/35214
AI Use
Claude wrote this code and description with some careful prompting. I will review and test.