[ 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              'ancestor',
 270              'provides_context',
 271              'uses_context',
 272              'supports',
 273              'styles',
 274              'textdomain',
 275              'example',
 276              'editor_script',
 277              'script',
 278              'view_script',
 279              'editor_style',
 280              'style',
 281              'variations',
 282          );
 283          foreach ( $extra_fields as $extra_field ) {
 284              if ( rest_is_field_included( $extra_field, $fields ) ) {
 285                  if ( isset( $block_type->$extra_field ) ) {
 286                      $field = $block_type->$extra_field;
 287                  } elseif ( array_key_exists( 'default', $schema['properties'][ $extra_field ] ) ) {
 288                      $field = $schema['properties'][ $extra_field ]['default'];
 289                  } else {
 290                      $field = '';
 291                  }
 292                  $data[ $extra_field ] = rest_sanitize_value_from_schema( $field, $schema['properties'][ $extra_field ] );
 293              }
 294          }
 295  
 296          if ( rest_is_field_included( 'styles', $fields ) ) {
 297              $styles         = $this->style_registry->get_registered_styles_for_block( $block_type->name );
 298              $styles         = array_values( $styles );
 299              $data['styles'] = wp_parse_args( $styles, $data['styles'] );
 300              $data['styles'] = array_filter( $data['styles'] );
 301          }
 302  
 303          $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
 304          $data    = $this->add_additional_fields_to_object( $data, $request );
 305          $data    = $this->filter_response_by_context( $data, $context );
 306  
 307          $response = rest_ensure_response( $data );
 308  
 309          $response->add_links( $this->prepare_links( $block_type ) );
 310  
 311          /**
 312           * Filters a block type returned from the REST API.
 313           *
 314           * Allows modification of the block type data right before it is returned.
 315           *
 316           * @since 5.5.0
 317           *
 318           * @param WP_REST_Response $response   The response object.
 319           * @param WP_Block_Type    $block_type The original block type object.
 320           * @param WP_REST_Request  $request    Request used to generate the response.
 321           */
 322          return apply_filters( 'rest_prepare_block_type', $response, $block_type, $request );
 323      }
 324  
 325      /**
 326       * Prepares links for the request.
 327       *
 328       * @since 5.5.0
 329       *
 330       * @param WP_Block_Type $block_type Block type data.
 331       * @return array Links for the given block type.
 332       */
 333  	protected function prepare_links( $block_type ) {
 334          list( $namespace ) = explode( '/', $block_type->name );
 335  
 336          $links = array(
 337              'collection' => array(
 338                  'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
 339              ),
 340              'self'       => array(
 341                  'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $block_type->name ) ),
 342              ),
 343              'up'         => array(
 344                  'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $namespace ) ),
 345              ),
 346          );
 347  
 348          if ( $block_type->is_dynamic() ) {
 349              $links['https://api.w.org/render-block'] = array(
 350                  'href' => add_query_arg( 'context', 'edit', rest_url( sprintf( '%s/%s/%s', 'wp/v2', 'block-renderer', $block_type->name ) ) ),
 351              );
 352          }
 353  
 354          return $links;
 355      }
 356  
 357      /**
 358       * Retrieves the block type' schema, conforming to JSON Schema.
 359       *
 360       * @since 5.5.0
 361       *
 362       * @return array Item schema data.
 363       */
 364  	public function get_item_schema() {
 365          if ( $this->schema ) {
 366              return $this->add_additional_fields_schema( $this->schema );
 367          }
 368  
 369          // rest_validate_value_from_schema doesn't understand $refs, pull out reused definitions for readability.
 370          $inner_blocks_definition = array(
 371              'description' => __( 'The list of inner blocks used in the example.' ),
 372              'type'        => 'array',
 373              'items'       => array(
 374                  'type'       => 'object',
 375                  'properties' => array(
 376                      'name'        => array(
 377                          'description' => __( 'The name of the inner block.' ),
 378                          'type'        => 'string',
 379                      ),
 380                      'attributes'  => array(
 381                          'description' => __( 'The attributes of the inner block.' ),
 382                          'type'        => 'object',
 383                      ),
 384                      'innerBlocks' => array(
 385                          'description' => __( "A list of the inner block's own inner blocks. This is a recursive definition following the parent innerBlocks schema." ),
 386                          'type'        => 'array',
 387                      ),
 388                  ),
 389              ),
 390          );
 391  
 392          $example_definition = array(
 393              'description' => __( 'Block example.' ),
 394              'type'        => array( 'object', 'null' ),
 395              'default'     => null,
 396              'properties'  => array(
 397                  'attributes'  => array(
 398                      'description' => __( 'The attributes used in the example.' ),
 399                      'type'        => 'object',
 400                  ),
 401                  'innerBlocks' => $inner_blocks_definition,
 402              ),
 403              'context'     => array( 'embed', 'view', 'edit' ),
 404              'readonly'    => true,
 405          );
 406  
 407          $keywords_definition = array(
 408              'description' => __( 'Block keywords.' ),
 409              'type'        => 'array',
 410              'items'       => array(
 411                  'type' => 'string',
 412              ),
 413              'default'     => array(),
 414              'context'     => array( 'embed', 'view', 'edit' ),
 415              'readonly'    => true,
 416          );
 417  
 418          $icon_definition = array(
 419              'description' => __( 'Icon of block type.' ),
 420              'type'        => array( 'string', 'null' ),
 421              'default'     => null,
 422              'context'     => array( 'embed', 'view', 'edit' ),
 423              'readonly'    => true,
 424          );
 425  
 426          $category_definition = array(
 427              'description' => __( 'Block category.' ),
 428              'type'        => array( 'string', 'null' ),
 429              'default'     => null,
 430              'context'     => array( 'embed', 'view', 'edit' ),
 431              'readonly'    => true,
 432          );
 433  
 434          $schema = array(
 435              '$schema'    => 'http://json-schema.org/draft-04/schema#',
 436              'title'      => 'block-type',
 437              'type'       => 'object',
 438              'properties' => array(
 439                  'api_version'      => array(
 440                      'description' => __( 'Version of block API.' ),
 441                      'type'        => 'integer',
 442                      'default'     => 1,
 443                      'context'     => array( 'embed', 'view', 'edit' ),
 444                      'readonly'    => true,
 445                  ),
 446                  'title'            => array(
 447                      'description' => __( 'Title of block type.' ),
 448                      'type'        => 'string',
 449                      'default'     => '',
 450                      'context'     => array( 'embed', 'view', 'edit' ),
 451                      'readonly'    => true,
 452                  ),
 453                  'name'             => array(
 454                      'description' => __( 'Unique name identifying the block type.' ),
 455                      'type'        => 'string',
 456                      'default'     => '',
 457                      'context'     => array( 'embed', 'view', 'edit' ),
 458                      'readonly'    => true,
 459                  ),
 460                  'description'      => array(
 461                      'description' => __( 'Description of block type.' ),
 462                      'type'        => 'string',
 463                      'default'     => '',
 464                      'context'     => array( 'embed', 'view', 'edit' ),
 465                      'readonly'    => true,
 466                  ),
 467                  'icon'             => $icon_definition,
 468                  'attributes'       => array(
 469                      'description'          => __( 'Block attributes.' ),
 470                      'type'                 => array( 'object', 'null' ),
 471                      'properties'           => array(),
 472                      'default'              => null,
 473                      'additionalProperties' => array(
 474                          'type' => 'object',
 475                      ),
 476                      'context'              => array( 'embed', 'view', 'edit' ),
 477                      'readonly'             => true,
 478                  ),
 479                  'provides_context' => array(
 480                      'description'          => __( 'Context provided by blocks of this type.' ),
 481                      'type'                 => 'object',
 482                      'properties'           => array(),
 483                      'additionalProperties' => array(
 484                          'type' => 'string',
 485                      ),
 486                      'default'              => array(),
 487                      'context'              => array( 'embed', 'view', 'edit' ),
 488                      'readonly'             => true,
 489                  ),
 490                  'uses_context'     => array(
 491                      'description' => __( 'Context values inherited by blocks of this type.' ),
 492                      'type'        => 'array',
 493                      'default'     => array(),
 494                      'items'       => array(
 495                          'type' => 'string',
 496                      ),
 497                      'context'     => array( 'embed', 'view', 'edit' ),
 498                      'readonly'    => true,
 499                  ),
 500                  'supports'         => array(
 501                      'description' => __( 'Block supports.' ),
 502                      'type'        => 'object',
 503                      'default'     => array(),
 504                      'properties'  => array(),
 505                      'context'     => array( 'embed', 'view', 'edit' ),
 506                      'readonly'    => true,
 507                  ),
 508                  'category'         => $category_definition,
 509                  'is_dynamic'       => array(
 510                      'description' => __( 'Is the block dynamically rendered.' ),
 511                      'type'        => 'boolean',
 512                      'default'     => false,
 513                      'context'     => array( 'embed', 'view', 'edit' ),
 514                      'readonly'    => true,
 515                  ),
 516                  'editor_script'    => array(
 517                      'description' => __( 'Editor script handle.' ),
 518                      'type'        => array( 'string', 'null' ),
 519                      'default'     => null,
 520                      'context'     => array( 'embed', 'view', 'edit' ),
 521                      'readonly'    => true,
 522                  ),
 523                  'script'           => array(
 524                      'description' => __( 'Public facing and editor script handle.' ),
 525                      'type'        => array( 'string', 'null' ),
 526                      'default'     => null,
 527                      'context'     => array( 'embed', 'view', 'edit' ),
 528                      'readonly'    => true,
 529                  ),
 530                  'view_script'      => array(
 531                      'description' => __( 'Public facing script handle.' ),
 532                      'type'        => array( 'string', 'null' ),
 533                      'default'     => null,
 534                      'context'     => array( 'embed', 'view', 'edit' ),
 535                      'readonly'    => true,
 536                  ),
 537                  'editor_style'     => array(
 538                      'description' => __( 'Editor style handle.' ),
 539                      'type'        => array( 'string', 'null' ),
 540                      'default'     => null,
 541                      'context'     => array( 'embed', 'view', 'edit' ),
 542                      'readonly'    => true,
 543                  ),
 544                  'style'            => array(
 545                      'description' => __( 'Public facing and editor style handle.' ),
 546                      'type'        => array( 'string', 'null' ),
 547                      'default'     => null,
 548                      'context'     => array( 'embed', 'view', 'edit' ),
 549                      'readonly'    => true,
 550                  ),
 551                  'styles'           => array(
 552                      'description' => __( 'Block style variations.' ),
 553                      'type'        => 'array',
 554                      'items'       => array(
 555                          'type'       => 'object',
 556                          'properties' => array(
 557                              'name'         => array(
 558                                  'description' => __( 'Unique name identifying the style.' ),
 559                                  'type'        => 'string',
 560                                  'required'    => true,
 561                              ),
 562                              'label'        => array(
 563                                  'description' => __( 'The human-readable label for the style.' ),
 564                                  'type'        => 'string',
 565                              ),
 566                              'inline_style' => array(
 567                                  'description' => __( 'Inline CSS code that registers the CSS class required for the style.' ),
 568                                  'type'        => 'string',
 569                              ),
 570                              'style_handle' => array(
 571                                  'description' => __( 'Contains the handle that defines the block style.' ),
 572                                  'type'        => 'string',
 573                              ),
 574                          ),
 575                      ),
 576                      'default'     => array(),
 577                      'context'     => array( 'embed', 'view', 'edit' ),
 578                      'readonly'    => true,
 579                  ),
 580                  'variations'       => array(
 581                      'description' => __( 'Block variations.' ),
 582                      'type'        => 'array',
 583                      'items'       => array(
 584                          'type'       => 'object',
 585                          'properties' => array(
 586                              'name'        => array(
 587                                  'description' => __( 'The unique and machine-readable name.' ),
 588                                  'type'        => 'string',
 589                                  'required'    => true,
 590                              ),
 591                              'title'       => array(
 592                                  'description' => __( 'A human-readable variation title.' ),
 593                                  'type'        => 'string',
 594                                  'required'    => true,
 595                              ),
 596                              'description' => array(
 597                                  'description' => __( 'A detailed variation description.' ),
 598                                  'type'        => 'string',
 599                                  'required'    => false,
 600                              ),
 601                              'category'    => $category_definition,
 602                              'icon'        => $icon_definition,
 603                              'isDefault'   => array(
 604                                  'description' => __( 'Indicates whether the current variation is the default one.' ),
 605                                  'type'        => 'boolean',
 606                                  'required'    => false,
 607                                  'default'     => false,
 608                              ),
 609                              'attributes'  => array(
 610                                  'description' => __( 'The initial values for attributes.' ),
 611                                  'type'        => 'object',
 612                              ),
 613                              'innerBlocks' => $inner_blocks_definition,
 614                              'example'     => $example_definition,
 615                              'scope'       => array(
 616                                  'description' => __( 'The list of scopes where the variation is applicable. When not provided, it assumes all available scopes.' ),
 617                                  'type'        => array( 'array', 'null' ),
 618                                  'default'     => null,
 619                                  'items'       => array(
 620                                      'type' => 'string',
 621                                      'enum' => array( 'block', 'inserter', 'transform' ),
 622                                  ),
 623                                  'readonly'    => true,
 624                              ),
 625                              'keywords'    => $keywords_definition,
 626                          ),
 627                      ),
 628                      'readonly'    => true,
 629                      'context'     => array( 'embed', 'view', 'edit' ),
 630                      'default'     => null,
 631                  ),
 632                  'textdomain'       => array(
 633                      'description' => __( 'Public text domain.' ),
 634                      'type'        => array( 'string', 'null' ),
 635                      'default'     => null,
 636                      'context'     => array( 'embed', 'view', 'edit' ),
 637                      'readonly'    => true,
 638                  ),
 639                  'parent'           => array(
 640                      'description' => __( 'Parent blocks.' ),
 641                      'type'        => array( 'array', 'null' ),
 642                      'items'       => array(
 643                          'type' => 'string',
 644                      ),
 645                      'default'     => null,
 646                      'context'     => array( 'embed', 'view', 'edit' ),
 647                      'readonly'    => true,
 648                  ),
 649                  'ancestor'         => array(
 650                      'description' => __( 'Ancestor blocks.' ),
 651                      'type'        => array( 'array', 'null' ),
 652                      'items'       => array(
 653                          'type' => 'string',
 654                      ),
 655                      'default'     => null,
 656                      'context'     => array( 'embed', 'view', 'edit' ),
 657                      'readonly'    => true,
 658                  ),
 659                  'keywords'         => $keywords_definition,
 660                  'example'          => $example_definition,
 661              ),
 662          );
 663  
 664          $this->schema = $schema;
 665  
 666          return $this->add_additional_fields_schema( $this->schema );
 667      }
 668  
 669      /**
 670       * Retrieves the query params for collections.
 671       *
 672       * @since 5.5.0
 673       *
 674       * @return array Collection parameters.
 675       */
 676  	public function get_collection_params() {
 677          return array(
 678              'context'   => $this->get_context_param( array( 'default' => 'view' ) ),
 679              'namespace' => array(
 680                  'description' => __( 'Block namespace.' ),
 681                  'type'        => 'string',
 682              ),
 683          );
 684      }
 685  
 686  }


Generated: Thu Nov 21 01:00:03 2024 Cross-referenced by PHPXref 0.7.1