WordPress.org

Make WordPress Core

Changeset 48069


Ignore:
Timestamp:
06/17/2020 03:20:02 AM (6 months ago)
Author:
TimothyBlynJacobs
Message:

REST API: Only register one block renderer route.

Every block has a different set of attributes. These attributes are specified as a JSON Schema object. Previously, every block registered its own block renderer route using its attributes for the schema. This allowed for the attributes to be validated using the built in endpoint validation rules. It had the unfortunate side effect, however, of creating a large number of nearly identical REST API routes, one for each dynamic block. Each registered route has a performance impact. As the number of server side blocks goes up, this becomes more and more of an issue.

Now, we register a single block renderer route and dynamically validate the attributes based on the selected block.

Fixes #48079.
Props gziolo, TimothyBlynJacobs.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php

    r47756 r48069  
    3535     */
    3636    public function register_routes() {
    37         $block_types = WP_Block_Type_Registry::get_instance()->get_all_registered();
    38 
    39         foreach ( $block_types as $block_type ) {
    40             if ( ! $block_type->is_dynamic() ) {
    41                 continue;
    42             }
    43 
    44             register_rest_route(
    45                 $this->namespace,
    46                 '/' . $this->rest_base . '/(?P<name>' . $block_type->name . ')',
     37        register_rest_route(
     38            $this->namespace,
     39            '/' . $this->rest_base . '/(?P<name>[a-z0-9-]+/[a-z0-9-]+)',
     40            array(
     41                'args'   => array(
     42                    'name' => array(
     43                        'description' => __( 'Unique registered name for the block.' ),
     44                        'type'        => 'string',
     45                    ),
     46                ),
    4747                array(
    48                     'args'   => array(
    49                         'name' => array(
    50                             'description' => __( 'Unique registered name for the block.' ),
    51                             'type'        => 'string',
     48                    'methods'             => array( WP_REST_Server::READABLE, WP_REST_Server::CREATABLE ),
     49                    'callback'            => array( $this, 'get_item' ),
     50                    'permission_callback' => array( $this, 'get_item_permissions_check' ),
     51                    'args'                => array(
     52                        'context'    => $this->get_context_param( array( 'default' => 'view' ) ),
     53                        'attributes' => array(
     54                            'description'       => __( 'Attributes for the block' ),
     55                            'type'              => 'object',
     56                            'default'           => array(),
     57                            'validate_callback' => static function ( $value, $request ) {
     58                                $block = WP_Block_Type_Registry::get_instance()->get_registered( $request['name'] );
     59
     60                                if ( ! $block ) {
     61                                    // This will get rejected in ::get_item().
     62                                    return true;
     63                                }
     64
     65                                $schema = array(
     66                                    'type'                 => 'object',
     67                                    'properties'           => $block->get_attributes(),
     68                                    'additionalProperties' => false,
     69                                );
     70
     71                                return rest_validate_value_from_schema( $value, $schema );
     72                            },
     73                        ),
     74                        'post_id'    => array(
     75                            'description' => __( 'ID of the post context.' ),
     76                            'type'        => 'integer',
    5277                        ),
    5378                    ),
    54                     array(
    55                         'methods'             => array( WP_REST_Server::READABLE, WP_REST_Server::CREATABLE ),
    56                         'callback'            => array( $this, 'get_item' ),
    57                         'permission_callback' => array( $this, 'get_item_permissions_check' ),
    58                         'args'                => array(
    59                             'context'    => $this->get_context_param( array( 'default' => 'view' ) ),
    60                             'attributes' => array(
    61                                 /* translators: %s: The name of the block. */
    62                                 'description'          => sprintf( __( 'Attributes for %s block' ), $block_type->name ),
    63                                 'type'                 => 'object',
    64                                 'additionalProperties' => false,
    65                                 'properties'           => $block_type->get_attributes(),
    66                                 'default'              => array(),
    67                             ),
    68                             'post_id'    => array(
    69                                 'description' => __( 'ID of the post context.' ),
    70                                 'type'        => 'integer',
    71                             ),
    72                         ),
    73                     ),
    74                     'schema' => array( $this, 'get_public_item_schema' ),
    75                 )
    76             );
    77         }
     79                ),
     80                'schema' => array( $this, 'get_public_item_schema' ),
     81            )
     82        );
    7883    }
    7984
     
    137142            setup_postdata( $post );
    138143        }
    139         $registry = WP_Block_Type_Registry::get_instance();
    140 
    141         if ( null === $registry->get_registered( $request['name'] ) ) {
     144
     145        $registry   = WP_Block_Type_Registry::get_instance();
     146        $registered = $registry->get_registered( $request['name'] );
     147
     148        if ( null === $registered || ! $registered->is_dynamic() ) {
    142149            return new WP_Error(
    143150                'block_invalid',
  • trunk/tests/phpunit/tests/rest-api/rest-block-renderer-controller.php

    r47756 r48069  
    4848
    4949    /**
     50     * Non dynamic block name.
     51     *
     52     * @since 5.5.0
     53     *
     54     * @var string
     55     */
     56    protected static $non_dynamic_block_name = 'core/non-dynamic';
     57
     58    /**
    5059     * Test API user's ID.
    5160     *
     
    118127        $this->register_test_block();
    119128        $this->register_post_context_test_block();
     129        $this->register_non_dynamic_block();
    120130        parent::setUp();
    121131    }
     
    129139        WP_Block_Type_Registry::get_instance()->unregister( self::$block_name );
    130140        WP_Block_Type_Registry::get_instance()->unregister( self::$context_block_name );
     141        WP_Block_Type_Registry::get_instance()->unregister( self::$non_dynamic_block_name );
    131142        parent::tearDown();
    132143    }
     
    177188
    178189    /**
     190     * Registers the non-dynamic block name.
     191     *
     192     * @since 5.5.0
     193     */
     194    protected function register_non_dynamic_block() {
     195        register_block_type( self::$non_dynamic_block_name );
     196    }
     197
     198    /**
    179199     * Test render callback.
    180200     *
     
    211231
    212232        $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         }
     233        $this->assertArrayHasKey( self::$rest_api_route . '(?P<name>[a-z0-9-]+/[a-z0-9-]+)', $routes );
    216234    }
    217235
     
    262280        $response = rest_get_server()->dispatch( $request );
    263281
    264         $this->assertErrorResponse( 'rest_no_route', $response, 404 );
     282        $this->assertErrorResponse( 'block_invalid', $response, 404 );
    265283    }
    266284
     
    512530
    513531    /**
     532     * @ticket 48079
     533     */
     534    public function test_get_item_non_dynamic_block() {
     535        wp_set_current_user( self::$user_id );
     536        $request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$non_dynamic_block_name );
     537
     538        $request->set_param( 'context', 'edit' );
     539        $response = rest_get_server()->dispatch( $request );
     540
     541        $this->assertErrorResponse( 'block_invalid', $response, 404 );
     542    }
     543
     544    /**
    514545     * Get item schema.
    515546     *
  • trunk/tests/phpunit/tests/rest-api/rest-schema-setup.php

    r47250 r48069  
    121121            '/wp/v2/comments/(?P<id>[\\d]+)',
    122122            '/wp/v2/search',
    123             '/wp/v2/block-renderer/(?P<name>core/archives)',
    124             '/wp/v2/block-renderer/(?P<name>core/block)',
    125             '/wp/v2/block-renderer/(?P<name>core/calendar)',
    126             '/wp/v2/block-renderer/(?P<name>core/categories)',
    127             '/wp/v2/block-renderer/(?P<name>core/latest-comments)',
    128             '/wp/v2/block-renderer/(?P<name>core/latest-posts)',
    129             '/wp/v2/block-renderer/(?P<name>core/rss)',
    130             '/wp/v2/block-renderer/(?P<name>core/search)',
    131             '/wp/v2/block-renderer/(?P<name>core/shortcode)',
    132             '/wp/v2/block-renderer/(?P<name>core/social-link)',
    133             '/wp/v2/block-renderer/(?P<name>core/tag-cloud)',
     123            '/wp/v2/block-renderer/(?P<name>[a-z0-9-]+/[a-z0-9-]+)',
    134124            '/wp/v2/settings',
    135125            '/wp/v2/themes',
  • trunk/tests/qunit/fixtures/wp-api-generated.js

    r47757 r48069  
    43954395            }
    43964396        },
    4397         "/wp/v2/block-renderer/(?P<name>core/archives)": {
     4397        "/wp/v2/block-renderer/(?P<name>[a-z0-9-]+/[a-z0-9-]+)": {
    43984398            "namespace": "wp/v2",
    43994399            "methods": [
     
    44254425                            "required": false,
    44264426                            "default": [],
    4427                             "description": "Attributes for core/archives block",
    4428                             "type": "object"
    4429                         },
    4430                         "post_id": {
    4431                             "required": false,
    4432                             "description": "ID of the post context.",
    4433                             "type": "integer"
    4434                         }
    4435                     }
    4436                 }
    4437             ]
    4438         },
    4439         "/wp/v2/block-renderer/(?P<name>core/block)": {
    4440             "namespace": "wp/v2",
    4441             "methods": [
    4442                 "GET",
    4443                 "POST"
    4444             ],
    4445             "endpoints": [
    4446                 {
    4447                     "methods": [
    4448                         "GET",
    4449                         "POST"
    4450                     ],
    4451                     "args": {
    4452                         "name": {
    4453                             "required": false,
    4454                             "description": "Unique registered name for the block.",
    4455                             "type": "string"
    4456                         },
    4457                         "context": {
    4458                             "required": false,
    4459                             "default": "view",
    4460                             "enum": [
    4461                                 "edit"
    4462                             ],
    4463                             "description": "Scope under which the request is made; determines fields present in response.",
    4464                             "type": "string"
    4465                         },
    4466                         "attributes": {
    4467                             "required": false,
    4468                             "default": [],
    4469                             "description": "Attributes for core/block block",
    4470                             "type": "object"
    4471                         },
    4472                         "post_id": {
    4473                             "required": false,
    4474                             "description": "ID of the post context.",
    4475                             "type": "integer"
    4476                         }
    4477                     }
    4478                 }
    4479             ]
    4480         },
    4481         "/wp/v2/block-renderer/(?P<name>core/calendar)": {
    4482             "namespace": "wp/v2",
    4483             "methods": [
    4484                 "GET",
    4485                 "POST"
    4486             ],
    4487             "endpoints": [
    4488                 {
    4489                     "methods": [
    4490                         "GET",
    4491                         "POST"
    4492                     ],
    4493                     "args": {
    4494                         "name": {
    4495                             "required": false,
    4496                             "description": "Unique registered name for the block.",
    4497                             "type": "string"
    4498                         },
    4499                         "context": {
    4500                             "required": false,
    4501                             "default": "view",
    4502                             "enum": [
    4503                                 "edit"
    4504                             ],
    4505                             "description": "Scope under which the request is made; determines fields present in response.",
    4506                             "type": "string"
    4507                         },
    4508                         "attributes": {
    4509                             "required": false,
    4510                             "default": [],
    4511                             "description": "Attributes for core/calendar 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/categories)": {
    4524             "namespace": "wp/v2",
    4525             "methods": [
    4526                 "GET",
    4527                 "POST"
    4528             ],
    4529             "endpoints": [
    4530                 {
    4531                     "methods": [
    4532                         "GET",
    4533                         "POST"
    4534                     ],
    4535                     "args": {
    4536                         "name": {
    4537                             "required": false,
    4538                             "description": "Unique registered name for the block.",
    4539                             "type": "string"
    4540                         },
    4541                         "context": {
    4542                             "required": false,
    4543                             "default": "view",
    4544                             "enum": [
    4545                                 "edit"
    4546                             ],
    4547                             "description": "Scope under which the request is made; determines fields present in response.",
    4548                             "type": "string"
    4549                         },
    4550                         "attributes": {
    4551                             "required": false,
    4552                             "default": [],
    4553                             "description": "Attributes for core/categories block",
    4554                             "type": "object"
    4555                         },
    4556                         "post_id": {
    4557                             "required": false,
    4558                             "description": "ID of the post context.",
    4559                             "type": "integer"
    4560                         }
    4561                     }
    4562                 }
    4563             ]
    4564         },
    4565         "/wp/v2/block-renderer/(?P<name>core/latest-comments)": {
    4566             "namespace": "wp/v2",
    4567             "methods": [
    4568                 "GET",
    4569                 "POST"
    4570             ],
    4571             "endpoints": [
    4572                 {
    4573                     "methods": [
    4574                         "GET",
    4575                         "POST"
    4576                     ],
    4577                     "args": {
    4578                         "name": {
    4579                             "required": false,
    4580                             "description": "Unique registered name for the block.",
    4581                             "type": "string"
    4582                         },
    4583                         "context": {
    4584                             "required": false,
    4585                             "default": "view",
    4586                             "enum": [
    4587                                 "edit"
    4588                             ],
    4589                             "description": "Scope under which the request is made; determines fields present in response.",
    4590                             "type": "string"
    4591                         },
    4592                         "attributes": {
    4593                             "required": false,
    4594                             "default": [],
    4595                             "description": "Attributes for core/latest-comments block",
    4596                             "type": "object"
    4597                         },
    4598                         "post_id": {
    4599                             "required": false,
    4600                             "description": "ID of the post context.",
    4601                             "type": "integer"
    4602                         }
    4603                     }
    4604                 }
    4605             ]
    4606         },
    4607         "/wp/v2/block-renderer/(?P<name>core/latest-posts)": {
    4608             "namespace": "wp/v2",
    4609             "methods": [
    4610                 "GET",
    4611                 "POST"
    4612             ],
    4613             "endpoints": [
    4614                 {
    4615                     "methods": [
    4616                         "GET",
    4617                         "POST"
    4618                     ],
    4619                     "args": {
    4620                         "name": {
    4621                             "required": false,
    4622                             "description": "Unique registered name for the block.",
    4623                             "type": "string"
    4624                         },
    4625                         "context": {
    4626                             "required": false,
    4627                             "default": "view",
    4628                             "enum": [
    4629                                 "edit"
    4630                             ],
    4631                             "description": "Scope under which the request is made; determines fields present in response.",
    4632                             "type": "string"
    4633                         },
    4634                         "attributes": {
    4635                             "required": false,
    4636                             "default": [],
    4637                             "description": "Attributes for core/latest-posts block",
    4638                             "type": "object"
    4639                         },
    4640                         "post_id": {
    4641                             "required": false,
    4642                             "description": "ID of the post context.",
    4643                             "type": "integer"
    4644                         }
    4645                     }
    4646                 }
    4647             ]
    4648         },
    4649         "/wp/v2/block-renderer/(?P<name>core/rss)": {
    4650             "namespace": "wp/v2",
    4651             "methods": [
    4652                 "GET",
    4653                 "POST"
    4654             ],
    4655             "endpoints": [
    4656                 {
    4657                     "methods": [
    4658                         "GET",
    4659                         "POST"
    4660                     ],
    4661                     "args": {
    4662                         "name": {
    4663                             "required": false,
    4664                             "description": "Unique registered name for the block.",
    4665                             "type": "string"
    4666                         },
    4667                         "context": {
    4668                             "required": false,
    4669                             "default": "view",
    4670                             "enum": [
    4671                                 "edit"
    4672                             ],
    4673                             "description": "Scope under which the request is made; determines fields present in response.",
    4674                             "type": "string"
    4675                         },
    4676                         "attributes": {
    4677                             "required": false,
    4678                             "default": [],
    4679                             "description": "Attributes for core/rss block",
    4680                             "type": "object"
    4681                         },
    4682                         "post_id": {
    4683                             "required": false,
    4684                             "description": "ID of the post context.",
    4685                             "type": "integer"
    4686                         }
    4687                     }
    4688                 }
    4689             ]
    4690         },
    4691         "/wp/v2/block-renderer/(?P<name>core/search)": {
    4692             "namespace": "wp/v2",
    4693             "methods": [
    4694                 "GET",
    4695                 "POST"
    4696             ],
    4697             "endpoints": [
    4698                 {
    4699                     "methods": [
    4700                         "GET",
    4701                         "POST"
    4702                     ],
    4703                     "args": {
    4704                         "name": {
    4705                             "required": false,
    4706                             "description": "Unique registered name for the block.",
    4707                             "type": "string"
    4708                         },
    4709                         "context": {
    4710                             "required": false,
    4711                             "default": "view",
    4712                             "enum": [
    4713                                 "edit"
    4714                             ],
    4715                             "description": "Scope under which the request is made; determines fields present in response.",
    4716                             "type": "string"
    4717                         },
    4718                         "attributes": {
    4719                             "required": false,
    4720                             "default": [],
    4721                             "description": "Attributes for core/search block",
    4722                             "type": "object"
    4723                         },
    4724                         "post_id": {
    4725                             "required": false,
    4726                             "description": "ID of the post context.",
    4727                             "type": "integer"
    4728                         }
    4729                     }
    4730                 }
    4731             ]
    4732         },
    4733         "/wp/v2/block-renderer/(?P<name>core/shortcode)": {
    4734             "namespace": "wp/v2",
    4735             "methods": [
    4736                 "GET",
    4737                 "POST"
    4738             ],
    4739             "endpoints": [
    4740                 {
    4741                     "methods": [
    4742                         "GET",
    4743                         "POST"
    4744                     ],
    4745                     "args": {
    4746                         "name": {
    4747                             "required": false,
    4748                             "description": "Unique registered name for the block.",
    4749                             "type": "string"
    4750                         },
    4751                         "context": {
    4752                             "required": false,
    4753                             "default": "view",
    4754                             "enum": [
    4755                                 "edit"
    4756                             ],
    4757                             "description": "Scope under which the request is made; determines fields present in response.",
    4758                             "type": "string"
    4759                         },
    4760                         "attributes": {
    4761                             "required": false,
    4762                             "default": [],
    4763                             "description": "Attributes for core/shortcode block",
    4764                             "type": "object"
    4765                         },
    4766                         "post_id": {
    4767                             "required": false,
    4768                             "description": "ID of the post context.",
    4769                             "type": "integer"
    4770                         }
    4771                     }
    4772                 }
    4773             ]
    4774         },
    4775         "/wp/v2/block-renderer/(?P<name>core/social-link)": {
    4776             "namespace": "wp/v2",
    4777             "methods": [
    4778                 "GET",
    4779                 "POST"
    4780             ],
    4781             "endpoints": [
    4782                 {
    4783                     "methods": [
    4784                         "GET",
    4785                         "POST"
    4786                     ],
    4787                     "args": {
    4788                         "name": {
    4789                             "required": false,
    4790                             "description": "Unique registered name for the block.",
    4791                             "type": "string"
    4792                         },
    4793                         "context": {
    4794                             "required": false,
    4795                             "default": "view",
    4796                             "enum": [
    4797                                 "edit"
    4798                             ],
    4799                             "description": "Scope under which the request is made; determines fields present in response.",
    4800                             "type": "string"
    4801                         },
    4802                         "attributes": {
    4803                             "required": false,
    4804                             "default": [],
    4805                             "description": "Attributes for core/social-link block",
    4806                             "type": "object"
    4807                         },
    4808                         "post_id": {
    4809                             "required": false,
    4810                             "description": "ID of the post context.",
    4811                             "type": "integer"
    4812                         }
    4813                     }
    4814                 }
    4815             ]
    4816         },
    4817         "/wp/v2/block-renderer/(?P<name>core/tag-cloud)": {
    4818             "namespace": "wp/v2",
    4819             "methods": [
    4820                 "GET",
    4821                 "POST"
    4822             ],
    4823             "endpoints": [
    4824                 {
    4825                     "methods": [
    4826                         "GET",
    4827                         "POST"
    4828                     ],
    4829                     "args": {
    4830                         "name": {
    4831                             "required": false,
    4832                             "description": "Unique registered name for the block.",
    4833                             "type": "string"
    4834                         },
    4835                         "context": {
    4836                             "required": false,
    4837                             "default": "view",
    4838                             "enum": [
    4839                                 "edit"
    4840                             ],
    4841                             "description": "Scope under which the request is made; determines fields present in response.",
    4842                             "type": "string"
    4843                         },
    4844                         "attributes": {
    4845                             "required": false,
    4846                             "default": [],
    4847                             "description": "Attributes for core/tag-cloud block",
     4427                            "description": "Attributes for the block",
    48484428                            "type": "object"
    48494429                        },
Note: See TracChangeset for help on using the changeset viewer.