Skip to content

REST API: Check for a missing post before the comment status capability. - #12764

Open
ramonjd wants to merge 2 commits into
WordPress:trunkfrom
ramonjd:fix/comments-rest-error-mismatch
Open

REST API: Check for a missing post before the comment status capability.#12764
ramonjd wants to merge 2 commits into
WordPress:trunkfrom
ramonjd:fix/comments-rest-error-mismatch

Conversation

@ramonjd

@ramonjd ramonjd commented Jul 30, 2026

Copy link
Copy Markdown
Member

What

WP_REST_Comments_Controller::create_item_permissions_check() checks whether the caller is allowed to set the status parameter before it checks that a post was supplied at all. A request that carries a status but no post is therefore rejected with rest_comment_invalid_status, "Sorry, you are not allowed to edit 'status' for comments", which points at the wrong parameter. The actual problem is the missing post.

This moves the missing-post guard above the status capability check. It is a pure move of about seven lines; no logic changes.

Trac ticket: https://core.trac.wordpress.org/ticket/65761

Why the wrong error appears

The status check consults moderate_comments for ordinary comments. An Administrator has it, so the check passes and execution reaches the missing-post guard, producing the correct error. A Subscriber, Contributor or Author does not, so it stops one guard early and reports the status problem instead. That asymmetry between roles is the bug.

Behaviour changes

The reorder flips the reported error code in two situations. Both remain HTTP 403 and both remain rejected. Only the reason changes.

Request Before After
status set, no post, caller lacks moderate_comments rest_comment_invalid_status rest_comment_invalid_post_id
type: note, status set, no post, any caller rest_comment_invalid_status rest_comment_invalid_post_id

The second row is easy to miss. For a note, $edit_cap becomes array( 'edit_post', (int) $request['post'] ), which is array( 'edit_post', 0 ) when no post is supplied. map_meta_cap() returns do_not_allow for edit_post whenever get_post() finds nothing, so that check failed for every caller, including Administrators, before this change.

Because a response code changes, this belongs in a major release rather than a point release, hence 7.2.

Testing instructions

To check by hand, as an Author with a published post open in the block editor:

wp.apiFetch( {
	path: '/wp/v2/comments',
	method: 'POST',
	data: { content: 'AUTHOR_YOLO', status: 'approved' },
} ).then( console.log ).catch( console.log );

/*

// Before


{
    "code": "rest_comment_invalid_status",
    "message": "Sorry, you are not allowed to edit 'status' for comments.",
    "data": {
        "status": 403
    }
}


// After

{
    "code": "rest_comment_invalid_post_id",
    "message": "Sorry, you are not allowed to create this comment without a post.",
    "data": {
        "status": 403
    }
}

*/

Still as an Author, check that you get the right "status" error when you do provide a post id:

const post = wp.data.select( 'core/editor' ).getCurrentPostId();
wp.apiFetch( { path: '/wp/v2/comments', method: 'POST', data: { post, content: 'happy path', status: 'approved' } } ).then( console.log ).catch( console.log );

/*

{
    "code": "rest_comment_invalid_status",
    "message": "Sorry, you are not allowed to edit 'status' for comments.",
    "data": {
        "status": 403
    }
}

*/

Then do a happy path as an Admin in a post:

const post = wp.data.select( 'core/editor' ).getCurrentPostId();
wp.apiFetch( {
	path: '/wp/v2/comments',
	method: 'POST',
	data: { post, content: 'happy path', status: 'approved' },
} ).then( console.log ).catch( console.log );

/*
Expect 201 with "status": "approved"
*/

Tests

npm run test:php -- --filter WP_Test_REST_Comments_Controller
npm run test:php -- --group comment

`WP_REST_Comments_Controller::create_item_permissions_check()` checked whether
the user is allowed to set `status` before checking that a `post` was supplied
at all. A request carrying a status but no post was therefore rejected as
`rest_comment_invalid_status`, which points at the wrong parameter.

Move the missing-post guard above the status capability check so the missing
post is reported as such.

Fixes #65761.
Copilot AI review requested due to automatic review settings July 30, 2026 06:04
@github-actions

github-actions Bot commented Jul 30, 2026

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 ramonopoly, andrewserong, mukesh27.

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

Copilot AI 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.

🟡 Not ready to approve

The reordered guard also changes behaviour for type=note requests with status and no post, but there is no regression test covering that case.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

This PR adjusts WP_REST_Comments_Controller::create_item_permissions_check() to validate that a post is provided before performing the capability check for the status parameter, ensuring the API returns an error that correctly points to the missing post parameter. It also adds a PHPUnit regression test to confirm the corrected error code for a user who cannot set status.

Changes:

  • Reordered the “missing post” guard to run before the status capability check in comment creation permissions.
  • Added a REST API PHPUnit test asserting rest_comment_invalid_post_id when status is provided but post is missing for a non-privileged user.
File summaries
File Description
src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php Moves the missing-post check earlier so the REST API reports the correct parameter error.
tests/phpunit/tests/rest-api/rest-comments-controller.php Adds regression coverage for the missing-post + status scenario (non-note).
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Low

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

@ramonjd ramonjd self-assigned this Jul 30, 2026
@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

Notes resolve the status capability against `edit_post` with the submitted post
ID. With no post that becomes `current_user_can( 'edit_post', 0 )`, which
`map_meta_cap()` denies for every role, so the missing post was reported as a
status error for all callers including administrators.

Cover the note variant so the guard order stays put.

See #65761.
Copilot AI review requested due to automatic review settings July 30, 2026 06:18

Copilot AI 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.

🟢 Ready to approve

The change is a small, well-scoped reorder aligned with the Trac report and is backed by targeted new tests.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Review details

Comments suppressed due to low confidence (1)

tests/phpunit/tests/rest-api/rest-comments-controller.php:3847

  • The docblock describes runtime behavior that is no longer true after this change: with the new early empty( $request['post'] ) guard, the status capability check is never reached when no post is supplied, so it doesn't "fall back" to current_user_can( 'edit_post', 0 ) anymore. Reword to past/conditional tense to avoid misleading future readers.
	 * Without a post, the `status` capability check falls back to
	 * `current_user_can( 'edit_post', 0 )`, which no role can satisfy. An
	 * administrator is used here to show the missing post is reported even for a
	 * user holding every capability.
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Low

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

@andrewserong andrewserong 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.

Good catch, and thank you for the thorough testing instructions. This patch is testing well, with the expected error messages now for an author user, and the happy path for an admin unchanged.

LGTM!

@mukeshpanchal27 mukeshpanchal27 added the props-bot Adding this label triggers the Props Bot workflow for a PR. label Jul 31, 2026
@github-actions github-actions Bot removed the props-bot Adding this label triggers the Props Bot workflow for a PR. label Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants