Make WordPress Core

Opened 6 weeks ago

Last modified 6 weeks ago

#65761 new defect (bug)

REST comments: wrong error when a status is sent with no post

Reported by: ramonopoly Owned by:
Priority: normal Milestone: 7.2
Component: REST API Version: 6.9
Severity: minor Keywords: has-patch has-unit-tests
Cc: Focuses:

Description (last modified by ramonopoly)

REST comments: wrong error when a status is sent with no post

WP_REST_Comments_Controller::create_item_permissions_check() checks whether the
user may set status before it checks that a post was given. A user without
moderate_comments who posts a status and no post gets
rest_comment_invalid_status ("not allowed to edit 'status'") when the real
problem is the missing post, which the guard below reports accurately as
rest_comment_invalid_post_id.

To reproduce:

The dividing line is the moderate_comments capability, so Subscriber, Contributor and Author all behave identically. Use Author, because it can open the block editor and so gives you a console with wp.apiFetch available.

  1. As an Author, create and publish a post and stay in its block editor.
  2. In the console, run a create with a status and no post:
wp.apiFetch( {
	path: '/wp/v2/comments',
	method: 'POST',
	data: { content: 'YOLO', status: 'approved' },
} ).then( console.log ).catch( console.log );

Returns 403 rest_comment_invalid_status, "Sorry, you are not allowed to edit
'status' for comments". The real problem is the missing post.

Fix: move the empty( $request['post'] ) guard above the $edit_cap check.
No test covers this combination today, so the reorder needs one.

Change History (2)

This ticket was mentioned in PR #12764 on WordPress/wordpress-develop by @ramonopoly.


6 weeks ago
#1

  • Keywords has-patch has-unit-tests added

## 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.

## Testing instructions

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

wp.apiFetch( {
        path: '/wp/v2/comments',
        method: 'POST',
        data: { content: 'SUBSCRIBER_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
    }
}

*/

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
    }
}

*/

Tests

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

#2 @ramonopoly
6 weeks ago

  • Description modified (diff)
Note: See TracTickets for help on using tickets.