Make WordPress Core

Ticket #45098: 45098.3.diff

File 45098.3.diff, 65.6 KB (added by danielbachhuber, 7 years ago)
  • src/wp-includes/rest-api.php

    diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php
    index ebc3d9a053..e1d8919c8d 100644
    a b function create_initial_rest_routes() { 
    250250        $controller = new WP_REST_Search_Controller( $search_handlers );
    251251        $controller->register_routes();
    252252
     253        // Block Renderer.
     254        $controller = new WP_REST_Block_Renderer_Controller;
     255        $controller->register_routes();
     256
    253257        // Settings.
    254258        $controller = new WP_REST_Settings_Controller;
    255259        $controller->register_routes();
    function create_initial_rest_routes() { 
    257261        // Themes.
    258262        $controller = new WP_REST_Themes_Controller;
    259263        $controller->register_routes();
     264
    260265}
    261266
    262267/**
  • new file src/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php

    diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php
    new file mode 100644
    index 0000000000..a4f17283c5
    - +  
     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 */
     17class 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}
  • new file src/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php

    diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php
    new file mode 100644
    index 0000000000..66a2e7adad
    - +  
     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 */
     20class WP_REST_Blocks_Controller extends WP_REST_Posts_Controller {
     21
     22        /**
     23         * Checks if a block can be read.
     24         *
     25         * @since 5.0.0
     26         *
     27         * @param object $post Post object that backs the block.
     28         * @return bool Whether the block can be read.
     29         */
     30        public function check_read_permission( $post ) {
     31                // Ensure that the user is logged in and has the read_blocks capability.
     32                $post_type = get_post_type_object( $post->post_type );
     33                if ( ! current_user_can( $post_type->cap->read_post, $post->ID ) ) {
     34                        return false;
     35                }
     36
     37                return parent::check_read_permission( $post );
     38        }
     39}
  • src/wp-settings.php

    diff --git a/src/wp-settings.php b/src/wp-settings.php
    index f711b9167b..efefa1b214 100644
    a b require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-terms-controller.p 
    235235require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-users-controller.php' );
    236236require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-comments-controller.php' );
    237237require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-search-controller.php' );
     238require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-blocks-controller.php' );
     239require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-block-renderer-controller.php' );
    238240require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-settings-controller.php' );
    239241require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-themes-controller.php' );
    240242require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-meta-fields.php' );
  • new file tests/phpunit/tests/rest-api/rest-block-renderer-controller.php

    diff --git a/tests/phpunit/tests/rest-api/rest-block-renderer-controller.php b/tests/phpunit/tests/rest-api/rest-block-renderer-controller.php
    new file mode 100644
    index 0000000000..472e448b10
    - +  
     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 */
     20class REST_Block_Renderer_Controller_Test extends WP_Test_REST_Controller_Testcase {
     21
     22        /**
     23         * The REST API route for the block renderer.
     24         *
     25         * @since 5.0.0
     26         *
     27         * @var string
     28         */
     29        protected static $rest_api_route = '/wp/v2/block-renderer/';
     30
     31        /**
     32         * Test block's name.
     33         *
     34         * @since 5.0.0
     35         *
     36         * @var string
     37         */
     38        protected static $block_name = 'core/test-block';
     39
     40        /**
     41         * Test post context block's name.
     42         *
     43         * @since 5.0.0
     44         *
     45         * @var string
     46         */
     47        protected static $context_block_name = 'core/context-test-block';
     48
     49        /**
     50         * Test API user's ID.
     51         *
     52         * @since 5.0.0
     53         *
     54         * @var int
     55         */
     56        protected static $user_id;
     57
     58        /**
     59         * Test post ID.
     60         *
     61         * @since 5.0.0
     62         *
     63         * @var int
     64         */
     65        protected static $post_id;
     66
     67        /**
     68         * Author test user ID.
     69         *
     70         * @since 5.0.0
     71         *
     72         * @var int
     73         */
     74        protected static $author_id;
     75
     76        /**
     77         * Create test data before the tests run.
     78         *
     79         * @since 5.0.0
     80         *
     81         * @param WP_UnitTest_Factory $factory Helper that lets us create fake data.
     82         */
     83        public static function wpSetUpBeforeClass( $factory ) {
     84                self::$user_id = $factory->user->create(
     85                        array(
     86                                'role' => 'editor',
     87                        )
     88                );
     89
     90                self::$author_id = $factory->user->create(
     91                        array(
     92                                'role' => 'author',
     93                        )
     94                );
     95
     96                self::$post_id = $factory->post->create(
     97                        array(
     98                                'post_title' => 'Test Post',
     99                        )
     100                );
     101        }
     102
     103        /**
     104         * Delete test data after our tests run.
     105         *
     106         * @since 5.0.0
     107         */
     108        public static function wpTearDownAfterClass() {
     109                self::delete_user( self::$user_id );
     110        }
     111
     112        /**
     113         * Set up each test method.
     114         *
     115         * @since 5.0.0
     116         */
     117        public function setUp() {
     118                $this->register_test_block();
     119                $this->register_post_context_test_block();
     120                parent::setUp();
     121        }
     122
     123        /**
     124         * Tear down each test method.
     125         *
     126         * @since 5.0.0
     127         */
     128        public function tearDown() {
     129                WP_Block_Type_Registry::get_instance()->unregister( self::$block_name );
     130                WP_Block_Type_Registry::get_instance()->unregister( self::$context_block_name );
     131                parent::tearDown();
     132        }
     133
     134        /**
     135         * Register test block.
     136         *
     137         * @since 5.0.0
     138         */
     139        public function register_test_block() {
     140                register_block_type(
     141                        self::$block_name,
     142                        array(
     143                                'attributes'      => array(
     144                                        'some_string' => array(
     145                                                'type'    => 'string',
     146                                                'default' => 'some_default',
     147                                        ),
     148                                        'some_int'    => array(
     149                                                'type' => 'integer',
     150                                        ),
     151                                        'some_array'  => array(
     152                                                'type'  => 'array',
     153                                                'items' => array(
     154                                                        'type' => 'integer',
     155                                                ),
     156                                        ),
     157                                ),
     158                                'render_callback' => array( $this, 'render_test_block' ),
     159                        )
     160                );
     161        }
     162
     163        /**
     164         * Register test block with post_id as attribute for post context test.
     165         *
     166         * @since 5.0.0
     167         */
     168        public function register_post_context_test_block() {
     169                register_block_type(
     170                        self::$context_block_name,
     171                        array(
     172                                'attributes'      => array(),
     173                                'render_callback' => array( $this, 'render_post_context_test_block' ),
     174                        )
     175                );
     176        }
     177
     178        /**
     179         * Test render callback.
     180         *
     181         * @since 5.0.0
     182         *
     183         * @param array $attributes Props.
     184         * @return string Rendered attributes, which is here just JSON.
     185         */
     186        public function render_test_block( $attributes ) {
     187                return wp_json_encode( $attributes );
     188        }
     189
     190        /**
     191         * Test render callback for testing post context.
     192         *
     193         * @since 5.0.0
     194         *
     195         * @return string
     196         */
     197        public function render_post_context_test_block() {
     198                return get_the_title();
     199        }
     200
     201        /**
     202         * Check that the route was registered properly.
     203         *
     204         * @ticket 45098
     205         *
     206         * @covers WP_REST_Block_Renderer_Controller::register_routes()
     207         */
     208        public function test_register_routes() {
     209                $dynamic_block_names = get_dynamic_block_names();
     210                $this->assertContains( self::$block_name, $dynamic_block_names );
     211
     212                $routes = rest_get_server()->get_routes();
     213                foreach ( $dynamic_block_names as $dynamic_block_name ) {
     214                        $this->assertArrayHasKey( self::$rest_api_route . "(?P<name>$dynamic_block_name)", $routes );
     215                }
     216        }
     217
     218        /**
     219         * Test getting item without permissions.
     220         *
     221         * @ticket 45098
     222         *
     223         * @covers WP_REST_Block_Renderer_Controller::get_item()
     224         */
     225        public function test_get_item_without_permissions() {
     226                wp_set_current_user( 0 );
     227
     228                $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name );
     229                $request->set_param( 'context', 'edit' );
     230
     231                $response = rest_get_server()->dispatch( $request );
     232
     233                $this->assertErrorResponse( 'block_cannot_read', $response, rest_authorization_required_code() );
     234        }
     235
     236        /**
     237         * Test getting item without 'edit' context.
     238         *
     239         * @ticket 45098
     240         */
     241        public function test_get_item_with_invalid_context() {
     242                wp_set_current_user( self::$user_id );
     243
     244                $request  = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name );
     245                $response = rest_get_server()->dispatch( $request );
     246
     247                $this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
     248        }
     249
     250        /**
     251         * Test getting item with invalid block name.
     252         *
     253         * @ticket 45098
     254         *
     255         * @covers WP_REST_Block_Renderer_Controller::get_item()
     256         */
     257        public function test_get_item_invalid_block_name() {
     258                wp_set_current_user( self::$user_id );
     259                $request = new WP_REST_Request( 'GET', self::$rest_api_route . 'core/123' );
     260
     261                $request->set_param( 'context', 'edit' );
     262                $response = rest_get_server()->dispatch( $request );
     263
     264                $this->assertErrorResponse( 'rest_no_route', $response, 404 );
     265        }
     266
     267        /**
     268         * Check getting item with an invalid param provided.
     269         *
     270         * @ticket 45098
     271         *
     272         * @covers WP_REST_Block_Renderer_Controller::get_item()
     273         */
     274        public function test_get_item_invalid_attribute() {
     275                wp_set_current_user( self::$user_id );
     276                $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name );
     277                $request->set_param( 'context', 'edit' );
     278                $request->set_param(
     279                        'attributes',
     280                        array(
     281                                'some_string' => array( 'no!' ),
     282                        )
     283                );
     284                $response = rest_get_server()->dispatch( $request );
     285                $this->assertEquals( 400, $response->get_status() );
     286        }
     287
     288        /**
     289         * Check getting item with an invalid param provided.
     290         *
     291         * @ticket 45098
     292         *
     293         * @covers WP_REST_Block_Renderer_Controller::get_item()
     294         */
     295        public function test_get_item_unrecognized_attribute() {
     296                wp_set_current_user( self::$user_id );
     297                $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name );
     298                $request->set_param( 'context', 'edit' );
     299                $request->set_param(
     300                        'attributes',
     301                        array(
     302                                'unrecognized' => 'yes',
     303                        )
     304                );
     305                $response = rest_get_server()->dispatch( $request );
     306                $this->assertEquals( 400, $response->get_status() );
     307        }
     308
     309        /**
     310         * Check getting item with default attributes provided.
     311         *
     312         * @ticket 45098
     313         *
     314         * @covers WP_REST_Block_Renderer_Controller::get_item()
     315         */
     316        public function test_get_item_default_attributes() {
     317                wp_set_current_user( self::$user_id );
     318
     319                $block_type = WP_Block_Type_Registry::get_instance()->get_registered( self::$block_name );
     320                $defaults   = array();
     321                foreach ( $block_type->attributes as $key => $attribute ) {
     322                        $defaults[ $key ] = isset( $attribute['default'] ) ? $attribute['default'] : null;
     323                }
     324
     325                $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name );
     326                $request->set_param( 'context', 'edit' );
     327                $request->set_param( 'attributes', array() );
     328                $response = rest_get_server()->dispatch( $request );
     329                $this->assertEquals( 200, $response->get_status() );
     330                $data = $response->get_data();
     331
     332                $this->assertEquals( $defaults, json_decode( $data['rendered'], true ) );
     333                $this->assertEquals(
     334                        json_decode( $block_type->render( $defaults ) ),
     335                        json_decode( $data['rendered'] )
     336                );
     337        }
     338
     339        /**
     340         * Check getting item with attributes provided.
     341         *
     342         * @ticket 45098
     343         *
     344         * @covers WP_REST_Block_Renderer_Controller::get_item()
     345         */
     346        public function test_get_item() {
     347                wp_set_current_user( self::$user_id );
     348
     349                $block_type = WP_Block_Type_Registry::get_instance()->get_registered( self::$block_name );
     350                $attributes = array(
     351                        'some_int'    => '123',
     352                        'some_string' => 'foo',
     353                        'some_array'  => array( 1, '2', 3 ),
     354                );
     355
     356                $expected_attributes               = $attributes;
     357                $expected_attributes['some_int']   = (int) $expected_attributes['some_int'];
     358                $expected_attributes['some_array'] = array_map( 'intval', $expected_attributes['some_array'] );
     359
     360                $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name );
     361                $request->set_param( 'context', 'edit' );
     362                $request->set_param( 'attributes', $attributes );
     363                $response = rest_get_server()->dispatch( $request );
     364                $this->assertEquals( 200, $response->get_status() );
     365                $data = $response->get_data();
     366
     367                $this->assertEquals( $expected_attributes, json_decode( $data['rendered'], true ) );
     368                $this->assertEquals(
     369                        json_decode( $block_type->render( $attributes ), true ),
     370                        json_decode( $data['rendered'], true )
     371                );
     372        }
     373
     374
     375
     376        /**
     377         * Check success response for getting item with layout attribute provided.
     378         *
     379         * @ticket 45098
     380         */
     381        public function test_get_item_with_layout() {
     382                wp_set_current_user( self::$user_id );
     383
     384                $attributes = array(
     385                        'layout' => 'foo',
     386                );
     387
     388                $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name );
     389                $request->set_param( 'context', 'edit' );
     390                $request->set_param( 'attributes', $attributes );
     391                $response = rest_get_server()->dispatch( $request );
     392                $this->assertEquals( 200, $response->get_status() );
     393        }
     394
     395        /**
     396         * Test getting item with post context.
     397         *
     398         * @ticket 45098
     399         */
     400        public function test_get_item_with_post_context() {
     401                wp_set_current_user( self::$user_id );
     402
     403                $expected_title = 'Test Post';
     404                $request        = new WP_REST_Request( 'GET', self::$rest_api_route . self::$context_block_name );
     405                $request->set_param( 'context', 'edit' );
     406
     407                // Test without post ID.
     408                $response = rest_get_server()->dispatch( $request );
     409
     410                $this->assertEquals( 200, $response->get_status() );
     411                $data = $response->get_data();
     412
     413                $this->assertTrue( empty( $data['rendered'] ) );
     414
     415                // Now test with post ID.
     416                $request->set_param( 'post_id', self::$post_id );
     417                $response = rest_get_server()->dispatch( $request );
     418
     419                $this->assertEquals( 200, $response->get_status() );
     420                $data = $response->get_data();
     421
     422                $this->assertEquals( $expected_title, $data['rendered'] );
     423        }
     424
     425        /**
     426         * Test getting item with invalid post ID.
     427         *
     428         * @ticket 45098
     429         */
     430        public function test_get_item_without_permissions_invalid_post() {
     431                wp_set_current_user( self::$user_id );
     432
     433                $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$context_block_name );
     434                $request->set_param( 'context', 'edit' );
     435
     436                // Test with invalid post ID.
     437                $request->set_param( 'post_id', PHP_INT_MAX );
     438                $response = rest_get_server()->dispatch( $request );
     439
     440                $this->assertErrorResponse( 'block_cannot_read', $response, 403 );
     441        }
     442
     443        /**
     444         * Test getting item without permissions to edit context post.
     445         *
     446         * @ticket 45098
     447         */
     448        public function test_get_item_without_permissions_cannot_edit_post() {
     449                wp_set_current_user( self::$author_id );
     450
     451                $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$context_block_name );
     452                $request->set_param( 'context', 'edit' );
     453
     454                // Test with private post ID.
     455                $request->set_param( 'post_id', self::$post_id );
     456                $response = rest_get_server()->dispatch( $request );
     457
     458                $this->assertErrorResponse( 'block_cannot_read', $response, 403 );
     459        }
     460
     461        /**
     462         * Get item schema.
     463         *
     464         * @ticket 45098
     465         *
     466         * @covers WP_REST_Block_Renderer_Controller::get_item_schema()
     467         */
     468        public function test_get_item_schema() {
     469                $request  = new WP_REST_Request( 'OPTIONS', self::$rest_api_route . self::$block_name );
     470                $response = rest_get_server()->dispatch( $request );
     471                $data     = $response->get_data();
     472
     473                $this->assertEqualSets( array( 'GET' ), $data['endpoints'][0]['methods'] );
     474                $this->assertEqualSets(
     475                        array( 'name', 'context', 'attributes', 'post_id' ),
     476                        array_keys( $data['endpoints'][0]['args'] )
     477                );
     478                $this->assertEquals( 'object', $data['endpoints'][0]['args']['attributes']['type'] );
     479
     480                $this->assertArrayHasKey( 'schema', $data );
     481                $this->assertEquals( 'rendered-block', $data['schema']['title'] );
     482                $this->assertEquals( 'object', $data['schema']['type'] );
     483                $this->arrayHasKey( 'rendered', $data['schema']['properties'] );
     484                $this->arrayHasKey( 'string', $data['schema']['properties']['rendered']['type'] );
     485                $this->assertEquals( array( 'edit' ), $data['schema']['properties']['rendered']['context'] );
     486        }
     487
     488        /**
     489         * The update_item() method does not exist for block rendering.
     490         */
     491        public function test_update_item() {
     492                $this->markTestSkipped( 'Controller does not implement update_item().' );
     493        }
     494
     495        /**
     496         * The create_item() method does not exist for block rendering.
     497         */
     498        public function test_create_item() {
     499                $this->markTestSkipped( 'Controller does not implement create_item().' );
     500        }
     501
     502        /**
     503         * The delete_item() method does not exist for block rendering.
     504         */
     505        public function test_delete_item() {
     506                $this->markTestSkipped( 'Controller does not implement delete_item().' );
     507        }
     508
     509        /**
     510         * The get_items() method does not exist for block rendering.
     511         */
     512        public function test_get_items() {
     513                $this->markTestSkipped( 'Controller does not implement get_items().' );
     514        }
     515
     516        /**
     517         * The context_param() method does not exist for block rendering.
     518         */
     519        public function test_context_param() {
     520                $this->markTestSkipped( 'Controller does not implement context_param().' );
     521        }
     522
     523        /**
     524         * The prepare_item() method does not exist for block rendering.
     525         */
     526        public function test_prepare_item() {
     527                $this->markTestSkipped( 'Controller does not implement prepare_item().' );
     528        }
     529}
  • new file tests/phpunit/tests/rest-api/rest-blocks-controller.php

    diff --git a/tests/phpunit/tests/rest-api/rest-blocks-controller.php b/tests/phpunit/tests/rest-api/rest-blocks-controller.php
    new file mode 100644
    index 0000000000..70798b2756
    - +  
     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 */
     20class REST_Blocks_Controller_Test extends WP_UnitTestCase {
     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         * @since 5.0.0
     44         *
     45         * @param WP_UnitTest_Factory $factory Helper that lets us create fake data.
     46         */
     47        public static function wpSetUpBeforeClass( $factory ) {
     48                self::$post_id = wp_insert_post(
     49                        array(
     50                                'post_type'    => 'wp_block',
     51                                'post_status'  => 'publish',
     52                                'post_title'   => 'My cool block',
     53                                'post_content' => '<!-- wp:core/paragraph --><p>Hello!</p><!-- /wp:core/paragraph -->',
     54                        )
     55                );
     56
     57                self::$user_id = $factory->user->create(
     58                        array(
     59                                'role' => 'editor',
     60                        )
     61                );
     62        }
     63
     64        /**
     65         * Delete our fake data after our tests run.
     66         *
     67         * @since 5.0.0
     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         * Test cases for test_capabilities().
     77         *
     78         * @since 5.0.0
     79         */
     80        public function data_capabilities() {
     81                return array(
     82                        array( 'create', 'editor', 201 ),
     83                        array( 'create', 'author', 201 ),
     84                        array( 'create', 'contributor', 403 ),
     85                        array( 'create', null, 401 ),
     86
     87                        array( 'read', 'editor', 200 ),
     88                        array( 'read', 'author', 200 ),
     89                        array( 'read', 'contributor', 200 ),
     90                        array( 'read', null, 401 ),
     91
     92                        array( 'update_delete_own', 'editor', 200 ),
     93                        array( 'update_delete_own', 'author', 200 ),
     94                        array( 'update_delete_own', 'contributor', 403 ),
     95
     96                        array( 'update_delete_others', 'editor', 200 ),
     97                        array( 'update_delete_others', 'author', 403 ),
     98                        array( 'update_delete_others', 'contributor', 403 ),
     99                        array( 'update_delete_others', null, 401 ),
     100                );
     101        }
     102
     103        /**
     104         * Exhaustively check that each role either can or cannot create, edit,
     105         * update, and delete reusable blocks.
     106         *
     107         * @ticket 45098
     108         *
     109         * @dataProvider data_capabilities
     110         *
     111         * @param string $action          Action to perform in the test.
     112         * @param string $role            User role to test.
     113         * @param int    $expected_status Expected HTTP response status.
     114         */
     115        public function test_capabilities( $action, $role, $expected_status ) {
     116                if ( $role ) {
     117                        $user_id = $this->factory->user->create( array( 'role' => $role ) );
     118                        wp_set_current_user( $user_id );
     119                } else {
     120                        wp_set_current_user( 0 );
     121                }
     122
     123                switch ( $action ) {
     124                        case 'create':
     125                                $request = new WP_REST_Request( 'POST', '/wp/v2/blocks' );
     126                                $request->set_body_params(
     127                                        array(
     128                                                'title'   => 'Test',
     129                                                'content' => '<!-- wp:core/paragraph --><p>Test</p><!-- /wp:core/paragraph -->',
     130                                        )
     131                                );
     132
     133                                $response = rest_get_server()->dispatch( $request );
     134                                $this->assertEquals( $expected_status, $response->get_status() );
     135
     136                                break;
     137
     138                        case 'read':
     139                                $request = new WP_REST_Request( 'GET', '/wp/v2/blocks/' . self::$post_id );
     140
     141                                $response = rest_get_server()->dispatch( $request );
     142                                $this->assertEquals( $expected_status, $response->get_status() );
     143
     144                                break;
     145
     146                        case 'update_delete_own':
     147                                $post_id = wp_insert_post(
     148                                        array(
     149                                                'post_type'    => 'wp_block',
     150                                                'post_status'  => 'publish',
     151                                                'post_title'   => 'My cool block',
     152                                                'post_content' => '<!-- wp:core/paragraph --><p>Hello!</p><!-- /wp:core/paragraph -->',
     153                                                'post_author'  => $user_id,
     154                                        )
     155                                );
     156
     157                                $request = new WP_REST_Request( 'PUT', '/wp/v2/blocks/' . $post_id );
     158                                $request->set_body_params(
     159                                        array(
     160                                                'title'   => 'Test',
     161                                                'content' => '<!-- wp:core/paragraph --><p>Test</p><!-- /wp:core/paragraph -->',
     162                                        )
     163                                );
     164
     165                                $response = rest_get_server()->dispatch( $request );
     166                                $this->assertEquals( $expected_status, $response->get_status() );
     167
     168                                $request = new WP_REST_Request( 'DELETE', '/wp/v2/blocks/' . $post_id );
     169
     170                                $response = rest_get_server()->dispatch( $request );
     171                                $this->assertEquals( $expected_status, $response->get_status() );
     172
     173                                wp_delete_post( $post_id );
     174
     175                                break;
     176
     177                        case 'update_delete_others':
     178                                $request = new WP_REST_Request( 'PUT', '/wp/v2/blocks/' . self::$post_id );
     179                                $request->set_body_params(
     180                                        array(
     181                                                'title'   => 'Test',
     182                                                'content' => '<!-- wp:core/paragraph --><p>Test</p><!-- /wp:core/paragraph -->',
     183                                        )
     184                                );
     185
     186                                $response = rest_get_server()->dispatch( $request );
     187                                $this->assertEquals( $expected_status, $response->get_status() );
     188
     189                                $request = new WP_REST_Request( 'DELETE', '/wp/v2/blocks/' . self::$post_id );
     190
     191                                $response = rest_get_server()->dispatch( $request );
     192                                $this->assertEquals( $expected_status, $response->get_status() );
     193
     194                                break;
     195
     196                        default:
     197                                $this->fail( "'$action' is not a valid action." );
     198                }
     199
     200                if ( isset( $user_id ) ) {
     201                        self::delete_user( $user_id );
     202                }
     203        }
     204}
  • tests/phpunit/tests/rest-api/rest-schema-setup.php

    diff --git a/tests/phpunit/tests/rest-api/rest-schema-setup.php b/tests/phpunit/tests/rest-api/rest-schema-setup.php
    index 70330b7f03..e9de00aa4f 100644
    a b class WP_Test_REST_Schema_Initialization extends WP_Test_REST_TestCase { 
    9999                        '/wp/v2/pages/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)',
    100100                        '/wp/v2/media',
    101101                        '/wp/v2/media/(?P<id>[\\d]+)',
     102                        '/wp/v2/blocks',
     103                        '/wp/v2/blocks/(?P<id>[\d]+)',
     104                        '/wp/v2/blocks/(?P<parent>[\d]+)/autosaves',
     105                        '/wp/v2/blocks/(?P<parent>[\d]+)/autosaves/(?P<id>[\d]+)',
    102106                        '/wp/v2/types',
    103107                        '/wp/v2/types/(?P<type>[\\w-]+)',
    104108                        '/wp/v2/statuses',
  • tests/qunit/fixtures/wp-api-generated.js

    diff --git a/tests/qunit/fixtures/wp-api-generated.js b/tests/qunit/fixtures/wp-api-generated.js
    index 8a236da00d..8576875105 100644
    a b mockedApiResponse.Schema = { 
    22712271                }
    22722272            ]
    22732273        },
     2274        "/wp/v2/blocks": {
     2275            "namespace": "wp/v2",
     2276            "methods": [
     2277                "GET",
     2278                "POST"
     2279            ],
     2280            "endpoints": [
     2281                {
     2282                    "methods": [
     2283                        "GET"
     2284                    ],
     2285                    "args": {
     2286                        "context": {
     2287                            "required": false,
     2288                            "default": "view",
     2289                            "enum": [
     2290                                "view",
     2291                                "embed",
     2292                                "edit"
     2293                            ],
     2294                            "description": "Scope under which the request is made; determines fields present in response.",
     2295                            "type": "string"
     2296                        },
     2297                        "page": {
     2298                            "required": false,
     2299                            "default": 1,
     2300                            "description": "Current page of the collection.",
     2301                            "type": "integer"
     2302                        },
     2303                        "per_page": {
     2304                            "required": false,
     2305                            "default": 10,
     2306                            "description": "Maximum number of items to be returned in result set.",
     2307                            "type": "integer"
     2308                        },
     2309                        "search": {
     2310                            "required": false,
     2311                            "description": "Limit results to those matching a string.",
     2312                            "type": "string"
     2313                        },
     2314                        "after": {
     2315                            "required": false,
     2316                            "description": "Limit response to posts published after a given ISO8601 compliant date.",
     2317                            "type": "string"
     2318                        },
     2319                        "before": {
     2320                            "required": false,
     2321                            "description": "Limit response to posts published before a given ISO8601 compliant date.",
     2322                            "type": "string"
     2323                        },
     2324                        "exclude": {
     2325                            "required": false,
     2326                            "default": [],
     2327                            "description": "Ensure result set excludes specific IDs.",
     2328                            "type": "array",
     2329                            "items": {
     2330                                "type": "integer"
     2331                            }
     2332                        },
     2333                        "include": {
     2334                            "required": false,
     2335                            "default": [],
     2336                            "description": "Limit result set to specific IDs.",
     2337                            "type": "array",
     2338                            "items": {
     2339                                "type": "integer"
     2340                            }
     2341                        },
     2342                        "offset": {
     2343                            "required": false,
     2344                            "description": "Offset the result set by a specific number of items.",
     2345                            "type": "integer"
     2346                        },
     2347                        "order": {
     2348                            "required": false,
     2349                            "default": "desc",
     2350                            "enum": [
     2351                                "asc",
     2352                                "desc"
     2353                            ],
     2354                            "description": "Order sort attribute ascending or descending.",
     2355                            "type": "string"
     2356                        },
     2357                        "orderby": {
     2358                            "required": false,
     2359                            "default": "date",
     2360                            "enum": [
     2361                                "author",
     2362                                "date",
     2363                                "id",
     2364                                "include",
     2365                                "modified",
     2366                                "parent",
     2367                                "relevance",
     2368                                "slug",
     2369                                "include_slugs",
     2370                                "title"
     2371                            ],
     2372                            "description": "Sort collection by object attribute.",
     2373                            "type": "string"
     2374                        },
     2375                        "slug": {
     2376                            "required": false,
     2377                            "description": "Limit result set to posts with one or more specific slugs.",
     2378                            "type": "array",
     2379                            "items": {
     2380                                "type": "string"
     2381                            }
     2382                        },
     2383                        "status": {
     2384                            "required": false,
     2385                            "default": "publish",
     2386                            "description": "Limit result set to posts assigned one or more statuses.",
     2387                            "type": "array",
     2388                            "items": {
     2389                                "enum": [
     2390                                    "publish",
     2391                                    "future",
     2392                                    "draft",
     2393                                    "pending",
     2394                                    "private",
     2395                                    "trash",
     2396                                    "auto-draft",
     2397                                    "inherit",
     2398                                    "request-pending",
     2399                                    "request-confirmed",
     2400                                    "request-failed",
     2401                                    "request-completed",
     2402                                    "any"
     2403                                ],
     2404                                "type": "string"
     2405                            }
     2406                        }
     2407                    }
     2408                },
     2409                {
     2410                    "methods": [
     2411                        "POST"
     2412                    ],
     2413                    "args": {
     2414                        "date": {
     2415                            "required": false,
     2416                            "description": "The date the object was published, in the site's timezone.",
     2417                            "type": "string"
     2418                        },
     2419                        "date_gmt": {
     2420                            "required": false,
     2421                            "description": "The date the object was published, as GMT.",
     2422                            "type": "string"
     2423                        },
     2424                        "slug": {
     2425                            "required": false,
     2426                            "description": "An alphanumeric identifier for the object unique to its type.",
     2427                            "type": "string"
     2428                        },
     2429                        "status": {
     2430                            "required": false,
     2431                            "enum": [
     2432                                "publish",
     2433                                "future",
     2434                                "draft",
     2435                                "pending",
     2436                                "private"
     2437                            ],
     2438                            "description": "A named status for the object.",
     2439                            "type": "string"
     2440                        },
     2441                        "password": {
     2442                            "required": false,
     2443                            "description": "A password to protect access to the content and excerpt.",
     2444                            "type": "string"
     2445                        },
     2446                        "title": {
     2447                            "required": false,
     2448                            "description": "The title for the object.",
     2449                            "type": "object"
     2450                        },
     2451                        "content": {
     2452                            "required": false,
     2453                            "description": "The content for the object.",
     2454                            "type": "object"
     2455                        },
     2456                        "template": {
     2457                            "required": false,
     2458                            "description": "The theme file to use to display the object.",
     2459                            "type": "string"
     2460                        }
     2461                    }
     2462                }
     2463            ],
     2464            "_links": {
     2465                "self": "http://example.org/index.php?rest_route=/wp/v2/blocks"
     2466            }
     2467        },
     2468        "/wp/v2/blocks/(?P<id>[\\d]+)": {
     2469            "namespace": "wp/v2",
     2470            "methods": [
     2471                "GET",
     2472                "POST",
     2473                "PUT",
     2474                "PATCH",
     2475                "DELETE"
     2476            ],
     2477            "endpoints": [
     2478                {
     2479                    "methods": [
     2480                        "GET"
     2481                    ],
     2482                    "args": {
     2483                        "id": {
     2484                            "required": false,
     2485                            "description": "Unique identifier for the object.",
     2486                            "type": "integer"
     2487                        },
     2488                        "context": {
     2489                            "required": false,
     2490                            "default": "view",
     2491                            "enum": [
     2492                                "view",
     2493                                "embed",
     2494                                "edit"
     2495                            ],
     2496                            "description": "Scope under which the request is made; determines fields present in response.",
     2497                            "type": "string"
     2498                        },
     2499                        "password": {
     2500                            "required": false,
     2501                            "description": "The password for the post if it is password protected.",
     2502                            "type": "string"
     2503                        }
     2504                    }
     2505                },
     2506                {
     2507                    "methods": [
     2508                        "POST",
     2509                        "PUT",
     2510                        "PATCH"
     2511                    ],
     2512                    "args": {
     2513                        "id": {
     2514                            "required": false,
     2515                            "description": "Unique identifier for the object.",
     2516                            "type": "integer"
     2517                        },
     2518                        "date": {
     2519                            "required": false,
     2520                            "description": "The date the object was published, in the site's timezone.",
     2521                            "type": "string"
     2522                        },
     2523                        "date_gmt": {
     2524                            "required": false,
     2525                            "description": "The date the object was published, as GMT.",
     2526                            "type": "string"
     2527                        },
     2528                        "slug": {
     2529                            "required": false,
     2530                            "description": "An alphanumeric identifier for the object unique to its type.",
     2531                            "type": "string"
     2532                        },
     2533                        "status": {
     2534                            "required": false,
     2535                            "enum": [
     2536                                "publish",
     2537                                "future",
     2538                                "draft",
     2539                                "pending",
     2540                                "private"
     2541                            ],
     2542                            "description": "A named status for the object.",
     2543                            "type": "string"
     2544                        },
     2545                        "password": {
     2546                            "required": false,
     2547                            "description": "A password to protect access to the content and excerpt.",
     2548                            "type": "string"
     2549                        },
     2550                        "title": {
     2551                            "required": false,
     2552                            "description": "The title for the object.",
     2553                            "type": "object"
     2554                        },
     2555                        "content": {
     2556                            "required": false,
     2557                            "description": "The content for the object.",
     2558                            "type": "object"
     2559                        },
     2560                        "template": {
     2561                            "required": false,
     2562                            "description": "The theme file to use to display the object.",
     2563                            "type": "string"
     2564                        }
     2565                    }
     2566                },
     2567                {
     2568                    "methods": [
     2569                        "DELETE"
     2570                    ],
     2571                    "args": {
     2572                        "id": {
     2573                            "required": false,
     2574                            "description": "Unique identifier for the object.",
     2575                            "type": "integer"
     2576                        },
     2577                        "force": {
     2578                            "required": false,
     2579                            "default": false,
     2580                            "description": "Whether to bypass trash and force deletion.",
     2581                            "type": "boolean"
     2582                        }
     2583                    }
     2584                }
     2585            ]
     2586        },
     2587        "/wp/v2/blocks/(?P<parent>[\\d]+)/autosaves": {
     2588            "namespace": "wp/v2",
     2589            "methods": [
     2590                "GET",
     2591                "POST"
     2592            ],
     2593            "endpoints": [
     2594                {
     2595                    "methods": [
     2596                        "GET"
     2597                    ],
     2598                    "args": {
     2599                        "parent": {
     2600                            "required": false,
     2601                            "description": "The ID for the parent of the object.",
     2602                            "type": "integer"
     2603                        },
     2604                        "context": {
     2605                            "required": false,
     2606                            "default": "view",
     2607                            "enum": [
     2608                                "view",
     2609                                "embed",
     2610                                "edit"
     2611                            ],
     2612                            "description": "Scope under which the request is made; determines fields present in response.",
     2613                            "type": "string"
     2614                        },
     2615                        "page": {
     2616                            "required": false,
     2617                            "default": 1,
     2618                            "description": "Current page of the collection.",
     2619                            "type": "integer"
     2620                        },
     2621                        "per_page": {
     2622                            "required": false,
     2623                            "description": "Maximum number of items to be returned in result set.",
     2624                            "type": "integer"
     2625                        },
     2626                        "search": {
     2627                            "required": false,
     2628                            "description": "Limit results to those matching a string.",
     2629                            "type": "string"
     2630                        },
     2631                        "exclude": {
     2632                            "required": false,
     2633                            "default": [],
     2634                            "description": "Ensure result set excludes specific IDs.",
     2635                            "type": "array",
     2636                            "items": {
     2637                                "type": "integer"
     2638                            }
     2639                        },
     2640                        "include": {
     2641                            "required": false,
     2642                            "default": [],
     2643                            "description": "Limit result set to specific IDs.",
     2644                            "type": "array",
     2645                            "items": {
     2646                                "type": "integer"
     2647                            }
     2648                        },
     2649                        "offset": {
     2650                            "required": false,
     2651                            "description": "Offset the result set by a specific number of items.",
     2652                            "type": "integer"
     2653                        },
     2654                        "order": {
     2655                            "required": false,
     2656                            "default": "desc",
     2657                            "enum": [
     2658                                "asc",
     2659                                "desc"
     2660                            ],
     2661                            "description": "Order sort attribute ascending or descending.",
     2662                            "type": "string"
     2663                        },
     2664                        "orderby": {
     2665                            "required": false,
     2666                            "default": "date",
     2667                            "enum": [
     2668                                "date",
     2669                                "id",
     2670                                "include",
     2671                                "relevance",
     2672                                "slug",
     2673                                "include_slugs",
     2674                                "title"
     2675                            ],
     2676                            "description": "Sort collection by object attribute.",
     2677                            "type": "string"
     2678                        }
     2679                    }
     2680                },
     2681                {
     2682                    "methods": [
     2683                        "POST"
     2684                    ],
     2685                    "args": {
     2686                        "parent": {
     2687                            "required": false,
     2688                            "description": "The ID for the parent of the object.",
     2689                            "type": "integer"
     2690                        },
     2691                        "author": {
     2692                            "required": false,
     2693                            "description": "The ID for the author of the object.",
     2694                            "type": "integer"
     2695                        },
     2696                        "date": {
     2697                            "required": false,
     2698                            "description": "The date the object was published, in the site's timezone.",
     2699                            "type": "string"
     2700                        },
     2701                        "date_gmt": {
     2702                            "required": false,
     2703                            "description": "The date the object was published, as GMT.",
     2704                            "type": "string"
     2705                        },
     2706                        "id": {
     2707                            "required": false,
     2708                            "description": "Unique identifier for the object.",
     2709                            "type": "integer"
     2710                        },
     2711                        "modified": {
     2712                            "required": false,
     2713                            "description": "The date the object was last modified, in the site's timezone.",
     2714                            "type": "string"
     2715                        },
     2716                        "modified_gmt": {
     2717                            "required": false,
     2718                            "description": "The date the object was last modified, as GMT.",
     2719                            "type": "string"
     2720                        },
     2721                        "slug": {
     2722                            "required": false,
     2723                            "description": "An alphanumeric identifier for the object unique to its type.",
     2724                            "type": "string"
     2725                        },
     2726                        "title": {
     2727                            "required": false,
     2728                            "description": "The title for the object.",
     2729                            "type": "object"
     2730                        },
     2731                        "content": {
     2732                            "required": false,
     2733                            "description": "The content for the object.",
     2734                            "type": "object"
     2735                        }
     2736                    }
     2737                }
     2738            ]
     2739        },
     2740        "/wp/v2/blocks/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)": {
     2741            "namespace": "wp/v2",
     2742            "methods": [
     2743                "GET"
     2744            ],
     2745            "endpoints": [
     2746                {
     2747                    "methods": [
     2748                        "GET"
     2749                    ],
     2750                    "args": {
     2751                        "parent": {
     2752                            "required": false,
     2753                            "description": "The ID for the parent of the object.",
     2754                            "type": "integer"
     2755                        },
     2756                        "id": {
     2757                            "required": false,
     2758                            "description": "The ID for the object.",
     2759                            "type": "integer"
     2760                        },
     2761                        "context": {
     2762                            "required": false,
     2763                            "default": "view",
     2764                            "enum": [
     2765                                "view",
     2766                                "embed",
     2767                                "edit"
     2768                            ],
     2769                            "description": "Scope under which the request is made; determines fields present in response.",
     2770                            "type": "string"
     2771                        }
     2772                    }
     2773                }
     2774            ]
     2775        },
    22742776        "/wp/v2/types": {
    22752777            "namespace": "wp/v2",
    22762778            "methods": [
    mockedApiResponse.Schema = { 
    38624364                "self": "http://example.org/index.php?rest_route=/wp/v2/search"
    38634365            }
    38644366        },
     4367        "/wp/v2/block-renderer/(?P<name>core/block)": {
     4368            "namespace": "wp/v2",
     4369            "methods": [
     4370                "GET"
     4371            ],
     4372            "endpoints": [
     4373                {
     4374                    "methods": [
     4375                        "GET"
     4376                    ],
     4377                    "args": {
     4378                        "name": {
     4379                            "required": false,
     4380                            "description": "Unique registered name for the block.",
     4381                            "type": "string"
     4382                        },
     4383                        "context": {
     4384                            "required": false,
     4385                            "default": "view",
     4386                            "enum": [
     4387                                "edit"
     4388                            ],
     4389                            "description": "Scope under which the request is made; determines fields present in response.",
     4390                            "type": "string"
     4391                        },
     4392                        "attributes": {
     4393                            "required": false,
     4394                            "description": "Attributes for core/block block",
     4395                            "type": "object"
     4396                        },
     4397                        "post_id": {
     4398                            "required": false,
     4399                            "description": "ID of the post context.",
     4400                            "type": "integer"
     4401                        }
     4402                    }
     4403                }
     4404            ]
     4405        },
     4406        "/wp/v2/block-renderer/(?P<name>core/latest-comments)": {
     4407            "namespace": "wp/v2",
     4408            "methods": [
     4409                "GET"
     4410            ],
     4411            "endpoints": [
     4412                {
     4413                    "methods": [
     4414                        "GET"
     4415                    ],
     4416                    "args": {
     4417                        "name": {
     4418                            "required": false,
     4419                            "description": "Unique registered name for the block.",
     4420                            "type": "string"
     4421                        },
     4422                        "context": {
     4423                            "required": false,
     4424                            "default": "view",
     4425                            "enum": [
     4426                                "edit"
     4427                            ],
     4428                            "description": "Scope under which the request is made; determines fields present in response.",
     4429                            "type": "string"
     4430                        },
     4431                        "attributes": {
     4432                            "required": false,
     4433                            "description": "Attributes for core/latest-comments block",
     4434                            "type": "object"
     4435                        },
     4436                        "post_id": {
     4437                            "required": false,
     4438                            "description": "ID of the post context.",
     4439                            "type": "integer"
     4440                        }
     4441                    }
     4442                }
     4443            ]
     4444        },
     4445        "/wp/v2/block-renderer/(?P<name>core/archives)": {
     4446            "namespace": "wp/v2",
     4447            "methods": [
     4448                "GET"
     4449            ],
     4450            "endpoints": [
     4451                {
     4452                    "methods": [
     4453                        "GET"
     4454                    ],
     4455                    "args": {
     4456                        "name": {
     4457                            "required": false,
     4458                            "description": "Unique registered name for the block.",
     4459                            "type": "string"
     4460                        },
     4461                        "context": {
     4462                            "required": false,
     4463                            "default": "view",
     4464                            "enum": [
     4465                                "edit"
     4466                            ],
     4467                            "description": "Scope under which the request is made; determines fields present in response.",
     4468                            "type": "string"
     4469                        },
     4470                        "attributes": {
     4471                            "required": false,
     4472                            "description": "Attributes for core/archives block",
     4473                            "type": "object"
     4474                        },
     4475                        "post_id": {
     4476                            "required": false,
     4477                            "description": "ID of the post context.",
     4478                            "type": "integer"
     4479                        }
     4480                    }
     4481                }
     4482            ]
     4483        },
     4484        "/wp/v2/block-renderer/(?P<name>core/categories)": {
     4485            "namespace": "wp/v2",
     4486            "methods": [
     4487                "GET"
     4488            ],
     4489            "endpoints": [
     4490                {
     4491                    "methods": [
     4492                        "GET"
     4493                    ],
     4494                    "args": {
     4495                        "name": {
     4496                            "required": false,
     4497                            "description": "Unique registered name for the block.",
     4498                            "type": "string"
     4499                        },
     4500                        "context": {
     4501                            "required": false,
     4502                            "default": "view",
     4503                            "enum": [
     4504                                "edit"
     4505                            ],
     4506                            "description": "Scope under which the request is made; determines fields present in response.",
     4507                            "type": "string"
     4508                        },
     4509                        "attributes": {
     4510                            "required": false,
     4511                            "description": "Attributes for core/categories block",
     4512                            "type": "object"
     4513                        },
     4514                        "post_id": {
     4515                            "required": false,
     4516                            "description": "ID of the post context.",
     4517                            "type": "integer"
     4518                        }
     4519                    }
     4520                }
     4521            ]
     4522        },
     4523        "/wp/v2/block-renderer/(?P<name>core/latest-posts)": {
     4524            "namespace": "wp/v2",
     4525            "methods": [
     4526                "GET"
     4527            ],
     4528            "endpoints": [
     4529                {
     4530                    "methods": [
     4531                        "GET"
     4532                    ],
     4533                    "args": {
     4534                        "name": {
     4535                            "required": false,
     4536                            "description": "Unique registered name for the block.",
     4537                            "type": "string"
     4538                        },
     4539                        "context": {
     4540                            "required": false,
     4541                            "default": "view",
     4542                            "enum": [
     4543                                "edit"
     4544                            ],
     4545                            "description": "Scope under which the request is made; determines fields present in response.",
     4546                            "type": "string"
     4547                        },
     4548                        "attributes": {
     4549                            "required": false,
     4550                            "description": "Attributes for core/latest-posts block",
     4551                            "type": "object"
     4552                        },
     4553                        "post_id": {
     4554                            "required": false,
     4555                            "description": "ID of the post context.",
     4556                            "type": "integer"
     4557                        }
     4558                    }
     4559                }
     4560            ]
     4561        },
     4562        "/wp/v2/block-renderer/(?P<name>core/shortcode)": {
     4563            "namespace": "wp/v2",
     4564            "methods": [
     4565                "GET"
     4566            ],
     4567            "endpoints": [
     4568                {
     4569                    "methods": [
     4570                        "GET"
     4571                    ],
     4572                    "args": {
     4573                        "name": {
     4574                            "required": false,
     4575                            "description": "Unique registered name for the block.",
     4576                            "type": "string"
     4577                        },
     4578                        "context": {
     4579                            "required": false,
     4580                            "default": "view",
     4581                            "enum": [
     4582                                "edit"
     4583                            ],
     4584                            "description": "Scope under which the request is made; determines fields present in response.",
     4585                            "type": "string"
     4586                        },
     4587                        "attributes": {
     4588                            "required": false,
     4589                            "description": "Attributes for core/shortcode block",
     4590                            "type": "object"
     4591                        },
     4592                        "post_id": {
     4593                            "required": false,
     4594                            "description": "ID of the post context.",
     4595                            "type": "integer"
     4596                        }
     4597                    }
     4598                }
     4599            ]
     4600        },
    38654601        "/wp/v2/settings": {
    38664602            "namespace": "wp/v2",
    38674603            "methods": [
    mockedApiResponse.postRevisions = [ 
    43395075        }
    43405076    },
    43415077    {
    4342         "author": 389,
     5078        "author": 404,
    43435079        "date": "2017-02-14T00:00:00",
    43445080        "date_gmt": "2017-02-14T00:00:00",
    4345         "id": 36710,
     5081        "id": 36717,
    43465082        "modified": "2017-02-14T00:00:00",
    43475083        "modified_gmt": "2017-02-14T00:00:00",
    4348         "parent": 36709,
    4349         "slug": "36709-revision-v1",
     5084        "parent": 36716,
     5085        "slug": "36716-revision-v1",
    43505086        "guid": {
    4351             "rendered": "http://example.org/?p=36710"
     5087            "rendered": "http://example.org/?p=36717"
    43525088        },
    43535089        "title": {
    43545090            "rendered": "REST API Client Fixture: Post"
    mockedApiResponse.postRevisions = [ 
    43625098        "_links": {
    43635099            "parent": [
    43645100                {
    4365                     "href": "http://example.org/index.php?rest_route=/wp/v2/posts/36709"
     5101                    "href": "http://example.org/index.php?rest_route=/wp/v2/posts/36716"
    43665102                }
    43675103            ]
    43685104        }
    mockedApiResponse.revision = { 
    43945130
    43955131mockedApiResponse.postAutosaves = [
    43965132    {
    4397         "author": 389,
     5133        "author": 404,
    43985134        "date": "2017-02-14T00:00:00",
    43995135        "date_gmt": "2017-02-14T00:00:00",
    4400         "id": 36711,
     5136        "id": 36718,
    44015137        "modified": "2017-02-14T00:00:00",
    44025138        "modified_gmt": "2017-02-14T00:00:00",
    4403         "parent": 36709,
    4404         "slug": "36709-autosave-v1",
     5139        "parent": 36716,
     5140        "slug": "36716-autosave-v1",
    44055141        "guid": {
    4406             "rendered": "http://example.org/?p=36711"
     5142            "rendered": "http://example.org/?p=36718"
    44075143        },
    44085144        "title": {
    44095145            "rendered": ""
    mockedApiResponse.postAutosaves = [ 
    44175153        "_links": {
    44185154            "parent": [
    44195155                {
    4420                     "href": "http://example.org/index.php?rest_route=/wp/v2/posts/36709"
     5156                    "href": "http://example.org/index.php?rest_route=/wp/v2/posts/36716"
    44215157                }
    44225158            ]
    44235159        }
    mockedApiResponse.postAutosaves = [ 
    44255161];
    44265162
    44275163mockedApiResponse.autosave = {
    4428     "author": 389,
     5164    "author": 404,
    44295165    "date": "2017-02-14T00:00:00",
    44305166    "date_gmt": "2017-02-14T00:00:00",
    4431     "id": 36711,
     5167    "id": 36718,
    44325168    "modified": "2017-02-14T00:00:00",
    44335169    "modified_gmt": "2017-02-14T00:00:00",
    4434     "parent": 36709,
    4435     "slug": "36709-autosave-v1",
     5170    "parent": 36716,
     5171    "slug": "36716-autosave-v1",
    44365172    "guid": {
    4437         "rendered": "http://example.org/?p=36711"
     5173        "rendered": "http://example.org/?p=36718"
    44385174    },
    44395175    "title": {
    44405176        "rendered": ""
    mockedApiResponse.pageRevisions = [ 
    45995335        }
    46005336    },
    46015337    {
    4602         "author": 389,
     5338        "author": 404,
    46035339        "date": "2017-02-14T00:00:00",
    46045340        "date_gmt": "2017-02-14T00:00:00",
    4605         "id": 36713,
     5341        "id": 36720,
    46065342        "modified": "2017-02-14T00:00:00",
    46075343        "modified_gmt": "2017-02-14T00:00:00",
    4608         "parent": 36712,
    4609         "slug": "36712-revision-v1",
     5344        "parent": 36719,
     5345        "slug": "36719-revision-v1",
    46105346        "guid": {
    4611             "rendered": "http://example.org/?p=36713"
     5347            "rendered": "http://example.org/?p=36720"
    46125348        },
    46135349        "title": {
    46145350            "rendered": "REST API Client Fixture: Page"
    mockedApiResponse.pageRevisions = [ 
    46225358        "_links": {
    46235359            "parent": [
    46245360                {
    4625                     "href": "http://example.org/index.php?rest_route=/wp/v2/pages/36712"
     5361                    "href": "http://example.org/index.php?rest_route=/wp/v2/pages/36719"
    46265362                }
    46275363            ]
    46285364        }
    mockedApiResponse.pageRevision = { 
    46545390
    46555391mockedApiResponse.pageAutosaves = [
    46565392    {
    4657         "author": 389,
     5393        "author": 404,
    46585394        "date": "2017-02-14T00:00:00",
    46595395        "date_gmt": "2017-02-14T00:00:00",
    4660         "id": 36714,
     5396        "id": 36721,
    46615397        "modified": "2017-02-14T00:00:00",
    46625398        "modified_gmt": "2017-02-14T00:00:00",
    4663         "parent": 36712,
    4664         "slug": "36712-autosave-v1",
     5399        "parent": 36719,
     5400        "slug": "36719-autosave-v1",
    46655401        "guid": {
    4666             "rendered": "http://example.org/?p=36714"
     5402            "rendered": "http://example.org/?p=36721"
    46675403        },
    46685404        "title": {
    46695405            "rendered": ""
    mockedApiResponse.pageAutosaves = [ 
    46775413        "_links": {
    46785414            "parent": [
    46795415                {
    4680                     "href": "http://example.org/index.php?rest_route=/wp/v2/pages/36712"
     5416                    "href": "http://example.org/index.php?rest_route=/wp/v2/pages/36719"
    46815417                }
    46825418            ]
    46835419        }
    mockedApiResponse.pageAutosaves = [ 
    46855421];
    46865422
    46875423mockedApiResponse.pageAutosave = {
    4688     "author": 389,
     5424    "author": 404,
    46895425    "date": "2017-02-14T00:00:00",
    46905426    "date_gmt": "2017-02-14T00:00:00",
    4691     "id": 36714,
     5427    "id": 36721,
    46925428    "modified": "2017-02-14T00:00:00",
    46935429    "modified_gmt": "2017-02-14T00:00:00",
    4694     "parent": 36712,
    4695     "slug": "36712-autosave-v1",
     5430    "parent": 36719,
     5431    "slug": "36719-autosave-v1",
    46965432    "guid": {
    4697         "rendered": "http://example.org/?p=36714"
     5433        "rendered": "http://example.org/?p=36721"
    46985434    },
    46995435    "title": {
    47005436        "rendered": ""
    mockedApiResponse.TypesCollection = { 
    48905626                }
    48915627            ]
    48925628        }
     5629    },
     5630    "wp_block": {
     5631        "description": "",
     5632        "hierarchical": false,
     5633        "name": "Blocks",
     5634        "slug": "wp_block",
     5635        "taxonomies": [],
     5636        "rest_base": "blocks",
     5637        "_links": {
     5638            "collection": [
     5639                {
     5640                    "href": "http://example.org/index.php?rest_route=/wp/v2/types"
     5641                }
     5642            ],
     5643            "wp:items": [
     5644                {
     5645                    "href": "http://example.org/index.php?rest_route=/wp/v2/blocks"
     5646                }
     5647            ],
     5648            "curies": [
     5649                {
     5650                    "name": "wp",
     5651                    "href": "https://api.w.org/{rel}",
     5652                    "templated": true
     5653                }
     5654            ]
     5655        }
    48935656    }
    48945657};
    48955658