Ticket #45098: 45098.diff
| File 45098.diff, 38.2 KB (added by , 7 years ago) |
|---|
-
src/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php
1 <?php 2 /** 3 * Block Renderer REST API: WP_REST_Block_Renderer_Controller class 4 * 5 * @package WordPress 6 * @subpackage REST_API 7 * @since 5.0.0 8 */ 9 10 /** 11 * Controller which provides REST endpoint for rendering a block. 12 * 13 * @since 5.0.0 14 * 15 * @see WP_REST_Controller 16 */ 17 class WP_REST_Block_Renderer_Controller extends WP_REST_Controller { 18 19 /** 20 * Constructs the controller. 21 * 22 * @since 5.0.0 23 */ 24 public function __construct() { 25 $this->namespace = 'wp/v2'; 26 $this->rest_base = 'block-renderer'; 27 } 28 29 /** 30 * Registers the necessary REST API routes, one for each dynamic block. 31 * 32 * @since 5.0.0 33 */ 34 public function register_routes() { 35 $block_types = WP_Block_Type_Registry::get_instance()->get_all_registered(); 36 37 foreach ( $block_types as $block_type ) { 38 if ( ! $block_type->is_dynamic() ) { 39 continue; 40 } 41 42 register_rest_route( 43 $this->namespace, 44 '/' . $this->rest_base . '/(?P<name>' . $block_type->name . ')', 45 array( 46 'args' => array( 47 'name' => array( 48 'description' => __( 'Unique registered name for the block.' ), 49 'type' => 'string', 50 ), 51 ), 52 array( 53 'methods' => WP_REST_Server::READABLE, 54 'callback' => array( $this, 'get_item' ), 55 'permission_callback' => array( $this, 'get_item_permissions_check' ), 56 'args' => array( 57 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 58 'attributes' => array( 59 /* translators: %s is the name of the block */ 60 'description' => sprintf( __( 'Attributes for %s block' ), $block_type->name ), 61 'type' => 'object', 62 'additionalProperties' => false, 63 'properties' => $block_type->get_attributes(), 64 ), 65 'post_id' => array( 66 'description' => __( 'ID of the post context.' ), 67 'type' => 'integer', 68 ), 69 ), 70 ), 71 'schema' => array( $this, 'get_public_item_schema' ), 72 ) 73 ); 74 } 75 } 76 77 /** 78 * Checks if a given request has access to read blocks. 79 * 80 * @since 5.0.0 81 * 82 * @param WP_REST_Request $request Request. 83 * @return true|WP_Error True if the request has read access, WP_Error object otherwise. 84 */ 85 public function get_item_permissions_check( $request ) { 86 global $post; 87 88 $post_id = isset( $request['post_id'] ) ? intval( $request['post_id'] ) : 0; 89 90 if ( 0 < $post_id ) { 91 $post = get_post( $post_id ); 92 93 if ( ! $post || ! current_user_can( 'edit_post', $post->ID ) ) { 94 return new WP_Error( 95 'gutenberg_block_cannot_read', 96 __( 'Sorry, you are not allowed to read Gutenberg blocks of this post' ), 97 array( 98 'status' => rest_authorization_required_code(), 99 ) 100 ); 101 } 102 } else { 103 if ( ! current_user_can( 'edit_posts' ) ) { 104 return new WP_Error( 105 'gutenberg_block_cannot_read', 106 __( 'Sorry, you are not allowed to read Gutenberg blocks as this user.' ), 107 array( 108 'status' => rest_authorization_required_code(), 109 ) 110 ); 111 } 112 } 113 114 return true; 115 } 116 117 /** 118 * Returns block output from block's registered render_callback. 119 * 120 * @since 5.0.0 121 * 122 * @param WP_REST_Request $request Full details about the request. 123 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 124 */ 125 public function get_item( $request ) { 126 global $post; 127 128 $post_id = isset( $request['post_id'] ) ? intval( $request['post_id'] ) : 0; 129 130 if ( 0 < $post_id ) { 131 $post = get_post( $post_id ); 132 133 // Set up postdata since this will be needed if post_id was set. 134 setup_postdata( $post ); 135 } 136 $registry = WP_Block_Type_Registry::get_instance(); 137 $block = $registry->get_registered( $request['name'] ); 138 139 if ( null === $block ) { 140 return new WP_Error( 141 'gutenberg_block_invalid', 142 __( 'Invalid block.' ), 143 array( 144 'status' => 404, 145 ) 146 ); 147 } 148 149 $data = array( 150 'rendered' => $block->render( $request->get_param( 'attributes' ) ), 151 ); 152 return rest_ensure_response( $data ); 153 } 154 155 /** 156 * Retrieves block's output schema, conforming to JSON Schema. 157 * 158 * @since 5.0.0 159 * 160 * @return array Item schema data. 161 */ 162 public function get_item_schema() { 163 return array( 164 '$schema' => 'http://json-schema.org/schema#', 165 'title' => 'rendered-block', 166 'type' => 'object', 167 'properties' => array( 168 'rendered' => array( 169 'description' => __( 'The rendered block.' ), 170 'type' => 'string', 171 'required' => true, 172 'context' => array( 'edit' ), 173 ), 174 ), 175 ); 176 } 177 } -
src/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php
1 <?php 2 /** 3 * Reusable blocks REST API: WP_REST_Blocks_Controller class 4 * 5 * @package WordPress 6 * @subpackage REST_API 7 * @since 5.0.0 8 */ 9 10 /** 11 * Controller which provides a REST endpoint for Gutenberg to read, create, 12 * edit and delete reusable blocks. Blocks are stored as posts with the wp_block 13 * post type. 14 * 15 * @since 5.0.0 16 * 17 * @see WP_REST_Posts_Controller 18 * @see WP_REST_Controller 19 */ 20 class WP_REST_Blocks_Controller extends WP_REST_Posts_Controller { 21 /** 22 * Checks if a block can be read. 23 * 24 * @since 5.0.0 25 * 26 * @param object $post Post object that backs the block. 27 * @return bool Whether the block can be read. 28 */ 29 public function check_read_permission( $post ) { 30 // Ensure that the user is logged in and has the read_blocks capability. 31 $post_type = get_post_type_object( $post->post_type ); 32 if ( ! current_user_can( $post_type->cap->read_post, $post->ID ) ) { 33 return false; 34 } 35 36 return parent::check_read_permission( $post ); 37 } 38 39 /** 40 * Handle a DELETE request. 41 * 42 * @since 5.0.0 43 * 44 * @param WP_REST_Request $request Full details about the request. 45 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 46 */ 47 public function delete_item( $request ) { 48 // Always hard-delete a block. 49 $request->set_param( 'force', true ); 50 51 return parent::delete_item( $request ); 52 } 53 54 /** 55 * Given an update or create request, build the post object that is saved to 56 * the database. 57 * 58 * @since 5.0.0 59 * 60 * @param WP_REST_Request $request Request object. 61 * @return stdClass|WP_Error Post object or WP_Error. 62 */ 63 public function prepare_item_for_database( $request ) { 64 $prepared_post = parent::prepare_item_for_database( $request ); 65 66 // Force blocks to always be published. 67 $prepared_post->post_status = 'publish'; 68 69 return $prepared_post; 70 } 71 72 /** 73 * Given a block from the database, build the array that is returned from an 74 * API response. 75 * 76 * @since 5.0.0 77 * 78 * @param WP_Post $post Post object that backs the block. 79 * @param WP_REST_Request $request Request object. 80 * @return WP_REST_Response Response object. 81 */ 82 public function prepare_item_for_response( $post, $request ) { 83 $data = array( 84 'id' => $post->ID, 85 'title' => $post->post_title, 86 'content' => $post->post_content, 87 ); 88 89 $response = rest_ensure_response( $data ); 90 91 return apply_filters( "rest_prepare_{$this->post_type}", $response, $post, $request ); 92 } 93 94 /** 95 * Builds the block's schema, conforming to JSON Schema. 96 * 97 * @since 5.0.0 98 * 99 * @return array Item schema data. 100 */ 101 public function get_item_schema() { 102 return array( 103 '$schema' => 'http://json-schema.org/schema#', 104 'title' => $this->post_type, 105 'type' => 'object', 106 'properties' => array( 107 'id' => array( 108 'description' => __( 'Unique identifier for the block.' ), 109 'type' => 'integer', 110 'readonly' => true, 111 ), 112 'title' => array( 113 'description' => __( 'The block’s title.' ), 114 'type' => 'string', 115 'required' => true, 116 ), 117 'content' => array( 118 'description' => __( 'The block’s HTML content.' ), 119 'type' => 'string', 120 'required' => true, 121 ), 122 ), 123 ); 124 } 125 } -
src/wp-includes/rest-api.php
233 233 // Settings. 234 234 $controller = new WP_REST_Settings_Controller; 235 235 $controller->register_routes(); 236 237 // Blocks. 238 $controller = new WP_REST_Block_Renderer_Controller; 239 $controller->register_routes(); 236 240 } 237 241 238 242 /** -
src/wp-settings.php
235 235 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-users-controller.php' ); 236 236 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-comments-controller.php' ); 237 237 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-settings-controller.php' ); 238 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-block-renderer-controller.php' ); 239 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-blocks-controller.php' ); 238 240 require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-meta-fields.php' ); 239 241 require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-comment-meta-fields.php' ); 240 242 require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-post-meta-fields.php' ); -
tests/phpunit/tests/rest-api/rest-block-renderer-controller.php
1 <?php 2 /** 3 * WP_REST_Block_Renderer_Controller tests. 4 * 5 * @package WordPress 6 * @subpackage REST API 7 * @since 5.0.0 8 */ 9 10 /** 11 * Tests for WP_REST_Block_Renderer_Controller. 12 * 13 * @since 5.0.0 14 * 15 * @covers WP_REST_Block_Renderer_Controller 16 * 17 * @group restapi-blocks 18 * @group restapi 19 */ 20 class REST_Block_Renderer_Controller_Test extends WP_Test_REST_Controller_Testcase { 21 /** 22 * The REST API route for the block renderer. 23 * 24 * @since 5.0.0 25 * 26 * @var string 27 */ 28 protected static $rest_api_route = '/wp/v2/block-renderer/'; 29 30 /** 31 * Test block's name. 32 * 33 * @since 5.0.0 34 * 35 * @var string 36 */ 37 protected static $block_name = 'core/test-block'; 38 39 /** 40 * Test post context block's name. 41 * 42 * @since 5.0.0 43 * 44 * @var string 45 */ 46 protected static $context_block_name = 'core/context-test-block'; 47 48 /** 49 * Test API user's ID. 50 * 51 * @since 5.0.0 52 * 53 * @var int 54 */ 55 protected static $user_id; 56 57 /** 58 * Test post ID. 59 * 60 * @since 5.0.0 61 * 62 * @var int 63 */ 64 protected static $post_id; 65 66 /** 67 * Author test user ID. 68 * 69 * @since 5.0.0 70 * 71 * @var int 72 */ 73 protected static $author_id; 74 75 /** 76 * Create test data before the tests run. 77 * 78 * @since 5.0.0 79 * 80 * @param WP_UnitTest_Factory $factory Helper that lets us create fake data. 81 */ 82 public static function wpSetUpBeforeClass( $factory ) { 83 self::$user_id = $factory->user->create( 84 array( 85 'role' => 'editor', 86 ) 87 ); 88 89 self::$author_id = $factory->user->create( 90 array( 91 'role' => 'author', 92 ) 93 ); 94 95 self::$post_id = $factory->post->create( 96 array( 97 'post_title' => 'Test Post', 98 ) 99 ); 100 } 101 102 /** 103 * Delete test data after our tests run. 104 * 105 * @since 5.0.0 106 */ 107 public static function wpTearDownAfterClass() { 108 self::delete_user( self::$user_id ); 109 } 110 111 /** 112 * Set up. 113 * 114 * @since 5.0.0 115 */ 116 public function setUp() { 117 $this->register_test_block(); 118 $this->register_post_context_test_block(); 119 parent::setUp(); 120 } 121 122 /** 123 * Tear down. 124 * 125 * @since 5.0.0 126 */ 127 public function tearDown() { 128 WP_Block_Type_Registry::get_instance()->unregister( self::$block_name ); 129 WP_Block_Type_Registry::get_instance()->unregister( self::$context_block_name ); 130 parent::tearDown(); 131 } 132 133 /** 134 * Register test block. 135 * 136 * @since 5.0.0 137 */ 138 public function register_test_block() { 139 register_block_type( 140 self::$block_name, 141 array( 142 'attributes' => array( 143 'some_string' => array( 144 'type' => 'string', 145 'default' => 'some_default', 146 ), 147 'some_int' => array( 148 'type' => 'integer', 149 ), 150 'some_array' => array( 151 'type' => 'array', 152 'items' => array( 153 'type' => 'integer', 154 ), 155 ), 156 ), 157 'render_callback' => array( $this, 'render_test_block' ), 158 ) 159 ); 160 } 161 162 /** 163 * Register test block with post_id as attribute for post context test. 164 * 165 * @since 5.0.0 166 */ 167 public function register_post_context_test_block() { 168 register_block_type( 169 self::$context_block_name, 170 array( 171 'attributes' => array(), 172 'render_callback' => array( $this, 'render_post_context_test_block' ), 173 ) 174 ); 175 } 176 177 /** 178 * Test render callback. 179 * 180 * @since 5.0.0 181 * 182 * @param array $attributes Props. 183 * @return string Rendered attributes, which is here just JSON. 184 */ 185 public function render_test_block( $attributes ) { 186 return wp_json_encode( $attributes ); 187 } 188 189 /** 190 * Test render callback for testing post context. 191 * 192 * @since 5.0.0 193 * 194 * @return string 195 */ 196 public function render_post_context_test_block() { 197 return get_the_title(); 198 } 199 200 /** 201 * Check that the route was registered properly. 202 * 203 * @ticket 45098 204 * 205 * @covers WP_REST_Block_Renderer_Controller::register_routes() 206 */ 207 public function test_register_routes() { 208 $dynamic_block_names = get_dynamic_block_names(); 209 $this->assertContains( self::$block_name, $dynamic_block_names ); 210 211 $routes = rest_get_server()->get_routes(); 212 foreach ( $dynamic_block_names as $dynamic_block_name ) { 213 $this->assertArrayHasKey( self::$rest_api_route . "(?P<name>$dynamic_block_name)", $routes ); 214 } 215 } 216 217 /** 218 * Test getting item without permissions. 219 * 220 * @ticket 45098 221 * 222 * @covers WP_REST_Block_Renderer_Controller::get_item() 223 */ 224 public function test_get_item_without_permissions() { 225 wp_set_current_user( 0 ); 226 227 $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name ); 228 $request->set_param( 'context', 'edit' ); 229 230 $response = rest_get_server()->dispatch( $request ); 231 232 $this->assertErrorResponse( 'gutenberg_block_cannot_read', $response, rest_authorization_required_code() ); 233 } 234 235 /** 236 * Test getting item without 'edit' context. 237 * 238 * @ticket 45098 239 */ 240 public function test_get_item_with_invalid_context() { 241 wp_set_current_user( self::$user_id ); 242 243 $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name ); 244 $response = rest_get_server()->dispatch( $request ); 245 246 $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); 247 } 248 249 /** 250 * Test getting item with invalid block name. 251 * 252 * @ticket 45098 253 * 254 * @covers WP_REST_Block_Renderer_Controller::get_item() 255 */ 256 public function test_get_item_invalid_block_name() { 257 wp_set_current_user( self::$user_id ); 258 $request = new WP_REST_Request( 'GET', self::$rest_api_route . 'core/123' ); 259 260 $request->set_param( 'context', 'edit' ); 261 $response = rest_get_server()->dispatch( $request ); 262 263 $this->assertErrorResponse( 'rest_no_route', $response, 404 ); 264 } 265 266 /** 267 * Check getting item with an invalid param provided. 268 * 269 * @ticket 45098 270 * 271 * @covers WP_REST_Block_Renderer_Controller::get_item() 272 */ 273 public function test_get_item_invalid_attribute() { 274 wp_set_current_user( self::$user_id ); 275 $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name ); 276 $request->set_param( 'context', 'edit' ); 277 $request->set_param( 278 'attributes', 279 array( 280 'some_string' => array( 'no!' ), 281 ) 282 ); 283 $response = rest_get_server()->dispatch( $request ); 284 $this->assertEquals( 400, $response->get_status() ); 285 } 286 287 /** 288 * Check getting item with an invalid param provided. 289 * 290 * @ticket 45098 291 * 292 * @covers WP_REST_Block_Renderer_Controller::get_item() 293 */ 294 public function test_get_item_unrecognized_attribute() { 295 wp_set_current_user( self::$user_id ); 296 $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name ); 297 $request->set_param( 'context', 'edit' ); 298 $request->set_param( 299 'attributes', 300 array( 301 'unrecognized' => 'yes', 302 ) 303 ); 304 $response = rest_get_server()->dispatch( $request ); 305 $this->assertEquals( 400, $response->get_status() ); 306 } 307 308 /** 309 * Check getting item with default attributes provided. 310 * 311 * @ticket 45098 312 * 313 * @covers WP_REST_Block_Renderer_Controller::get_item() 314 */ 315 public function test_get_item_default_attributes() { 316 wp_set_current_user( self::$user_id ); 317 318 $block_type = WP_Block_Type_Registry::get_instance()->get_registered( self::$block_name ); 319 $defaults = array(); 320 foreach ( $block_type->attributes as $key => $attribute ) { 321 $defaults[ $key ] = isset( $attribute['default'] ) ? $attribute['default'] : null; 322 } 323 324 $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name ); 325 $request->set_param( 'context', 'edit' ); 326 $request->set_param( 'attributes', array() ); 327 $response = rest_get_server()->dispatch( $request ); 328 $this->assertEquals( 200, $response->get_status() ); 329 $data = $response->get_data(); 330 331 $this->assertEquals( $defaults, json_decode( $data['rendered'], true ) ); 332 $this->assertEquals( 333 json_decode( $block_type->render( $defaults ) ), 334 json_decode( $data['rendered'] ) 335 ); 336 } 337 338 /** 339 * Check getting item with attributes provided. 340 * 341 * @ticket 45098 342 * 343 * @covers WP_REST_Block_Renderer_Controller::get_item() 344 */ 345 public function test_get_item() { 346 wp_set_current_user( self::$user_id ); 347 348 $block_type = WP_Block_Type_Registry::get_instance()->get_registered( self::$block_name ); 349 $attributes = array( 350 'some_int' => '123', 351 'some_string' => 'foo', 352 'some_array' => array( 1, '2', 3 ), 353 ); 354 355 $expected_attributes = $attributes; 356 $expected_attributes['some_int'] = (int) $expected_attributes['some_int']; 357 $expected_attributes['some_array'] = array_map( 'intval', $expected_attributes['some_array'] ); 358 359 $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name ); 360 $request->set_param( 'context', 'edit' ); 361 $request->set_param( 'attributes', $attributes ); 362 $response = rest_get_server()->dispatch( $request ); 363 $this->assertEquals( 200, $response->get_status() ); 364 $data = $response->get_data(); 365 366 $this->assertEquals( $expected_attributes, json_decode( $data['rendered'], true ) ); 367 $this->assertEquals( 368 json_decode( $block_type->render( $attributes ), true ), 369 json_decode( $data['rendered'], true ) 370 ); 371 } 372 373 374 375 /** 376 * Check success response for getting item with layout attribute provided. 377 * 378 * @ticket 45098 379 */ 380 public function test_get_item_with_layout() { 381 wp_set_current_user( self::$user_id ); 382 383 $attributes = array( 384 'layout' => 'foo', 385 ); 386 387 $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name ); 388 $request->set_param( 'context', 'edit' ); 389 $request->set_param( 'attributes', $attributes ); 390 $response = rest_get_server()->dispatch( $request ); 391 $this->assertEquals( 200, $response->get_status() ); 392 } 393 394 /** 395 * Test getting item with post context. 396 * 397 * @ticket 45098 398 */ 399 public function test_get_item_with_post_context() { 400 wp_set_current_user( self::$user_id ); 401 402 $expected_title = 'Test Post'; 403 $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$context_block_name ); 404 $request->set_param( 'context', 'edit' ); 405 406 // Test without post ID. 407 $response = rest_get_server()->dispatch( $request ); 408 409 $this->assertEquals( 200, $response->get_status() ); 410 $data = $response->get_data(); 411 412 $this->assertTrue( empty( $data['rendered'] ) ); 413 414 // Now test with post ID. 415 $request->set_param( 'post_id', self::$post_id ); 416 $response = rest_get_server()->dispatch( $request ); 417 418 $this->assertEquals( 200, $response->get_status() ); 419 $data = $response->get_data(); 420 421 $this->assertEquals( $expected_title, $data['rendered'] ); 422 } 423 424 /** 425 * Test getting item with invalid post ID. 426 * 427 * @ticket 45098 428 */ 429 public function test_get_item_without_permissions_invalid_post() { 430 wp_set_current_user( self::$user_id ); 431 432 $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$context_block_name ); 433 $request->set_param( 'context', 'edit' ); 434 435 // Test with invalid post ID. 436 $request->set_param( 'post_id', PHP_INT_MAX ); 437 $response = rest_get_server()->dispatch( $request ); 438 439 $this->assertErrorResponse( 'gutenberg_block_cannot_read', $response, 403 ); 440 } 441 442 /** 443 * Test getting item without permissions to edit context post. 444 * 445 * @ticket 45098 446 */ 447 public function test_get_item_without_permissions_cannot_edit_post() { 448 wp_set_current_user( self::$author_id ); 449 450 $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$context_block_name ); 451 $request->set_param( 'context', 'edit' ); 452 453 // Test with private post ID. 454 $request->set_param( 'post_id', self::$post_id ); 455 $response = rest_get_server()->dispatch( $request ); 456 457 $this->assertErrorResponse( 'gutenberg_block_cannot_read', $response, 403 ); 458 } 459 460 /** 461 * Get item schema. 462 * 463 * @ticket 45098 464 * 465 * @covers WP_REST_Block_Renderer_Controller::get_item_schema() 466 */ 467 public function test_get_item_schema() { 468 $request = new WP_REST_Request( 'OPTIONS', self::$rest_api_route . self::$block_name ); 469 $response = rest_get_server()->dispatch( $request ); 470 $data = $response->get_data(); 471 472 $this->assertEqualSets( array( 'GET' ), $data['endpoints'][0]['methods'] ); 473 $this->assertEqualSets( 474 array( 'name', 'context', 'attributes', 'post_id' ), 475 array_keys( $data['endpoints'][0]['args'] ) 476 ); 477 $this->assertEquals( 'object', $data['endpoints'][0]['args']['attributes']['type'] ); 478 479 $this->assertArrayHasKey( 'schema', $data ); 480 $this->assertEquals( 'rendered-block', $data['schema']['title'] ); 481 $this->assertEquals( 'object', $data['schema']['type'] ); 482 $this->arrayHasKey( 'rendered', $data['schema']['properties'] ); 483 $this->arrayHasKey( 'string', $data['schema']['properties']['rendered']['type'] ); 484 $this->assertEquals( array( 'edit' ), $data['schema']['properties']['rendered']['context'] ); 485 } 486 487 /** 488 * The update_item() method does not exist for block rendering. 489 */ 490 public function test_update_item() { 491 $this->markTestSkipped( 'Controller does not implement update_item().' ); 492 } 493 494 /** 495 * The create_item() method does not exist for block rendering. 496 */ 497 public function test_create_item() { 498 $this->markTestSkipped( 'Controller does not implement create_item().' ); 499 } 500 501 /** 502 * The delete_item() method does not exist for block rendering. 503 */ 504 public function test_delete_item() { 505 $this->markTestSkipped( 'Controller does not implement delete_item().' ); 506 } 507 508 /** 509 * The get_items() method does not exist for block rendering. 510 */ 511 public function test_get_items() { 512 $this->markTestSkipped( 'Controller does not implement get_items().' ); 513 } 514 515 /** 516 * The context_param() method does not exist for block rendering. 517 */ 518 public function test_context_param() { 519 $this->markTestSkipped( 'Controller does not implement context_param().' ); 520 } 521 522 /** 523 * The prepare_item() method does not exist for block rendering. 524 */ 525 public function test_prepare_item() { 526 $this->markTestSkipped( 'Controller does not implement prepare_item().' ); 527 } 528 } -
tests/phpunit/tests/rest-api/rest-blocks-controller.php
1 <?php 2 /** 3 * WP_REST_Blocks_Controller tests 4 * 5 * @package WordPress 6 * @subpackage REST API 7 * @since 5.0.0 8 */ 9 10 /** 11 * Tests for WP_REST_Blocks_Controller. 12 * 13 * @since 5.0.0 14 * 15 * @see WP_Test_REST_Controller_Testcase 16 * 17 * @group restapi-blocks 18 * @group restapi 19 */ 20 class REST_Blocks_Controller_Test extends WP_Test_REST_Controller_Testcase { 21 22 /** 23 * Our fake block's post ID. 24 * 25 * @since 5.0.0 26 * 27 * @var int 28 */ 29 protected static $post_id; 30 31 /** 32 * Our fake user's ID. 33 * 34 * @since 5.0.0 35 * 36 * @var int 37 */ 38 protected static $user_id; 39 40 /** 41 * Create fake data before our tests run. 42 * 43 * @param WP_UnitTest_Factory $factory Helper that lets us create fake data. 44 */ 45 public static function wpSetUpBeforeClass( $factory ) { 46 self::$post_id = wp_insert_post( 47 array( 48 'post_type' => 'wp_block', 49 'post_status' => 'publish', 50 'post_title' => 'My cool block', 51 'post_content' => '<!-- wp:core/paragraph --><p>Hello!</p><!-- /wp:core/paragraph -->', 52 ) 53 ); 54 55 self::$user_id = $factory->user->create( 56 array( 57 'role' => 'editor', 58 ) 59 ); 60 } 61 62 /** 63 * Delete our fake data after our tests run. 64 * 65 * @since 5.0.0 66 * 67 * @ticket 45098 68 */ 69 public static function wpTearDownAfterClass() { 70 wp_delete_post( self::$post_id ); 71 72 self::delete_user( self::$user_id ); 73 } 74 75 /** 76 * Check that our routes get set up properly. 77 * 78 * @ticket 45098 79 */ 80 public function test_register_routes() { 81 $routes = rest_get_server()->get_routes(); 82 83 $this->assertArrayHasKey( '/wp/v2/blocks', $routes ); 84 $this->assertCount( 2, $routes['/wp/v2/blocks'] ); 85 $this->assertArrayHasKey( '/wp/v2/blocks/(?P<id>[\d]+)', $routes ); 86 $this->assertCount( 3, $routes['/wp/v2/blocks/(?P<id>[\d]+)'] ); 87 } 88 89 /** 90 * Check that we can GET a collection of blocks. 91 * 92 * @ticket 45098 93 */ 94 public function test_get_items() { 95 wp_set_current_user( self::$user_id ); 96 97 $request = new WP_REST_Request( 'GET', '/wp/v2/blocks' ); 98 $response = rest_get_server()->dispatch( $request ); 99 100 $this->assertEquals( 200, $response->get_status() ); 101 $this->assertEquals( 102 array( 103 array( 104 'id' => self::$post_id, 105 'title' => 'My cool block', 106 'content' => '<!-- wp:core/paragraph --><p>Hello!</p><!-- /wp:core/paragraph -->', 107 ), 108 ), 109 $response->get_data() 110 ); 111 } 112 113 /** 114 * Check that we can GET a single block. 115 * 116 * @ticket 45098 117 */ 118 public function test_get_item() { 119 wp_set_current_user( self::$user_id ); 120 121 $request = new WP_REST_Request( 'GET', '/wp/v2/blocks/' . self::$post_id ); 122 $response = rest_get_server()->dispatch( $request ); 123 124 $this->assertEquals( 200, $response->get_status() ); 125 $this->assertEquals( 126 array( 127 'id' => self::$post_id, 128 'title' => 'My cool block', 129 'content' => '<!-- wp:core/paragraph --><p>Hello!</p><!-- /wp:core/paragraph -->', 130 ), 131 $response->get_data() 132 ); 133 } 134 135 /** 136 * Check that we can POST to create a new block. 137 * 138 * @ticket 45098 139 */ 140 public function test_create_item() { 141 wp_set_current_user( self::$user_id ); 142 143 $request = new WP_REST_Request( 'POST', '/wp/v2/blocks/' . self::$post_id ); 144 $request->set_body_params( 145 array( 146 'title' => 'New cool block', 147 'content' => '<!-- wp:core/paragraph --><p>Wow!</p><!-- /wp:core/paragraph -->', 148 ) 149 ); 150 151 $response = rest_get_server()->dispatch( $request ); 152 153 $this->assertEquals( 200, $response->get_status() ); 154 155 $data = $response->get_data(); 156 157 $this->assertArrayHasKey( 'id', $data ); 158 $this->assertArrayHasKey( 'title', $data ); 159 $this->assertArrayHasKey( 'content', $data ); 160 161 $this->assertEquals( self::$post_id, $data['id'] ); 162 $this->assertEquals( 'New cool block', $data['title'] ); 163 $this->assertEquals( '<!-- wp:core/paragraph --><p>Wow!</p><!-- /wp:core/paragraph -->', $data['content'] ); 164 } 165 166 /** 167 * Check that we can PUT to update a block. 168 * 169 * @ticket 45098 170 */ 171 public function test_update_item() { 172 wp_set_current_user( self::$user_id ); 173 174 $request = new WP_REST_Request( 'PUT', '/wp/v2/blocks/' . self::$post_id ); 175 $request->set_body_params( 176 array( 177 'title' => 'Updated cool block', 178 'content' => '<!-- wp:core/paragraph --><p>Nice!</p><!-- /wp:core/paragraph -->', 179 ) 180 ); 181 182 $response = rest_get_server()->dispatch( $request ); 183 184 $this->assertEquals( 200, $response->get_status() ); 185 186 $data = $response->get_data(); 187 188 $this->assertArrayHasKey( 'id', $data ); 189 $this->assertArrayHasKey( 'title', $data ); 190 $this->assertArrayHasKey( 'content', $data ); 191 192 $this->assertEquals( self::$post_id, $data['id'] ); 193 $this->assertEquals( 'Updated cool block', $data['title'] ); 194 $this->assertEquals( '<!-- wp:core/paragraph --><p>Nice!</p><!-- /wp:core/paragraph -->', $data['content'] ); 195 } 196 197 /** 198 * Check that we can DELETE a block. 199 * 200 * @ticket 45098 201 */ 202 public function test_delete_item() { 203 wp_set_current_user( self::$user_id ); 204 205 $request = new WP_REST_Request( 'DELETE', '/wp/v2/blocks/' . self::$post_id ); 206 207 $response = rest_get_server()->dispatch( $request ); 208 209 $this->assertEquals( 200, $response->get_status() ); 210 211 $data = $response->get_data(); 212 213 $this->assertArrayHasKey( 'deleted', $data ); 214 $this->assertArrayHasKey( 'previous', $data ); 215 216 $this->assertTrue( $data['deleted'] ); 217 218 $this->assertArrayHasKey( 'id', $data['previous'] ); 219 $this->assertArrayHasKey( 'title', $data['previous'] ); 220 $this->assertArrayHasKey( 'content', $data['previous'] ); 221 222 $this->assertEquals( self::$post_id, $data['previous']['id'] ); 223 $this->assertEquals( 'My cool block', $data['previous']['title'] ); 224 $this->assertEquals( '<!-- wp:core/paragraph --><p>Hello!</p><!-- /wp:core/paragraph -->', $data['previous']['content'] ); 225 } 226 227 /** 228 * Check that we have defined a JSON schema. 229 * 230 * @ticket 45098 231 */ 232 public function test_get_item_schema() { 233 $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/blocks' ); 234 $response = rest_get_server()->dispatch( $request ); 235 $data = $response->get_data(); 236 $properties = $data['schema']['properties']; 237 238 $this->assertEquals( 3, count( $properties ) ); 239 $this->assertArrayHasKey( 'id', $properties ); 240 $this->assertArrayHasKey( 'title', $properties ); 241 $this->assertArrayHasKey( 'content', $properties ); 242 } 243 244 /** 245 * Test cases for test_capabilities(). 246 * 247 * @since 5.0.0 248 */ 249 public function data_capabilities() { 250 return array( 251 array( 'create', 'editor', 201 ), 252 array( 'create', 'author', 201 ), 253 array( 'create', 'contributor', 403 ), 254 array( 'create', null, 401 ), 255 256 array( 'read', 'editor', 200 ), 257 array( 'read', 'author', 200 ), 258 array( 'read', 'contributor', 200 ), 259 array( 'read', null, 401 ), 260 261 array( 'update_delete_own', 'editor', 200 ), 262 array( 'update_delete_own', 'author', 200 ), 263 array( 'update_delete_own', 'contributor', 403 ), 264 265 array( 'update_delete_others', 'editor', 200 ), 266 array( 'update_delete_others', 'author', 403 ), 267 array( 'update_delete_others', 'contributor', 403 ), 268 array( 'update_delete_others', null, 401 ), 269 ); 270 } 271 272 /** 273 * Exhaustively check that each role either can or cannot create, edit, 274 * update, and delete reusable blocks. 275 * 276 * @ticket 45098 277 * 278 * @dataProvider data_capabilities 279 */ 280 public function test_capabilities( $action, $role, $expected_status ) { 281 if ( $role ) { 282 $user_id = $this->factory->user->create( array( 'role' => $role ) ); 283 wp_set_current_user( $user_id ); 284 } else { 285 wp_set_current_user( 0 ); 286 } 287 288 switch ( $action ) { 289 case 'create': 290 $request = new WP_REST_Request( 'POST', '/wp/v2/blocks' ); 291 $request->set_body_params( 292 array( 293 'title' => 'Test', 294 'content' => '<!-- wp:core/paragraph --><p>Test</p><!-- /wp:core/paragraph -->', 295 ) 296 ); 297 298 $response = rest_get_server()->dispatch( $request ); 299 $this->assertEquals( $expected_status, $response->get_status() ); 300 301 break; 302 303 case 'read': 304 $request = new WP_REST_Request( 'GET', '/wp/v2/blocks/' . self::$post_id ); 305 306 $response = rest_get_server()->dispatch( $request ); 307 $this->assertEquals( $expected_status, $response->get_status() ); 308 309 break; 310 311 case 'update_delete_own': 312 $post_id = wp_insert_post( 313 array( 314 'post_type' => 'wp_block', 315 'post_status' => 'publish', 316 'post_title' => 'My cool block', 317 'post_content' => '<!-- wp:core/paragraph --><p>Hello!</p><!-- /wp:core/paragraph -->', 318 'post_author' => $user_id, 319 ) 320 ); 321 322 $request = new WP_REST_Request( 'PUT', '/wp/v2/blocks/' . $post_id ); 323 $request->set_body_params( 324 array( 325 'title' => 'Test', 326 'content' => '<!-- wp:core/paragraph --><p>Test</p><!-- /wp:core/paragraph -->', 327 ) 328 ); 329 330 $response = rest_get_server()->dispatch( $request ); 331 $this->assertEquals( $expected_status, $response->get_status() ); 332 333 $request = new WP_REST_Request( 'DELETE', '/wp/v2/blocks/' . $post_id ); 334 335 $response = rest_get_server()->dispatch( $request ); 336 $this->assertEquals( $expected_status, $response->get_status() ); 337 338 wp_delete_post( $post_id ); 339 340 break; 341 342 case 'update_delete_others': 343 $request = new WP_REST_Request( 'PUT', '/wp/v2/blocks/' . self::$post_id ); 344 $request->set_body_params( 345 array( 346 'title' => 'Test', 347 'content' => '<!-- wp:core/paragraph --><p>Test</p><!-- /wp:core/paragraph -->', 348 ) 349 ); 350 351 $response = rest_get_server()->dispatch( $request ); 352 $this->assertEquals( $expected_status, $response->get_status() ); 353 354 $request = new WP_REST_Request( 'DELETE', '/wp/v2/blocks/' . self::$post_id ); 355 356 $response = rest_get_server()->dispatch( $request ); 357 $this->assertEquals( $expected_status, $response->get_status() ); 358 359 break; 360 361 default: 362 $this->fail( "'$action' is not a valid action." ); 363 } 364 365 if ( isset( $user_id ) ) { 366 self::delete_user( $user_id ); 367 } 368 } 369 370 /** 371 * The context_param() method does not exist for blocks. 372 */ 373 public function test_context_param() { 374 $this->markTestSkipped( 'Controller does not implement get_context_param().' ); 375 } 376 377 /** 378 * The prepare_item() method does not exist for blocks. 379 */ 380 public function test_prepare_item() { 381 $this->markTestSkipped( 'Controller does not implement prepare_item().' ); 382 } 383 } -
tests/qunit/fixtures/wp-api-generated.js
3525 3525 "_links": { 3526 3526 "self": "http://example.org/index.php?rest_route=/wp/v2/settings" 3527 3527 } 3528 }, 3529 "/wp/v2/block-renderer/(?P<name>core/block)": { 3530 "namespace": "wp/v2", 3531 "methods": [ 3532 "GET" 3533 ], 3534 "endpoints": [ 3535 { 3536 "methods": [ 3537 "GET" 3538 ], 3539 "args": { 3540 "name": { 3541 "required": false, 3542 "description": "Unique registered name for the block.", 3543 "type": "string" 3544 }, 3545 "context": { 3546 "required": false, 3547 "default": "view", 3548 "enum": [ 3549 "edit" 3550 ], 3551 "description": "Scope under which the request is made; determines fields present in response.", 3552 "type": "string" 3553 }, 3554 "attributes": { 3555 "required": false, 3556 "description": "Attributes for core/block block", 3557 "type": "object" 3558 }, 3559 "post_id": { 3560 "required": false, 3561 "description": "ID of the post context.", 3562 "type": "integer" 3563 } 3564 } 3565 } 3566 ] 3567 }, 3568 "/wp/v2/block-renderer/(?P<name>core/latest-comments)": { 3569 "namespace": "wp/v2", 3570 "methods": [ 3571 "GET" 3572 ], 3573 "endpoints": [ 3574 { 3575 "methods": [ 3576 "GET" 3577 ], 3578 "args": { 3579 "name": { 3580 "required": false, 3581 "description": "Unique registered name for the block.", 3582 "type": "string" 3583 }, 3584 "context": { 3585 "required": false, 3586 "default": "view", 3587 "enum": [ 3588 "edit" 3589 ], 3590 "description": "Scope under which the request is made; determines fields present in response.", 3591 "type": "string" 3592 }, 3593 "attributes": { 3594 "required": false, 3595 "description": "Attributes for core/latest-comments block", 3596 "type": "object" 3597 }, 3598 "post_id": { 3599 "required": false, 3600 "description": "ID of the post context.", 3601 "type": "integer" 3602 } 3603 } 3604 } 3605 ] 3528 3606 } 3529 3607 } 3530 3608 };