[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/rest-api/endpoints/ -> class-wp-rest-block-types-controller.php (source)

   1  <?php
   2  /**
   3   * REST API: WP_REST_Block_Types_Controller class
   4   *
   5   * @package WordPress
   6   * @subpackage REST_API
   7   * @since 5.5.0
   8   */
   9  
  10  /**
  11   * Core class used to access block types via the REST API.
  12   *
  13   * @since 5.5.0
  14   *
  15   * @see WP_REST_Controller
  16   */
  17  class WP_REST_Block_Types_Controller extends WP_REST_Controller {
  18  
  19      /**
  20       * Instance of WP_Block_Type_Registry.
  21       *
  22       * @since 5.5.0
  23       * @var WP_Block_Type_Registry
  24       */
  25      protected $block_registry;
  26  
  27      /**
  28       * Instance of WP_Block_Styles_Registry.
  29       *
  30       * @since 5.5.0
  31       * @var WP_Block_Styles_Registry
  32       */
  33      protected $style_registry;
  34  
  35      /**
  36       * Constructor.
  37       *
  38       * @since 5.5.0
  39       */
  40  	public function __construct() {
  41          $this->namespace      = 'wp/v2';
  42          $this->rest_base      = 'block-types';
  43          $this->block_registry = WP_Block_Type_Registry::get_instance();
  44          $this->style_registry = WP_Block_Styles_Registry::get_instance();
  45      }
  46  
  47      /**
  48       * Registers the routes for block types.
  49       *
  50       * @since 5.5.0
  51       *
  52       * @see register_rest_route()
  53       */
  54  	public function register_routes() {
  55  
  56          register_rest_route(
  57              $this->namespace,
  58              '/' . $this->rest_base,
  59              array(
  60                  array(
  61                      'methods'             => WP_REST_Server::READABLE,
  62                      'callback'            => array( $this, 'get_items' ),
  63                      'permission_callback' => array( $this, 'get_items_permissions_check' ),
  64                      'args'                => $this->get_collection_params(),
  65                  ),
  66                  'schema' => array( $this, 'get_public_item_schema' ),
  67              )
  68          );
  69  
  70          register_rest_route(
  71              $this->namespace,
  72              '/' . $this->rest_base . '/(?P<namespace>[a-zA-Z0-9_-]+)',
  73              array(
  74                  array(
  75                      'methods'             => WP_REST_Server::READABLE,
  76                      'callback'            => array( $this, 'get_items' ),
  77                      'permission_callback' => array( $this, 'get_items_permissions_check' ),
  78                      'args'                => $this->get_collection_params(),
  79                  ),
  80                  'schema' => array( $this, 'get_public_item_schema' ),
  81              )
  82          );
  83  
  84          register_rest_route(
  85              $this->namespace,
  86              '/' . $this->rest_base . '/(?P<namespace>[a-zA-Z0-9_-]+)/(?P<name>[a-zA-Z0-9_-]+)',
  87              array(
  88                  'args'   => array(
  89                      'name'      => array(
  90                          'description' => __( 'Block name.' ),
  91                          'type'        => 'string',
  92                      ),
  93                      'namespace' => array(
  94                          'description' => __( 'Block namespace.' ),
  95                          'type'        => 'string',
  96                      ),
  97                  ),
  98                  array(
  99                      'methods'             => WP_REST_Server::READABLE,
 100                      'callback'            => array( $this, 'get_item' ),
 101                      'permission_callback' => array( $this, 'get_item_permissions_check' ),
 102                      'args'                => array(
 103                          'context' => $this->get_context_param( array( 'default' => 'view' ) ),
 104                      ),
 105                  ),
 106                  'schema' => array( $this, 'get_public_item_schema' ),
 107              )
 108          );
 109      }
 110  
 111      /**
 112       * Checks whether a given request has permission to read post block types.
 113       *
 114       * @since 5.5.0
 115       *
 116       * @param WP_REST_Request $request Full details about the request.
 117       * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
 118       */
 119  	public function get_items_permissions_check( $request ) {
 120          return $this->check_read_permission();
 121      }
 122  
 123      /**
 124       * Retrieves all post block types, depending on user context.
 125       *
 126       * @since 5.5.0
 127       *
 128       * @param WP_REST_Request $request Full details about the request.
 129       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 130       */
 131  	public function get_items( $request ) {
 132          $data        = array();
 133          $block_types = $this->block_registry->get_all_registered();
 134  
 135          // Retrieve the list of registered collection query parameters.
 136          $registered = $this->get_collection_params();
 137          $namespace  = '';
 138          if ( isset( $registered['namespace'] ) && ! empty( $request['namespace'] ) ) {
 139              $namespace = $request['namespace'];
 140          }
 141  
 142          foreach ( $block_types as $slug => $obj ) {
 143              if ( $namespace ) {
 144                  list ( $block_namespace ) = explode( '/', $obj->name );
 145  
 146                  if ( $namespace !== $block_namespace ) {
 147                      continue;
 148                  }
 149              }
 150              $block_type = $this->prepare_item_for_response( $obj, $request );
 151              $data[]     = $this->prepare_response_for_collection( $block_type );
 152          }
 153  
 154          return rest_ensure_response( $data );
 155      }
 156  
 157      /**
 158       * Checks if a given request has access to read a block type.
 159       *
 160       * @since 5.5.0
 161       *
 162       * @param WP_REST_Request $request Full details about the request.
 163       * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
 164       */
 165  	public function get_item_permissions_check( $request ) {
 166          $check = $this->check_read_permission();
 167          if ( is_wp_error( $check ) ) {
 168              return $check;
 169          }
 170          $block_name = sprintf( '%s/%s', $request['namespace'], $request['name'] );
 171          $block_type = $this->get_block( $block_name );
 172          if ( is_wp_error( $block_type ) ) {
 173              return $block_type;
 174          }
 175  
 176          return true;
 177      }
 178  
 179      /**
 180       * Checks whether a given block type should be visible.
 181       *
 182       * @since 5.5.0
 183       *
 184       * @return true|WP_Error True if the block type is visible, WP_Error otherwise.
 185       */
 186  	protected function check_read_permission() {
 187          if ( current_user_can( 'edit_posts' ) ) {
 188              return true;
 189          }
 190          foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) {
 191              if ( current_user_can( $post_type->cap->edit_posts ) ) {
 192                  return true;
 193              }
 194          }
 195  
 196          return new WP_Error( 'rest_block_type_cannot_view', __( 'Sorry, you are not allowed to manage block types.' ), array( 'status' => rest_authorization_required_code() ) );
 197      }
 198  
 199      /**
 200       * Get the block, if the name is valid.
 201       *
 202       * @since 5.5.0
 203       *
 204       * @param string $name Block name.
 205       * @return WP_Block_Type|WP_Error Block type object if name is valid, WP_Error otherwise.
 206       */
 207  	protected function get_block( $name ) {
 208          $block_type = $this->block_registry->get_registered( $name );
 209          if ( empty( $block_type ) ) {
 210              return new WP_Error( 'rest_block_type_invalid', __( 'Invalid block type.' ), array( 'status' => 404 ) );
 211          }
 212  
 213          return $block_type;
 214      }
 215  
 216      /**
 217       * Retrieves a specific block type.
 218       *
 219       * @since 5.5.0
 220       *
 221       * @param WP_REST_Request $request Full details about the request.
 222       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 223       */
 224  	public function get_item( $request ) {
 225          $block_name = sprintf( '%s/%s', $request['namespace'], $request['name'] );
 226          $block_type = $this->get_block( $block_name );
 227          if ( is_wp_error( $block_type ) ) {
 228              return $block_type;
 229          }
 230          $data = $this->prepare_item_for_response( $block_type, $request );
 231  
 232          return rest_ensure_response( $data );
 233      }
 234  
 235      /**
 236       * Prepares a block type object for serialization.
 237       *
 238       * @since 5.5.0
 239       * @since 5.9.0 Renamed `$block_type` to `$item` to match parent class for PHP 8 named parameter support.
 240       *
 241       * @param WP_Block_Type   $item    Block type data.
 242       * @param WP_REST_Request $request Full details about the request.
 243       * @return WP_REST_Response Block type data.
 244       */
 245  	public function prepare_item_for_response( $item, $request ) {
 246          // Restores the more descriptive, specific name for use within this method.
 247          $block_type = $item;
 248          $fields     = $this->get_fields_for_response( $request );
 249          $data       = array();
 250  
 251          if ( rest_is_field_included( 'attributes', $fields ) ) {
 252              $data['attributes'] = $block_type->get_attributes();
 253          }
 254  
 255          if ( rest_is_field_included( 'is_dynamic', $fields ) ) {
 256              $data['is_dynamic'] = $block_type->is_dynamic();
 257          }
 258  
 259          $schema       = $this->get_item_schema();
 260          $extra_fields = array(
 261              'api_version',
 262              'name',
 263              'title',
 264              'description',
 265              'icon',
 266              'category',
 267              'keywords',
 268              'parent',
 269              'provides_context',
 270              'uses_context',
 271              'supports',
 272              'styles',
 273              'textdomain',
 274              'example',
 275              'editor_script',
 276              'script',
 277              'view_script',
 278              'editor_style',
 279              'style',
 280              'variations',
 281          );
 282          foreach ( $extra_fields as $extra_field ) {
 283              if ( rest_is_field_included( $extra_field, $fields ) ) {
 284                  if ( isset( $block_type->$extra_field ) ) {
 285                      $field = $block_type->$extra_field;
 286                  } elseif ( array_key_exists( 'default', $schema['properties'][ $extra_field ] ) ) {
 287                      $field = $schema['properties'][ $extra_field ]['default'];
 288                  } else {
 289                      $field = '';
 290                  }
 291                  $data[ $extra_field ] = rest_sanitize_value_from_schema( $field, $schema['properties'][ $extra_field ] );
 292              }
 293          }
 294  
 295          if ( rest_is_field_included( 'styles', $fields ) ) {
 296              $styles         = $this->style_registry->get_registered_styles_for_block( $block_type->name );
 297              $styles         = array_values( $styles );
 298              $data['styles'] = wp_parse_args( $styles, $data['styles'] );
 299              $data['styles'] = array_filter( $data['styles'] );
 300          }
 301  
 302          $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
 303          $data    = $this->add_additional_fields_to_object( $data, $request );
 304          $data    = $this->filter_response_by_context( $data, $context );
 305  
 306          $response = rest_ensure_response( $data );
 307  
 308          $response->add_links( $this->prepare_links( $block_type ) );
 309  
 310          /**
 311           * Filters a block type returned from the REST API.
 312           *
 313           * Allows modification of the block type data right before it is returned.
 314           *
 315           * @since 5.5.0
 316           *
 317           * @param WP_REST_Response $response   The response object.
 318           * @param WP_Block_Type    $block_type The original block type object.
 319           * @param WP_REST_Request  $request    Request used to generate the response.
 320           */
 321          return apply_filters( 'rest_prepare_block_type', $response, $block_type, $request );
 322      }
 323  
 324      /**
 325       * Prepares links for the request.
 326       *
 327       * @since 5.5.0
 328       *
 329       * @param WP_Block_Type $block_type Block type data.
 330       * @return array Links for the given block type.
 331       */
 332  	protected function prepare_links( $block_type ) {
 333          list( $namespace ) = explode( '/', $block_type->name );
 334  
 335          $links = array(
 336              'collection' => array(
 337                  'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
 338              ),
 339              'self'       => array(
 340                  'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $block_type->name ) ),
 341              ),
 342              'up'         => array(
 343                  'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $namespace ) ),
 344              ),
 345          );
 346  
 347          if ( $block_type->is_dynamic() ) {
 348              $links['https://api.w.org/render-block'] = array(
 349                  'href' => add_query_arg( 'context', 'edit', rest_url( sprintf( '%s/%s/%s', 'wp/v2', 'block-renderer', $block_type->name ) ) ),
 350              );
 351          }
 352  
 353          return $links;
 354      }
 355  
 356      /**
 357       * Retrieves the block type' schema, conforming to JSON Schema.
 358       *
 359       * @since 5.5.0
 360       *
 361       * @return array Item schema data.
 362       */
 363  	public function get_item_schema() {
 364          if ( $this->schema ) {
 365              return $this->add_additional_fields_schema( $this->schema );
 366          }
 367  
 368          // rest_validate_value_from_schema doesn't understand $refs, pull out reused definitions for readability.
 369          $inner_blocks_definition = array(
 370              'description' => __( 'The list of inner blocks used in the example.' ),
 371              'type'        => 'array',
 372              'items'       => array(
 373                  'type'       => 'object',
 374                  'properties' => array(
 375                      'name'        => array(
 376                          'description' => __( 'The name of the inner block.' ),
 377                          'type'        => 'string',
 378                      ),
 379                      'attributes'  => array(
 380                          'description' => __( 'The attributes of the inner block.' ),
 381                          'type'        => 'object',
 382                      ),
 383                      'innerBlocks' => array(
 384                          'description' => __( "A list of the inner block's own inner blocks. This is a recursive definition following the parent innerBlocks schema." ),
 385                          'type'        => 'array',
 386                      ),
 387                  ),
 388              ),
 389          );
 390  
 391          $example_definition = array(
 392              'description' => __( 'Block example.' ),
 393              'type'        => array( 'object', 'null' ),
 394              'default'     => null,
 395              'properties'  => array(
 396                  'attributes'  => array(
 397                      'description' => __( 'The attributes used in the example.' ),
 398                      'type'        => 'object',
 399                  ),
 400                  'innerBlocks' => $inner_blocks_definition,
 401              ),
 402              'context'     => array( 'embed', 'view', 'edit' ),
 403              'readonly'    => true,
 404          );
 405  
 406          $keywords_definition = array(
 407              'description' => __( 'Block keywords.' ),
 408              'type'        => 'array',
 409              'items'       => array(
 410                  'type' => 'string',
 411              ),
 412              'default'     => array(),
 413              'context'     => array( 'embed', 'view', 'edit' ),
 414              'readonly'    => true,
 415          );
 416  
 417          $icon_definition = array(
 418              'description' => __( 'Icon of block type.' ),
 419              'type'        => array( 'string', 'null' ),
 420              'default'     => null,
 421              'context'     => array( 'embed', 'view', 'edit' ),
 422              'readonly'    => true,
 423          );
 424  
 425          $category_definition = array(
 426              'description' => __( 'Block category.' ),
 427              'type'        => array( 'string', 'null' ),
 428              'default'     => null,
 429              'context'     => array( 'embed', 'view', 'edit' ),
 430              'readonly'    => true,
 431          );
 432  
 433          $schema = array(
 434              '$schema'    => 'http://json-schema.org/draft-04/schema#',
 435              'title'      => 'block-type',
 436              'type'       => 'object',
 437              'properties' => array(
 438                  'api_version'      => array(
 439                      'description' => __( 'Version of block API.' ),
 440                      'type'        => 'integer',
 441                      'default'     => 1,
 442                      'context'     => array( 'embed', 'view', 'edit' ),
 443                      'readonly'    => true,
 444                  ),
 445                  'title'            => array(
 446                      'description' => __( 'Title of block type.' ),
 447                      'type'        => 'string',
 448                      'default'     => '',
 449                      'context'     => array( 'embed', 'view', 'edit' ),
 450                      'readonly'    => true,
 451                  ),
 452                  'name'             => array(
 453                      'description' => __( 'Unique name identifying the block type.' ),
 454                      'type'        => 'string',
 455                      'default'     => '',
 456                      'context'     => array( 'embed', 'view', 'edit' ),
 457                      'readonly'    => true,
 458                  ),
 459                  'description'      => array(
 460                      'description' => __( 'Description of block type.' ),
 461                      'type'        => 'string',
 462                      'default'     => '',
 463                      'context'     => array( 'embed', 'view', 'edit' ),
 464                      'readonly'    => true,
 465                  ),
 466                  'icon'             => $icon_definition,
 467                  'attributes'       => array(
 468                      'description'          => __( 'Block attributes.' ),
 469                      'type'                 => array( 'object', 'null' ),
 470                      'properties'           => array(),
 471                      'default'              => null,
 472                      'additionalProperties' => array(
 473                          'type' => 'object',
 474                      ),
 475                      'context'              => array( 'embed', 'view', 'edit' ),
 476                      'readonly'             => true,
 477                  ),
 478                  'provides_context' => array(
 479                      'description'          => __( 'Context provided by blocks of this type.' ),
 480                      'type'                 => 'object',
 481                      'properties'           => array(),
 482                      'additionalProperties' => array(
 483                          'type' => 'string',
 484                      ),
 485                      'default'              => array(),
 486                      'context'              => array( 'embed', 'view', 'edit' ),
 487                      'readonly'             => true,
 488                  ),
 489                  'uses_context'     => array(
 490                      'description' => __( 'Context values inherited by blocks of this type.' ),
 491                      'type'        => 'array',
 492                      'default'     => array(),
 493                      'items'       => array(
 494                          'type' => 'string',
 495                      ),
 496                      'context'     => array( 'embed', 'view', 'edit' ),
 497                      'readonly'    => true,
 498                  ),
 499                  'supports'         => array(
 500                      'description' => __( 'Block supports.' ),
 501                      'type'        => 'object',
 502                      'default'     => array(),
 503                      'properties'  => array(),
 504                      'context'     => array( 'embed', 'view', 'edit' ),
 505                      'readonly'    => true,
 506                  ),
 507                  'category'         => $category_definition,
 508                  'is_dynamic'       => array(
 509                      'description' => __( 'Is the block dynamically rendered.' ),
 510                      'type'        => 'boolean',
 511                      'default'     => false,
 512                      'context'     => array( 'embed', 'view', 'edit' ),
 513                      'readonly'    => true,
 514                  ),
 515                  'editor_script'    => array(
 516                      'description' => __( 'Editor script handle.' ),
 517                      'type'        => array( 'string', 'null' ),
 518                      'default'     => null,
 519                      'context'     => array( 'embed', 'view', 'edit' ),
 520                      'readonly'    => true,
 521                  ),
 522                  'script'           => array(
 523                      'description' => __( 'Public facing and editor script handle.' ),
 524                      'type'        => array( 'string', 'null' ),
 525                      'default'     => null,
 526                      'context'     => array( 'embed', 'view', 'edit' ),
 527                      'readonly'    => true,
 528                  ),
 529                  'view_script'      => array(
 530                      'description' => __( 'Public facing script handle.' ),
 531                      'type'        => array( 'string', 'null' ),
 532                      'default'     => null,
 533                      'context'     => array( 'embed', 'view', 'edit' ),
 534                      'readonly'    => true,
 535                  ),
 536                  'editor_style'     => array(
 537                      'description' => __( 'Editor style handle.' ),
 538                      'type'        => array( 'string', 'null' ),
 539                      'default'     => null,
 540                      'context'     => array( 'embed', 'view', 'edit' ),
 541                      'readonly'    => true,
 542                  ),
 543                  'style'            => array(
 544                      'description' => __( 'Public facing and editor style handle.' ),
 545                      'type'        => array( 'string', 'null' ),
 546                      'default'     => null,
 547                      'context'     => array( 'embed', 'view', 'edit' ),
 548                      'readonly'    => true,
 549                  ),
 550                  'styles'           => array(
 551                      'description' => __( 'Block style variations.' ),
 552                      'type'        => 'array',
 553                      'items'       => array(
 554                          'type'       => 'object',
 555                          'properties' => array(
 556                              'name'         => array(
 557                                  'description' => __( 'Unique name identifying the style.' ),
 558                                  'type'        => 'string',
 559                                  'required'    => true,
 560                              ),
 561                              'label'        => array(
 562                                  'description' => __( 'The human-readable label for the style.' ),
 563                                  'type'        => 'string',
 564                              ),
 565                              'inline_style' => array(
 566                                  'description' => __( 'Inline CSS code that registers the CSS class required for the style.' ),
 567                                  'type'        => 'string',
 568                              ),
 569                              'style_handle' => array(
 570                                  'description' => __( 'Contains the handle that defines the block style.' ),
 571                                  'type'        => 'string',
 572                              ),
 573                          ),
 574                      ),
 575                      'default'     => array(),
 576                      'context'     => array( 'embed', 'view', 'edit' ),
 577                      'readonly'    => true,
 578                  ),
 579                  'variations'       => array(
 580                      'description' => __( 'Block variations.' ),
 581                      'type'        => 'array',
 582                      'items'       => array(
 583                          'type'       => 'object',
 584                          'properties' => array(
 585                              'name'        => array(
 586                                  'description' => __( 'The unique and machine-readable name.' ),
 587                                  'type'        => 'string',
 588                                  'required'    => true,
 589                              ),
 590                              'title'       => array(
 591                                  'description' => __( 'A human-readable variation title.' ),
 592                                  'type'        => 'string',
 593                                  'required'    => true,
 594                              ),
 595                              'description' => array(
 596                                  'description' => __( 'A detailed variation description.' ),
 597                                  'type'        => 'string',
 598                                  'required'    => false,
 599                              ),
 600                              'category'    => $category_definition,
 601                              'icon'        => $icon_definition,
 602                              'isDefault'   => array(
 603                                  'description' => __( 'Indicates whether the current variation is the default one.' ),
 604                                  'type'        => 'boolean',
 605                                  'required'    => false,
 606                                  'default'     => false,
 607                              ),
 608                              'attributes'  => array(
 609                                  'description' => __( 'The initial values for attributes.' ),
 610                                  'type'        => 'object',
 611                              ),
 612                              'innerBlocks' => $inner_blocks_definition,
 613                              'example'     => $example_definition,
 614                              'scope'       => array(
 615                                  'description' => __( 'The list of scopes where the variation is applicable. When not provided, it assumes all available scopes.' ),
 616                                  'type'        => array( 'array', 'null' ),
 617                                  'default'     => null,
 618                                  'items'       => array(
 619                                      'type' => 'string',
 620                                      'enum' => array( 'block', 'inserter', 'transform' ),
 621                                  ),
 622                                  'readonly'    => true,
 623                              ),
 624                              'keywords'    => $keywords_definition,
 625                          ),
 626                      ),
 627                      'readonly'    => true,
 628                      'context'     => array( 'embed', 'view', 'edit' ),
 629                      'default'     => null,
 630                  ),
 631                  'textdomain'       => array(
 632                      'description' => __( 'Public text domain.' ),
 633                      'type'        => array( 'string', 'null' ),
 634                      'default'     => null,
 635                      'context'     => array( 'embed', 'view', 'edit' ),
 636                      'readonly'    => true,
 637                  ),
 638                  'parent'           => array(
 639                      'description' => __( 'Parent blocks.' ),
 640                      'type'        => array( 'array', 'null' ),
 641                      'items'       => array(
 642                          'type' => 'string',
 643                      ),
 644                      'default'     => null,
 645                      'context'     => array( 'embed', 'view', 'edit' ),
 646                      'readonly'    => true,
 647                  ),
 648                  'keywords'         => $keywords_definition,
 649                  'example'          => $example_definition,
 650              ),
 651          );
 652  
 653          $this->schema = $schema;
 654  
 655          return $this->add_additional_fields_schema( $this->schema );
 656      }
 657  
 658      /**
 659       * Retrieves the query params for collections.
 660       *
 661       * @since 5.5.0
 662       *
 663       * @return array Collection parameters.
 664       */
 665  	public function get_collection_params() {
 666          return array(
 667              'context'   => $this->get_context_param( array( 'default' => 'view' ) ),
 668              'namespace' => array(
 669                  'description' => __( 'Block namespace.' ),
 670                  'type'        => 'string',
 671              ),
 672          );
 673      }
 674  
 675  }


Generated: Fri Sep 17 01:00:04 2021 Cross-referenced by PHPXref 0.7.1