Ticket #45098: 45098.2.diff
| File 45098.2.diff, 38.3 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 'block_cannot_read', 96 __( 'Sorry, you are not allowed to read 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 'block_cannot_read', 106 __( 'Sorry, you are not allowed to read 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 '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 the editor 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-blocks-controller.php' ); 239 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-block-renderer-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 each test method. 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 each test method. 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( '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( '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( '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 * Our fake block's post ID. 23 * 24 * @since 5.0.0 25 * 26 * @var int 27 */ 28 protected static $post_id; 29 30 /** 31 * Our fake user's ID. 32 * 33 * @since 5.0.0 34 * 35 * @var int 36 */ 37 protected static $user_id; 38 39 /** 40 * Create fake data before our tests run. 41 * 42 * @since 5.0.0 43 * 44 * @param WP_UnitTest_Factory $factory Helper that lets us create fake data. 45 */ 46 public static function wpSetUpBeforeClass( $factory ) { 47 self::$post_id = wp_insert_post( 48 array( 49 'post_type' => 'wp_block', 50 'post_status' => 'publish', 51 'post_title' => 'My cool block', 52 'post_content' => '<!-- wp:core/paragraph --><p>Hello!</p><!-- /wp:core/paragraph -->', 53 ) 54 ); 55 56 self::$user_id = $factory->user->create( 57 array( 58 'role' => 'editor', 59 ) 60 ); 61 } 62 63 /** 64 * Delete our fake data after our tests run. 65 * 66 * @since 5.0.0 67 */ 68 public static function wpTearDownAfterClass() { 69 wp_delete_post( self::$post_id ); 70 71 self::delete_user( self::$user_id ); 72 } 73 74 /** 75 * Check that our routes get set up properly. 76 * 77 * @ticket 45098 78 */ 79 public function test_register_routes() { 80 $routes = rest_get_server()->get_routes(); 81 82 $this->assertArrayHasKey( '/wp/v2/blocks', $routes ); 83 $this->assertCount( 2, $routes['/wp/v2/blocks'] ); 84 $this->assertArrayHasKey( '/wp/v2/blocks/(?P<id>[\d]+)', $routes ); 85 $this->assertCount( 3, $routes['/wp/v2/blocks/(?P<id>[\d]+)'] ); 86 } 87 88 /** 89 * Check that we can GET a collection of blocks. 90 * 91 * @ticket 45098 92 */ 93 public function test_get_items() { 94 wp_set_current_user( self::$user_id ); 95 96 $request = new WP_REST_Request( 'GET', '/wp/v2/blocks' ); 97 $response = rest_get_server()->dispatch( $request ); 98 99 $this->assertEquals( 200, $response->get_status() ); 100 $this->assertEquals( 101 array( 102 array( 103 'id' => self::$post_id, 104 'title' => 'My cool block', 105 'content' => '<!-- wp:core/paragraph --><p>Hello!</p><!-- /wp:core/paragraph -->', 106 ), 107 ), 108 $response->get_data() 109 ); 110 } 111 112 /** 113 * Check that we can GET a single block. 114 * 115 * @ticket 45098 116 */ 117 public function test_get_item() { 118 wp_set_current_user( self::$user_id ); 119 120 $request = new WP_REST_Request( 'GET', '/wp/v2/blocks/' . self::$post_id ); 121 $response = rest_get_server()->dispatch( $request ); 122 123 $this->assertEquals( 200, $response->get_status() ); 124 $this->assertEquals( 125 array( 126 'id' => self::$post_id, 127 'title' => 'My cool block', 128 'content' => '<!-- wp:core/paragraph --><p>Hello!</p><!-- /wp:core/paragraph -->', 129 ), 130 $response->get_data() 131 ); 132 } 133 134 /** 135 * Check that we can POST to create a new block. 136 * 137 * @ticket 45098 138 */ 139 public function test_create_item() { 140 wp_set_current_user( self::$user_id ); 141 142 $request = new WP_REST_Request( 'POST', '/wp/v2/blocks/' . self::$post_id ); 143 $request->set_body_params( 144 array( 145 'title' => 'New cool block', 146 'content' => '<!-- wp:core/paragraph --><p>Wow!</p><!-- /wp:core/paragraph -->', 147 ) 148 ); 149 150 $response = rest_get_server()->dispatch( $request ); 151 152 $this->assertEquals( 200, $response->get_status() ); 153 154 $data = $response->get_data(); 155 156 $this->assertArrayHasKey( 'id', $data ); 157 $this->assertArrayHasKey( 'title', $data ); 158 $this->assertArrayHasKey( 'content', $data ); 159 160 $this->assertEquals( self::$post_id, $data['id'] ); 161 $this->assertEquals( 'New cool block', $data['title'] ); 162 $this->assertEquals( '<!-- wp:core/paragraph --><p>Wow!</p><!-- /wp:core/paragraph -->', $data['content'] ); 163 } 164 165 /** 166 * Check that we can PUT to update a block. 167 * 168 * @ticket 45098 169 */ 170 public function test_update_item() { 171 wp_set_current_user( self::$user_id ); 172 173 $request = new WP_REST_Request( 'PUT', '/wp/v2/blocks/' . self::$post_id ); 174 $request->set_body_params( 175 array( 176 'title' => 'Updated cool block', 177 'content' => '<!-- wp:core/paragraph --><p>Nice!</p><!-- /wp:core/paragraph -->', 178 ) 179 ); 180 181 $response = rest_get_server()->dispatch( $request ); 182 183 $this->assertEquals( 200, $response->get_status() ); 184 185 $data = $response->get_data(); 186 187 $this->assertArrayHasKey( 'id', $data ); 188 $this->assertArrayHasKey( 'title', $data ); 189 $this->assertArrayHasKey( 'content', $data ); 190 191 $this->assertEquals( self::$post_id, $data['id'] ); 192 $this->assertEquals( 'Updated cool block', $data['title'] ); 193 $this->assertEquals( '<!-- wp:core/paragraph --><p>Nice!</p><!-- /wp:core/paragraph -->', $data['content'] ); 194 } 195 196 /** 197 * Check that we can DELETE a block. 198 * 199 * @ticket 45098 200 */ 201 public function test_delete_item() { 202 wp_set_current_user( self::$user_id ); 203 204 $request = new WP_REST_Request( 'DELETE', '/wp/v2/blocks/' . self::$post_id ); 205 206 $response = rest_get_server()->dispatch( $request ); 207 208 $this->assertEquals( 200, $response->get_status() ); 209 210 $data = $response->get_data(); 211 212 $this->assertArrayHasKey( 'deleted', $data ); 213 $this->assertArrayHasKey( 'previous', $data ); 214 215 $this->assertTrue( $data['deleted'] ); 216 217 $this->assertArrayHasKey( 'id', $data['previous'] ); 218 $this->assertArrayHasKey( 'title', $data['previous'] ); 219 $this->assertArrayHasKey( 'content', $data['previous'] ); 220 221 $this->assertEquals( self::$post_id, $data['previous']['id'] ); 222 $this->assertEquals( 'My cool block', $data['previous']['title'] ); 223 $this->assertEquals( '<!-- wp:core/paragraph --><p>Hello!</p><!-- /wp:core/paragraph -->', $data['previous']['content'] ); 224 } 225 226 /** 227 * Check that we have defined a JSON schema. 228 * 229 * @ticket 45098 230 */ 231 public function test_get_item_schema() { 232 $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/blocks' ); 233 $response = rest_get_server()->dispatch( $request ); 234 $data = $response->get_data(); 235 $properties = $data['schema']['properties']; 236 237 $this->assertEquals( 3, count( $properties ) ); 238 $this->assertArrayHasKey( 'id', $properties ); 239 $this->assertArrayHasKey( 'title', $properties ); 240 $this->assertArrayHasKey( 'content', $properties ); 241 } 242 243 /** 244 * Test cases for test_capabilities(). 245 * 246 * @since 5.0.0 247 */ 248 public function data_capabilities() { 249 return array( 250 array( 'create', 'editor', 201 ), 251 array( 'create', 'author', 201 ), 252 array( 'create', 'contributor', 403 ), 253 array( 'create', null, 401 ), 254 255 array( 'read', 'editor', 200 ), 256 array( 'read', 'author', 200 ), 257 array( 'read', 'contributor', 200 ), 258 array( 'read', null, 401 ), 259 260 array( 'update_delete_own', 'editor', 200 ), 261 array( 'update_delete_own', 'author', 200 ), 262 array( 'update_delete_own', 'contributor', 403 ), 263 264 array( 'update_delete_others', 'editor', 200 ), 265 array( 'update_delete_others', 'author', 403 ), 266 array( 'update_delete_others', 'contributor', 403 ), 267 array( 'update_delete_others', null, 401 ), 268 ); 269 } 270 271 /** 272 * Exhaustively check that each role either can or cannot create, edit, 273 * update, and delete reusable blocks. 274 * 275 * @ticket 45098 276 * 277 * @dataProvider data_capabilities 278 * 279 * @param string $action Action to perform in the test. 280 * @param string $role User role to test. 281 * @param int $expected_status Expected HTTP response status. 282 */ 283 public function test_capabilities( $action, $role, $expected_status ) { 284 if ( $role ) { 285 $user_id = $this->factory->user->create( array( 'role' => $role ) ); 286 wp_set_current_user( $user_id ); 287 } else { 288 wp_set_current_user( 0 ); 289 } 290 291 switch ( $action ) { 292 case 'create': 293 $request = new WP_REST_Request( 'POST', '/wp/v2/blocks' ); 294 $request->set_body_params( 295 array( 296 'title' => 'Test', 297 'content' => '<!-- wp:core/paragraph --><p>Test</p><!-- /wp:core/paragraph -->', 298 ) 299 ); 300 301 $response = rest_get_server()->dispatch( $request ); 302 $this->assertEquals( $expected_status, $response->get_status() ); 303 304 break; 305 306 case 'read': 307 $request = new WP_REST_Request( 'GET', '/wp/v2/blocks/' . self::$post_id ); 308 309 $response = rest_get_server()->dispatch( $request ); 310 $this->assertEquals( $expected_status, $response->get_status() ); 311 312 break; 313 314 case 'update_delete_own': 315 $post_id = wp_insert_post( 316 array( 317 'post_type' => 'wp_block', 318 'post_status' => 'publish', 319 'post_title' => 'My cool block', 320 'post_content' => '<!-- wp:core/paragraph --><p>Hello!</p><!-- /wp:core/paragraph -->', 321 'post_author' => $user_id, 322 ) 323 ); 324 325 $request = new WP_REST_Request( 'PUT', '/wp/v2/blocks/' . $post_id ); 326 $request->set_body_params( 327 array( 328 'title' => 'Test', 329 'content' => '<!-- wp:core/paragraph --><p>Test</p><!-- /wp:core/paragraph -->', 330 ) 331 ); 332 333 $response = rest_get_server()->dispatch( $request ); 334 $this->assertEquals( $expected_status, $response->get_status() ); 335 336 $request = new WP_REST_Request( 'DELETE', '/wp/v2/blocks/' . $post_id ); 337 338 $response = rest_get_server()->dispatch( $request ); 339 $this->assertEquals( $expected_status, $response->get_status() ); 340 341 wp_delete_post( $post_id ); 342 343 break; 344 345 case 'update_delete_others': 346 $request = new WP_REST_Request( 'PUT', '/wp/v2/blocks/' . self::$post_id ); 347 $request->set_body_params( 348 array( 349 'title' => 'Test', 350 'content' => '<!-- wp:core/paragraph --><p>Test</p><!-- /wp:core/paragraph -->', 351 ) 352 ); 353 354 $response = rest_get_server()->dispatch( $request ); 355 $this->assertEquals( $expected_status, $response->get_status() ); 356 357 $request = new WP_REST_Request( 'DELETE', '/wp/v2/blocks/' . self::$post_id ); 358 359 $response = rest_get_server()->dispatch( $request ); 360 $this->assertEquals( $expected_status, $response->get_status() ); 361 362 break; 363 364 default: 365 $this->fail( "'$action' is not a valid action." ); 366 } 367 368 if ( isset( $user_id ) ) { 369 self::delete_user( $user_id ); 370 } 371 } 372 373 /** 374 * The context_param() method does not exist for blocks. 375 */ 376 public function test_context_param() { 377 $this->markTestSkipped( 'Controller does not implement get_context_param().' ); 378 } 379 380 /** 381 * The prepare_item() method does not exist for blocks. 382 */ 383 public function test_prepare_item() { 384 $this->markTestSkipped( 'Controller does not implement prepare_item().' ); 385 } 386 } -
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 };