[ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Dec 5 01:00:03 2024 | Cross-referenced by PHPXref 0.7.1 |