Changeset 49608
- Timestamp:
- 11/16/2020 12:45:55 AM (4 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/blocks.php
r49312 r49608 663 663 664 664 /** 665 * Allows render_block() to be short-circuited, by returning a non-null value. 665 * Allows render_block() or WP_Block::render() to be short-circuited, by 666 * returning a non-null value. 666 667 * 667 668 * @since 5.1.0 … … 675 676 } 676 677 677 $source_block = $parsed_block;678 679 /**680 * Filters the block being rendered in render_block(), before it's processed.681 *682 * @since 5.1.0683 *684 * @param array $parsed_block The block being rendered.685 * @param array $source_block An un-modified copy of $parsed_block, as it appeared in the source content.686 */687 $parsed_block = apply_filters( 'render_block_data', $parsed_block, $source_block );688 689 678 $context = array(); 690 679 … … 707 696 } 708 697 } 709 710 /**711 * Filters the default context provided to a rendered block.712 *713 * @since 5.5.0714 *715 * @param array $context Default context.716 * @param array $parsed_block Block being rendered, filtered by `render_block_data`.717 */718 $context = apply_filters( 'render_block_context', $context, $parsed_block );719 698 720 699 $block = new WP_Block( $parsed_block, $context ); -
trunk/src/wp-includes/class-wp-block.php
r49540 r49608 12 12 * @since 5.5.0 13 13 * @property array $attributes 14 * @property array $context 15 * @property WP_Block[] $inner_blocks; 16 * @property string $inner_html; 17 * @property array $inner_content; 14 18 */ 15 19 class WP_Block { … … 24 28 25 29 /** 26 * Name of block.27 *28 * @example "core/paragraph"29 *30 * @since 5.5.031 * @var string32 */33 public $name;34 35 /**36 * Block type associated with the instance.37 *38 * @since 5.5.039 * @var WP_Block_Type40 */41 public $block_type;42 43 /**44 * Block context values.45 *46 * @since 5.5.047 * @var array48 */49 public $context = array();50 51 /**52 30 * All available context of the current hierarchy. 53 31 * … … 59 37 60 38 /** 61 * List of inner blocks (of this same class) 62 * 63 * @since 5.5.0 64 * @var WP_Block[] 65 */ 66 public $inner_blocks = array(); 67 68 /** 69 * Resultant HTML from inside block comment delimiters after removing inner 70 * blocks. 71 * 72 * @example "...Just <!-- wp:test /--> testing..." -> "Just testing..." 39 * Name of block. 40 * 41 * @example "core/paragraph" 73 42 * 74 43 * @since 5.5.0 75 44 * @var string 76 45 */ 77 public $inner_html = ''; 78 79 /** 80 * List of string fragments and null markers where inner blocks were found 81 * 82 * @example array( 83 * 'inner_html' => 'BeforeInnerAfter', 84 * 'inner_blocks' => array( block, block ), 85 * 'inner_content' => array( 'Before', null, 'Inner', null, 'After' ), 86 * ) 87 * 88 * @since 5.5.0 46 public $name; 47 48 /** 49 * Block type associated with the instance. 50 * 51 * @since 5.5.0 52 * @var WP_Block_Type 53 */ 54 public $block_type; 55 56 /** 57 * Map of block property names and their cached value. 58 * 59 * Some block properties are computed lazily using a getter function. The 60 * result is then cached here for subsequent use. 61 * 62 * @since 5.6.0 89 63 * @var array 90 64 */ 91 p ublic $inner_content= array();92 93 /** 94 * C onstructor.95 * 96 * Populates object properties from the provided block instance argument.65 protected $cached_properties = array(); 66 67 /** 68 * Creates a block instance from a backing `$parsed_block` array and list of 69 * `$available_context`. From these, the block's dynamic properties can be 70 * derived. 97 71 * 98 72 * The given array of context values will not necessarily be available on … … 104 78 * @since 5.5.0 105 79 * 106 * @param array $ blockArray of parsed block properties.80 * @param array $parsed_block Array of parsed block properties. 107 81 * @param array $available_context Optional array of ancestry context values. 108 82 * @param WP_Block_Type_Registry $registry Optional block type registry. 109 83 */ 110 public function __construct( $block, $available_context = array(), $registry = null ) { 111 $this->parsed_block = $block; 112 $this->name = $block['blockName']; 113 84 public function __construct( $parsed_block, $available_context = array(), $registry = null ) { 114 85 if ( is_null( $registry ) ) { 115 $registry = WP_Block_Type_Registry::get_instance(); 116 } 117 118 $this->block_type = $registry->get_registered( $this->name ); 119 86 $this->registry = WP_Block_Type_Registry::get_instance(); 87 } else { 88 $this->registry = $registry; 89 } 90 91 $this->reset( $parsed_block, $available_context ); 92 } 93 94 /** 95 * Changes the backing `$parsed_block` and `$available_context` used to 96 * derive the block's dynamic properties. 97 * 98 * @since 5.6.0 99 100 * @param array $parsed_block Array of parsed block properties. 101 * @param array $available_context Optional array of ancestry context values. 102 * @param array $cached_properties Optional cache of dynamic properties to use. 103 */ 104 protected function reset( 105 $parsed_block, 106 $available_context = array(), 107 $cached_properties = array() 108 ) { 109 $this->parsed_block = $parsed_block; 120 110 $this->available_context = $available_context; 111 $this->name = $parsed_block['blockName']; 112 $this->block_type = $this->registry->get_registered( $this->name ); 113 $this->cached_properties = $cached_properties; 114 } 115 116 /** 117 * Getter used for the block's dynamic properties: 118 * 119 * - `$block->attributes` 120 * - `$block->context` 121 * - `$block->inner_blocks` 122 * - `$block->inner_html` 123 * - `$block->inner_content` 124 * 125 * Each dynamic property is obtained by calling the associated getter 126 * function (e.g. `this->get_attributes()`). The result is then cached in 127 * `$this->cached_attributes` for subsequent calls. 128 * 129 * @since 5.5.0 130 * 131 * @param string $name Property name. 132 * @return array|null Prepared attributes, or null. 133 */ 134 public function __get( $name ) { 135 if ( method_exists( $this, "get_$name" ) ) { 136 if ( ! isset( $this->cached_properties[ $name ] ) ) { 137 $this->cached_properties[ $name ] = $this->{"get_$name"}(); 138 } 139 140 return $this->cached_properties[ $name ]; 141 } 142 143 return null; 144 } 145 146 /** 147 * Block attributes. 148 * 149 * Use `$block->attributes` to access this. 150 * 151 * @since 5.6.0 152 * @return array 153 */ 154 protected function get_attributes() { 155 $attributes = isset( $this->parsed_block['attrs'] ) ? 156 $this->parsed_block['attrs'] : 157 array(); 158 159 if ( ! is_null( $this->block_type ) ) { 160 return $this->block_type->prepare_attributes_for_render( $attributes ); 161 } 162 163 return $attributes; 164 } 165 166 /** 167 * Block context values. 168 * 169 * Use `$block->context` to access this. 170 * 171 * @since 5.6.0 172 * @return array 173 */ 174 protected function get_context() { 175 $context = array(); 121 176 122 177 if ( ! empty( $this->block_type->uses_context ) ) { 123 178 foreach ( $this->block_type->uses_context as $context_name ) { 124 179 if ( array_key_exists( $context_name, $this->available_context ) ) { 125 $ this->context[ $context_name ] = $this->available_context[ $context_name ];180 $context[ $context_name ] = $this->available_context[ $context_name ]; 126 181 } 127 182 } 128 183 } 129 184 130 if ( ! empty( $block['innerBlocks'] ) ) { 185 return $context; 186 } 187 188 /** 189 * List of inner blocks (of this same class). 190 * 191 * Use `$block->inner_blocks` to access this. 192 * 193 * @since 5.6.0 194 * @return WP_Block[] 195 */ 196 protected function get_inner_blocks() { 197 if ( ! empty( $this->parsed_block['innerBlocks'] ) ) { 131 198 $child_context = $this->available_context; 132 199 … … 139 206 } 140 207 141 $this->inner_blocks = new WP_Block_List( $block['innerBlocks'], $child_context, $registry ); 142 } 143 144 if ( ! empty( $block['innerHTML'] ) ) { 145 $this->inner_html = $block['innerHTML']; 146 } 147 148 if ( ! empty( $block['innerContent'] ) ) { 149 $this->inner_content = $block['innerContent']; 150 } 151 } 152 153 /** 154 * Returns a value from an inaccessible property. 155 * 156 * This is used to lazily initialize the `attributes` property of a block, 157 * such that it is only prepared with default attributes at the time that 158 * the property is accessed. For all other inaccessible properties, a `null` 159 * value is returned. 160 * 161 * @since 5.5.0 162 * 163 * @param string $name Property name. 164 * @return array|null Prepared attributes, or null. 165 */ 166 public function __get( $name ) { 167 if ( 'attributes' === $name ) { 168 $this->attributes = isset( $this->parsed_block['attrs'] ) ? 169 $this->parsed_block['attrs'] : 170 array(); 171 172 if ( ! is_null( $this->block_type ) ) { 173 $this->attributes = $this->block_type->prepare_attributes_for_render( $this->attributes ); 174 } 175 176 return $this->attributes; 177 } 178 179 return null; 208 return new WP_Block_List( 209 $this->parsed_block['innerBlocks'], 210 $child_context, 211 $this->registry 212 ); 213 } 214 215 return array(); 216 } 217 218 /** 219 * Resultant HTML from inside block comment delimiters after removing inner 220 * blocks. 221 * 222 * Use `$block->inner_html` to access this. 223 * 224 * @example "...Just <!-- wp:test /--> testing..." -> "Just testing..." 225 * 226 * @since 5.6.0 227 * @return string 228 */ 229 protected function get_inner_html() { 230 if ( ! empty( $this->parsed_block['innerHTML'] ) ) { 231 return $this->parsed_block['innerHTML']; 232 } 233 234 return ''; 235 } 236 237 /** 238 * List of string fragments and null markers where inner blocks were found 239 * 240 * Use `$block->inner_content` to access this. 241 * 242 * @example array( 243 * 'inner_html' => 'BeforeInnerAfter', 244 * 'inner_blocks' => array( block, block ), 245 * 'inner_content' => array( 'Before', null, 'Inner', null, 'After' ), 246 * ) 247 * 248 * @since 5.6.0 249 * @return array 250 */ 251 protected function get_inner_content() { 252 if ( ! empty( $this->parsed_block['innerContent'] ) ) { 253 return $this->parsed_block['innerContent']; 254 } 255 256 return array(); 180 257 } 181 258 … … 194 271 public function render( $options = array() ) { 195 272 global $post; 273 274 /** This filter is documented in src/wp-includes/blocks.php. */ 275 $pre_render = apply_filters( 'pre_render_block', null, $this->parsed_block ); 276 if ( ! is_null( $pre_render ) ) { 277 return $pre_render; 278 } 279 196 280 $options = wp_parse_args( 197 281 $options, … … 201 285 ); 202 286 203 $is_dynamic = $options['dynamic'] && $this->name && null !== $this->block_type && $this->block_type->is_dynamic(); 287 $initial_parsed_block = $this->parsed_block; 288 $initial_available_context = $this->available_context; 289 $initial_cached_properties = $this->cached_properties; 290 291 /** 292 * Filters a block which is to be rendered by render_block() or 293 * WP_Block::render(). 294 * 295 * @since 5.1.0 296 * 297 * @param array $parsed_block The block being rendered. 298 * @param array $source_block An un-modified copy of $parsed_block, as it appeared in the source content. 299 */ 300 $parsed_block = apply_filters( 301 'render_block_data', 302 $this->parsed_block, 303 $initial_parsed_block 304 ); 305 306 /** 307 * Filters the default context of a block which is to be rendered by 308 * render_block() or WP_Block::render(). 309 * 310 * @since 5.5.0 311 * 312 * @param array $available_context Default context. 313 * @param array $parsed_block Block being rendered, filtered by `render_block_data`. 314 */ 315 $available_context = apply_filters( 316 'render_block_context', 317 $this->available_context, 318 $this->parsed_block 319 ); 320 321 $this->reset( $parsed_block, $available_context ); 322 323 $is_dynamic = $options['dynamic'] 324 && $this->name 325 && null !== $this->block_type 326 && $this->block_type->is_dynamic(); 327 204 328 $block_content = ''; 205 329 … … 219 343 WP_Block_Supports::$block_to_render = $this->parsed_block; 220 344 221 $block_content = (string) call_user_func( $this->block_type->render_callback, $this->attributes, $block_content, $this ); 345 $block_content = (string) call_user_func( 346 $this->block_type->render_callback, 347 $this->attributes, 348 $block_content, 349 $this 350 ); 222 351 223 352 WP_Block_Supports::$block_to_render = $parent; … … 242 371 * @param array $block The full block, including name and attributes. 243 372 */ 244 return apply_filters( 'render_block', $block_content, $this->parsed_block ); 373 $block_content = apply_filters( 'render_block', $block_content, $this->parsed_block ); 374 375 $this->reset( 376 $initial_parsed_block, 377 $initial_available_context, 378 $initial_cached_properties 379 ); 380 381 return $block_content; 245 382 } 246 383 -
trunk/tests/phpunit/tests/blocks/block.php
r48937 r49608 46 46 } 47 47 48 function filter_pre_render_block( $pre_render, $parsed_block ) { 49 if ( 'core/skip' === $parsed_block['blockName'] ) { 50 return 'Hello world!'; 51 } 52 return null; 53 } 54 55 function filter_render_block_data( $parsed_block, $source_block ) { 56 $parsed_block['attrs']['tag'] = $parsed_block['attrs']['tag'] . '-filtered'; 57 return $parsed_block; 58 } 59 60 function filter_render_block_context( $available_context, $parsed_block ) { 61 $available_context['core/recordId'] += 1; 62 return $available_context; 63 } 64 48 65 /** 49 66 * @ticket 49927 … … 395 412 } 396 413 414 /** 415 * @ticket 51612 416 */ 417 function test_applies_pre_render_block_filter() { 418 $this->registry->register( 'core/skip', array() ); 419 420 add_filter( 'pre_render_block', array( $this, 'filter_pre_render_block' ), 10, 2 ); 421 422 $parsed_blocks = parse_blocks( '<!-- wp:skip /-->' ); 423 $parsed_block = $parsed_blocks[0]; 424 $context = array(); 425 $block = new WP_Block( $parsed_block, $context, $this->registry ); 426 427 $rendered_content = $block->render(); 428 429 remove_filter( 'pre_render_block', array( $this, 'filter_pre_render_block' ) ); 430 431 $this->assertSame( 'Hello world!', $rendered_content ); 432 } 433 434 /** 435 * @ticket 51612 436 */ 437 function test_applies_pre_render_block_filter_to_inner_blocks() { 438 $this->registry->register( 'core/outer', array() ); 439 $this->registry->register( 'core/skip', array() ); 440 441 add_filter( 'pre_render_block', array( $this, 'filter_pre_render_block' ), 10, 2 ); 442 443 $parsed_blocks = parse_blocks( '<!-- wp:outer --><!-- wp:skip /--> How are you?<!-- /wp:outer -->' ); 444 $parsed_block = $parsed_blocks[0]; 445 $context = array(); 446 $block = new WP_Block( $parsed_block, $context, $this->registry ); 447 448 $rendered_content = $block->render(); 449 450 remove_filter( 'pre_render_block', array( $this, 'filter_pre_render_block' ) ); 451 452 $this->assertSame( 'Hello world! How are you?', $rendered_content ); 453 } 454 455 /** 456 * @ticket 51612 457 */ 458 function test_applies_render_block_data_filter() { 459 $this->registry->register( 460 'core/wrapper', 461 array( 462 'attributes' => array( 463 'tag' => array( 464 'type' => 'string', 465 ), 466 ), 467 'render_callback' => function( $block_attributes, $content ) { 468 return sprintf( 469 '<%1$s>%2$s</%1$s>', 470 $block_attributes['tag'], 471 $content 472 ); 473 }, 474 ) 475 ); 476 477 add_filter( 'render_block_data', array( $this, 'filter_render_block_data' ), 10, 2 ); 478 479 $parsed_blocks = parse_blocks( '<!-- wp:wrapper {"tag":"outer"} --><!-- wp:wrapper {"tag":"inner"} -->Hello!<!-- /wp:wrapper --><!-- /wp:wrapper -->' ); 480 $parsed_block = $parsed_blocks[0]; 481 $context = array(); 482 $block = new WP_Block( $parsed_block, $context, $this->registry ); 483 484 $rendered_content = $block->render(); 485 486 remove_filter( 'render_block_data', array( $this, 'filter_render_block_data' ) ); 487 488 $this->assertSame( '<outer-filtered><inner-filtered>Hello!</inner-filtered></outer-filtered>', $rendered_content ); 489 } 490 491 /** 492 * @ticket 51612 493 */ 494 function test_applies_render_block_context_filter() { 495 $this->registry->register( 496 'core/provider', 497 array( 498 'attributes' => array( 499 'recordId' => array( 500 'type' => 'number', 501 ), 502 ), 503 'uses_context' => array( 'core/recordId' ), 504 'provides_context' => array( 505 'core/recordId' => 'recordId', 506 ), 507 ) 508 ); 509 $this->registry->register( 510 'core/consumer', 511 array( 512 'uses_context' => array( 'core/recordId' ), 513 'render_callback' => function( $block_attributes, $content, $block ) { 514 return sprintf( 'Record ID: %d ', $block->context['core/recordId'] ); 515 }, 516 ) 517 ); 518 519 add_filter( 'render_block_context', array( $this, 'filter_render_block_context' ), 10, 2 ); 520 521 $parsed_blocks = parse_blocks( '<!-- wp:consumer /--><!-- wp:provider {"recordId":20} --><!-- wp:consumer /--><!-- /wp:provider -->' ); 522 $context = array( 'core/recordId' => 10 ); 523 524 $rendered_content = ''; 525 526 foreach ( $parsed_blocks as $parsed_block ) { 527 $block = new WP_Block( $parsed_block, $context, $this->registry ); 528 529 $rendered_content .= $block->render(); 530 } 531 532 remove_filter( 'render_block_context', array( $this, 'filter_render_block_context' ) ); 533 534 $this->assertSame( 'Record ID: 11 Record ID: 21 ', $rendered_content ); 535 } 536 397 537 }
Note: See TracChangeset
for help on using the changeset viewer.