diff --git a/src/wp-includes/capabilities.php b/src/wp-includes/capabilities.php index eb6b3bbace..e6d16e927a 100644 --- a/src/wp-includes/capabilities.php +++ b/src/wp-includes/capabilities.php @@ -72,11 +72,8 @@ function map_meta_cap( $cap, $user_id, ...$args ) { } if ( 'revision' == $post->post_type ) { - $post = get_post( $post->post_parent ); - if ( ! $post ) { - $caps[] = 'do_not_allow'; - break; - } + $caps[] = 'do_not_allow'; + break; } if ( ( get_option( 'page_for_posts' ) == $post->ID ) || ( get_option( 'page_on_front' ) == $post->ID ) ) { diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php index 1b34619130..0a0a88106b 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php @@ -349,6 +349,11 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller { return $parent; } + $parent_post_type = get_post_type_object( $parent->post_type ); + if ( ! current_user_can( $parent_post_type->cap->delete_post, $parent->ID ) ) { + return new WP_Error( 'rest_cannot_delete', __( 'Sorry, you are not allowed to delete revisions of this post.' ), array( 'status' => rest_authorization_required_code() ) ); + } + $revision = $this->get_revision( $request['id'] ); if ( is_wp_error( $revision ) ) { return $revision; @@ -383,7 +388,12 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller { } $post_type = get_post_type_object( 'revision' ); - return current_user_can( $post_type->cap->delete_post, $revision->ID ); + + if ( ! current_user_can( $post_type->cap->delete_post, $revision->ID ) ) { + return new WP_Error( 'rest_cannot_delete', __( 'Sorry, you are not allowed to delete this revision.' ), array( 'status' => rest_authorization_required_code() ) ); + } + + return true; } /** diff --git a/tests/phpunit/tests/rest-api/rest-revisions-controller.php b/tests/phpunit/tests/rest-api/rest-revisions-controller.php index f9497845ce..655d675f49 100644 --- a/tests/phpunit/tests/rest-api/rest-revisions-controller.php +++ b/tests/phpunit/tests/rest-api/rest-revisions-controller.php @@ -76,6 +76,27 @@ class WP_Test_REST_Revisions_Controller extends WP_Test_REST_Controller_Testcase $this->revision_id3 = $this->revision_3->ID; } + public function tearDown() { + parent::tearDown(); + + remove_filter( 'map_meta_cap', array( $this, '_filter_map_meta_cap_remove_no_allow_revisions' ) ); + } + + public function _filter_map_meta_cap_remove_no_allow_revisions( $caps, $cap, $user_id, $args ) { + if ( 'delete_post' !== $cap || empty( $args ) ) { + return $caps; + } + $post = get_post( $args[0] ); + if ( ! $post || 'revision' !== $post->post_type ) { + return $caps; + } + $key = array_search( 'do_not_allow', $caps, true ); + if ( false !== $key ) { + unset( $caps[ $key ] ); + } + return $caps; + } + public function test_register_routes() { $routes = rest_get_server()->get_routes(); $this->assertArrayHasKey( '/wp/v2/posts/(?P[\d]+)/revisions', $routes ); @@ -216,13 +237,32 @@ class WP_Test_REST_Revisions_Controller extends WP_Test_REST_Controller_Testcase $request = new WP_REST_Request( 'DELETE', '/wp/v2/posts/' . self::$post_id . '/revisions/' . $this->revision_id1 ); $request->set_param( 'force', true ); $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_cannot_delete', $response, 403 ); + $this->assertNotNull( get_post( $this->revision_id1 ) ); + } + + public function test_delete_item_remove_do_not_allow() { + wp_set_current_user( self::$editor_id ); + add_filter( 'map_meta_cap', array( $this, '_filter_map_meta_cap_remove_no_allow_revisions' ), 10, 4 ); + $request = new WP_REST_Request( 'DELETE', '/wp/v2/posts/' . self::$post_id . '/revisions/' . $this->revision_id1 ); + $request->set_param( 'force', true ); + $response = rest_get_server()->dispatch( $request ); $this->assertEquals( 200, $response->get_status() ); $this->assertNull( get_post( $this->revision_id1 ) ); } + public function test_delete_item_cannot_delete_parent() { + wp_set_current_user( self::$editor_id ); + $request = new WP_REST_Request( 'DELETE', '/wp/v2/posts/' . self::$post_id . '/revisions/' . $this->revision_id1 ); + $request->set_param( 'force', true ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_cannot_delete', $response, 403 ); + $this->assertNotNull( get_post( $this->revision_id1 ) ); + } + public function test_delete_item_no_trash() { wp_set_current_user( self::$editor_id ); - + add_filter( 'map_meta_cap', array( $this, '_filter_map_meta_cap_remove_no_allow_revisions' ), 10, 4 ); $request = new WP_REST_Request( 'DELETE', '/wp/v2/posts/' . self::$post_id . '/revisions/' . $this->revision_id1 ); $response = rest_get_server()->dispatch( $request ); $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501 );