diff --git a/lib/endpoints/class-wp-rest-post-statuses-controller.php b/lib/endpoints/class-wp-rest-post-statuses-controller.php index 79a399c1db..9385d43f4f 100755 --- a/lib/endpoints/class-wp-rest-post-statuses-controller.php +++ b/lib/endpoints/class-wp-rest-post-statuses-controller.php @@ -25,6 +25,7 @@ public function register_routes() { array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), + 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), @@ -41,21 +42,52 @@ public function register_routes() { */ public function get_items( $request ) { $data = array(); - if ( is_user_logged_in() ) { - $statuses = get_post_stati( array( 'internal' => false ), 'object' ); - } else { - $statuses = get_post_stati( array( 'public' => true ), 'object' ); - } - foreach ( $statuses as $obj ) { - $status = $this->prepare_item_for_response( $obj, $request ); - if ( is_wp_error( $status ) ) { + $statuses = get_post_stati( array( 'internal' => false ), 'object' ); + $statuses['trash'] = get_post_status_object( 'trash' ); + foreach ( $statuses as $slug => $obj ) { + $ret = $this->check_read_permission( $obj ); + if ( ! $ret ) { continue; } + $status = $this->prepare_item_for_response( $obj, $request ); $data[ $obj->name ] = $this->prepare_response_for_collection( $status ); } return rest_ensure_response( $data ); } + public function get_item_permissions_check( $request ) { + $status = get_post_status_object( $request['status'] ); + if ( empty( $status ) ) { + return new WP_Error( 'rest_status_invalid', __( 'Invalid resource.' ), array( 'status' => 404 ) ); + } + $check = $this->check_read_permission( $status ); + if ( ! $check ) { + return new WP_Error( 'rest_cannot_read_status', __( 'Cannot view resource.' ), array( 'status' => rest_authorization_required_code() ) ); + } + return true; + } + + /** + * Check whether a given post status should be visible + * + * @param object $status + * @return boolean + */ + protected function check_read_permission( $status ) { + if ( true === $status->public ) { + return true; + } + if ( false === $status->internal || 'trash' === $status->name ) { + $types = get_post_types( array( 'show_in_rest' => true ), 'objects' ); + foreach ( $types as $type ) { + if ( current_user_can( $type->cap->edit_posts ) ) { + return true; + } + } + } + return false; + } + /** * Get a specific post status * @@ -79,9 +111,6 @@ public function get_item( $request ) { * @return WP_REST_Response Post status data */ public function prepare_item_for_response( $status, $request ) { - if ( ( false === $status->public && ! is_user_logged_in() ) || ( true === $status->internal && is_user_logged_in() ) ) { - return new WP_Error( 'rest_cannot_read_status', __( 'Cannot view resource.' ), array( 'status' => rest_authorization_required_code() ) ); - } $data = array( 'name' => $status->label, diff --git a/tests/test-rest-post-statuses-controller.php b/tests/test-rest-post-statuses-controller.php index b5918e9a6a..86877e1ffb 100644 --- a/tests/test-rest-post-statuses-controller.php +++ b/tests/test-rest-post-statuses-controller.php @@ -30,27 +30,28 @@ public function test_get_items() { $data = $response->get_data(); $statuses = get_post_stati( array( 'public' => true ), 'objects' ); $this->assertEquals( 1, count( $data ) ); - // Check each key in $data against those in $statuses - foreach ( $data as $key => $obj ) { - $this->assertEquals( $statuses[ $obj['slug'] ]->name, $key ); - $this->check_post_status_obj( $statuses[ $obj['slug'] ], $obj ); - } + $this->assertEquals( 'publish', $data['publish']['slug'] ); + $this->assertFalse( $data['publish']['private'] ); + $this->assertTrue( $data['publish']['public'] ); } public function test_get_items_logged_in() { - $user_id = $this->factory->user->create(); + $user_id = $this->factory->user->create( array( 'role' => 'author' ) ); wp_set_current_user( $user_id ); $request = new WP_REST_Request( 'GET', '/wp/v2/statuses' ); $response = $this->server->dispatch( $request ); $data = $response->get_data(); - $statuses = get_post_stati( array( 'internal' => false ), 'objects' ); - $this->assertEquals( 5, count( $data ) ); - // Check each key in $data against those in $statuses - foreach ( $data as $obj ) { - $this->check_post_status_obj( $statuses[ $obj['slug'] ], $obj ); - } + $this->assertEquals( 6, count( $data ) ); + $this->assertEqualSets( array( + 'publish', + 'private', + 'pending', + 'draft', + 'trash', + 'future', + ), array_keys( $data ) ); } public function test_get_item() {