Comments: Enforce registered comment type capabilities in map_meta_cap() (Trac #35214)#55
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. You can also manually ask me to refresh this list by adding the 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. |
|
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 ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
d2ee949 to
c4978f3
Compare
Summary
Follow-up to PR #52 (the advisory cap object), implementing Stages 1-2 of the enforcement plan: wiring
WP_Comment_Type::$capintomap_meta_cap(). Per discussion this supports both models.Before this, the cap object was advisory:
map_meta_cap()only knewedit_comment(derived from the parent post) and all moderation was a baremoderate_commentsprimitive check at each call site.What changed (
map_meta_cap()only - no call-site reroutes yet)edit_commentgeneralized. A comment whose type uses the defaultcommentcapability model (its mappededit_commentis the generic meta cap) still derives edit permission from the parent post - byte-for-byte unchanged, orphaned-comment fallback included. A type that opts into its own caps maps toedit_comments(own) /edit_others_comments(others) byuser_id, mirroringedit_post.delete_commentadded. Default model follows the parent post (matching how core's delete flows gate onedit_commenttoday); independent model maps todelete_comments.moderate_commentadded. Default model requires the globalmoderate_commentsprimitive; independent model maps to the type'smoderate_comments(e.g.moderate_reviews).Design: supports both, maps don't grant
capability_type => 'comment'is unchanged. Built-incomment/pingback/trackback/noteall resolve exactly as today, so no role (admin included) is affected.cap->edit_comment === 'edit_comment'), which also avoids any self-recursion.Deferred
read_comment- the Comments: Add a capabilities object to comment types #52 cap object has no read primitive, and approved comments are publicly readable, so gating reads needs its own design.wp_set_comment_status(), admincomment.php+ list-table, REST permission callbacks, AJAX handlers - lands as small per-surface PRs so each gets a focused security review. This PR is intentionallymap_meta_cap()-only.Testing
New
tests/phpunit/tests/comment/commentCapabilities.php:moderate_comments.reviewtype: amoderate_reviewsuser can moderate reviews but not default comments, and an administrator (hasmoderate_comments, notmoderate_reviews) is the exact inverse - proving independence and the no-auto-grant rule.Registered the two new meta caps in the core meta-cap coverage list (
tests/phpunit/tests/user/capabilities.php). Full--group comment --group capabilitiessuite passes (797 tests). PHPCS + PHPStan clean.Stacking
Based on
feature/comment-type-caps(#52). Retarget totrunkonce the registration (#12311) and cap-object PRs land.See #35214.