wp/wp-includes/class-wp-block.php
changeset 22 8c2e4d02f4ef
parent 21 48c4eec2b7e6
equal deleted inserted replaced
21:48c4eec2b7e6 22:8c2e4d02f4ef
    54 	 *
    54 	 *
    55 	 * @since 5.5.0
    55 	 * @since 5.5.0
    56 	 * @var array
    56 	 * @var array
    57 	 * @access protected
    57 	 * @access protected
    58 	 */
    58 	 */
    59 	protected $available_context;
    59 	protected $available_context = array();
    60 
    60 
    61 	/**
    61 	/**
    62 	 * Block type registry.
    62 	 * Block type registry.
    63 	 *
    63 	 *
    64 	 * @since 5.9.0
    64 	 * @since 5.9.0
   112 	 * its registered type will be assigned to the block's `context` property.
   112 	 * its registered type will be assigned to the block's `context` property.
   113 	 *
   113 	 *
   114 	 * @since 5.5.0
   114 	 * @since 5.5.0
   115 	 *
   115 	 *
   116 	 * @param array                  $block             {
   116 	 * @param array                  $block             {
   117 	 *     A representative array of a single parsed block object. See WP_Block_Parser_Block.
   117 	 *     An associative array of a single parsed block object. See WP_Block_Parser_Block.
   118 	 *
   118 	 *
   119 	 *     @type string   $blockName    Name of block.
   119 	 *     @type string   $blockName    Name of block.
   120 	 *     @type array    $attrs        Attributes from block comment delimiters.
   120 	 *     @type array    $attrs        Attributes from block comment delimiters.
   121 	 *     @type array    $innerBlocks  List of inner blocks. An array of arrays that
   121 	 *     @type array    $innerBlocks  List of inner blocks. An array of arrays that
   122 	 *                                  have the same structure as this one.
   122 	 *                                  have the same structure as this one.
   138 
   138 
   139 		$this->block_type = $registry->get_registered( $this->name );
   139 		$this->block_type = $registry->get_registered( $this->name );
   140 
   140 
   141 		$this->available_context = $available_context;
   141 		$this->available_context = $available_context;
   142 
   142 
       
   143 		$this->refresh_context_dependents();
       
   144 	}
       
   145 
       
   146 	/**
       
   147 	 * Updates the context for the current block and its inner blocks.
       
   148 	 *
       
   149 	 * The method updates the context of inner blocks, if any, by passing down
       
   150 	 * any context values the block provides (`provides_context`).
       
   151 	 *
       
   152 	 * If the block has inner blocks, the method recursively processes them by creating new instances of `WP_Block`
       
   153 	 * for each inner block and updating their context based on the block's `provides_context` property.
       
   154 	 *
       
   155 	 * @since 6.8.0
       
   156 	 */
       
   157 	public function refresh_context_dependents() {
       
   158 		/*
       
   159 		 * Merging the `$context` property here is not ideal, but for now needs to happen because of backward compatibility.
       
   160 		 * Ideally, the `$context` property itself would not be filterable directly and only the `$available_context` would be filterable.
       
   161 		 * However, this needs to be separately explored whether it's possible without breakage.
       
   162 		 */
       
   163 		$this->available_context = array_merge( $this->available_context, $this->context );
       
   164 
   143 		if ( ! empty( $this->block_type->uses_context ) ) {
   165 		if ( ! empty( $this->block_type->uses_context ) ) {
   144 			foreach ( $this->block_type->uses_context as $context_name ) {
   166 			foreach ( $this->block_type->uses_context as $context_name ) {
   145 				if ( array_key_exists( $context_name, $this->available_context ) ) {
   167 				if ( array_key_exists( $context_name, $this->available_context ) ) {
   146 					$this->context[ $context_name ] = $this->available_context[ $context_name ];
   168 					$this->context[ $context_name ] = $this->available_context[ $context_name ];
   147 				}
   169 				}
   148 			}
   170 			}
   149 		}
   171 		}
   150 
   172 
   151 		if ( ! empty( $block['innerBlocks'] ) ) {
   173 		$this->refresh_parsed_block_dependents();
       
   174 	}
       
   175 
       
   176 	/**
       
   177 	 * Updates the parsed block content for the current block and its inner blocks.
       
   178 	 *
       
   179 	 * This method sets the `inner_html` and `inner_content` properties of the block based on the parsed
       
   180 	 * block content provided during initialization. It ensures that the block instance reflects the
       
   181 	 * most up-to-date content for both the inner HTML and any string fragments around inner blocks.
       
   182 	 *
       
   183 	 * If the block has inner blocks, this method initializes a new `WP_Block_List` for them, ensuring the
       
   184 	 * correct content and context are updated for each nested block.
       
   185 	 *
       
   186 	 * @since 6.8.0
       
   187 	 */
       
   188 	public function refresh_parsed_block_dependents() {
       
   189 		if ( ! empty( $this->parsed_block['innerBlocks'] ) ) {
   152 			$child_context = $this->available_context;
   190 			$child_context = $this->available_context;
   153 
   191 
   154 			if ( ! empty( $this->block_type->provides_context ) ) {
   192 			if ( ! empty( $this->block_type->provides_context ) ) {
   155 				foreach ( $this->block_type->provides_context as $context_name => $attribute_name ) {
   193 				foreach ( $this->block_type->provides_context as $context_name => $attribute_name ) {
   156 					if ( array_key_exists( $attribute_name, $this->attributes ) ) {
   194 					if ( array_key_exists( $attribute_name, $this->attributes ) ) {
   157 						$child_context[ $context_name ] = $this->attributes[ $attribute_name ];
   195 						$child_context[ $context_name ] = $this->attributes[ $attribute_name ];
   158 					}
   196 					}
   159 				}
   197 				}
   160 			}
   198 			}
   161 
   199 
   162 			$this->inner_blocks = new WP_Block_List( $block['innerBlocks'], $child_context, $registry );
   200 			$this->inner_blocks = new WP_Block_List( $this->parsed_block['innerBlocks'], $child_context, $this->registry );
   163 		}
   201 		}
   164 
   202 
   165 		if ( ! empty( $block['innerHTML'] ) ) {
   203 		if ( ! empty( $this->parsed_block['innerHTML'] ) ) {
   166 			$this->inner_html = $block['innerHTML'];
   204 			$this->inner_html = $this->parsed_block['innerHTML'];
   167 		}
   205 		}
   168 
   206 
   169 		if ( ! empty( $block['innerContent'] ) ) {
   207 		if ( ! empty( $this->parsed_block['innerContent'] ) ) {
   170 			$this->inner_content = $block['innerContent'];
   208 			$this->inner_content = $this->parsed_block['innerContent'];
   171 		}
   209 		}
   172 	}
   210 	}
   173 
   211 
   174 	/**
   212 	/**
   175 	 * Returns a value from an inaccessible property.
   213 	 * Returns a value from an inaccessible property.
   235 	 * The above example will replace the `title` and `url` attributes of the Image
   273 	 * The above example will replace the `title` and `url` attributes of the Image
   236 	 * block with the values of the `text_custom_field` and `url_custom_field` post meta.
   274 	 * block with the values of the `text_custom_field` and `url_custom_field` post meta.
   237 	 *
   275 	 *
   238 	 * @since 6.5.0
   276 	 * @since 6.5.0
   239 	 * @since 6.6.0 Handle the `__default` attribute for pattern overrides.
   277 	 * @since 6.6.0 Handle the `__default` attribute for pattern overrides.
       
   278 	 * @since 6.7.0 Return any updated bindings metadata in the computed attributes.
   240 	 *
   279 	 *
   241 	 * @return array The computed block attributes for the provided block bindings.
   280 	 * @return array The computed block attributes for the provided block bindings.
   242 	 */
   281 	 */
   243 	private function process_block_bindings() {
   282 	private function process_block_bindings() {
   244 		$parsed_block               = $this->parsed_block;
   283 		$parsed_block               = $this->parsed_block;
   282 				$updated_bindings[ $attribute_name ] = isset( $bindings[ $attribute_name ] )
   321 				$updated_bindings[ $attribute_name ] = isset( $bindings[ $attribute_name ] )
   283 					? $bindings[ $attribute_name ]
   322 					? $bindings[ $attribute_name ]
   284 					: array( 'source' => 'core/pattern-overrides' );
   323 					: array( 'source' => 'core/pattern-overrides' );
   285 			}
   324 			}
   286 			$bindings = $updated_bindings;
   325 			$bindings = $updated_bindings;
       
   326 			/*
       
   327 			 * Update the bindings metadata of the computed attributes.
       
   328 			 * This ensures the block receives the expanded __default binding metadata when it renders.
       
   329 			 */
       
   330 			$computed_attributes['metadata'] = array_merge(
       
   331 				$parsed_block['attrs']['metadata'],
       
   332 				array( 'bindings' => $bindings )
       
   333 			);
   287 		}
   334 		}
   288 
   335 
   289 		foreach ( $bindings as $attribute_name => $block_binding ) {
   336 		foreach ( $bindings as $attribute_name => $block_binding ) {
   290 			// If the attribute is not in the supported list, process next attribute.
   337 			// If the attribute is not in the supported list, process next attribute.
   291 			if ( ! in_array( $attribute_name, $supported_block_attributes[ $this->name ], true ) ) {
   338 			if ( ! in_array( $attribute_name, $supported_block_attributes[ $this->name ], true ) ) {
   297 			}
   344 			}
   298 
   345 
   299 			$block_binding_source = get_block_bindings_source( $block_binding['source'] );
   346 			$block_binding_source = get_block_bindings_source( $block_binding['source'] );
   300 			if ( null === $block_binding_source ) {
   347 			if ( null === $block_binding_source ) {
   301 				continue;
   348 				continue;
       
   349 			}
       
   350 
       
   351 			// Adds the necessary context defined by the source.
       
   352 			if ( ! empty( $block_binding_source->uses_context ) ) {
       
   353 				foreach ( $block_binding_source->uses_context as $context_name ) {
       
   354 					if ( array_key_exists( $context_name, $this->available_context ) ) {
       
   355 						$this->context[ $context_name ] = $this->available_context[ $context_name ];
       
   356 					}
       
   357 				}
   302 			}
   358 			}
   303 
   359 
   304 			$source_args  = ! empty( $block_binding['args'] ) && is_array( $block_binding['args'] ) ? $block_binding['args'] : array();
   360 			$source_args  = ! empty( $block_binding['args'] ) && is_array( $block_binding['args'] ) ? $block_binding['args'] : array();
   305 			$source_value = $block_binding_source->get_value( $source_args, $this, $attribute_name );
   361 			$source_value = $block_binding_source->get_value( $source_args, $this, $attribute_name );
   306 
   362 
   354 					}
   410 					}
   355 				}
   411 				}
   356 
   412 
   357 				foreach ( $selectors as $selector ) {
   413 				foreach ( $selectors as $selector ) {
   358 					// If the parent tag, or any of its children, matches the selector, replace the HTML.
   414 					// If the parent tag, or any of its children, matches the selector, replace the HTML.
   359 					if ( strcasecmp( $block_reader->get_tag( $selector ), $selector ) === 0 || $block_reader->next_tag(
   415 					if ( strcasecmp( $block_reader->get_tag(), $selector ) === 0 || $block_reader->next_tag(
   360 						array(
   416 						array(
   361 							'tag_name' => $selector,
   417 							'tag_name' => $selector,
   362 						)
   418 						)
   363 					) ) {
   419 					) ) {
   364 						$block_reader->release_bookmark( 'iterate-selectors' );
   420 						$block_reader->release_bookmark( 'iterate-selectors' );
   486 					$pre_render = apply_filters( 'pre_render_block', null, $inner_block->parsed_block, $parent_block );
   542 					$pre_render = apply_filters( 'pre_render_block', null, $inner_block->parsed_block, $parent_block );
   487 
   543 
   488 					if ( ! is_null( $pre_render ) ) {
   544 					if ( ! is_null( $pre_render ) ) {
   489 						$block_content .= $pre_render;
   545 						$block_content .= $pre_render;
   490 					} else {
   546 					} else {
   491 						$source_block = $inner_block->parsed_block;
   547 						$source_block        = $inner_block->parsed_block;
       
   548 						$inner_block_context = $inner_block->context;
   492 
   549 
   493 						/** This filter is documented in wp-includes/blocks.php */
   550 						/** This filter is documented in wp-includes/blocks.php */
   494 						$inner_block->parsed_block = apply_filters( 'render_block_data', $inner_block->parsed_block, $source_block, $parent_block );
   551 						$inner_block->parsed_block = apply_filters( 'render_block_data', $inner_block->parsed_block, $source_block, $parent_block );
   495 
   552 
   496 						/** This filter is documented in wp-includes/blocks.php */
   553 						/** This filter is documented in wp-includes/blocks.php */
   497 						$inner_block->context = apply_filters( 'render_block_context', $inner_block->context, $inner_block->parsed_block, $parent_block );
   554 						$inner_block->context = apply_filters( 'render_block_context', $inner_block->context, $inner_block->parsed_block, $parent_block );
       
   555 
       
   556 						/*
       
   557 						 * The `refresh_context_dependents()` method already calls `refresh_parsed_block_dependents()`.
       
   558 						 * Therefore the second condition is irrelevant if the first one is satisfied.
       
   559 						 */
       
   560 						if ( $inner_block->context !== $inner_block_context ) {
       
   561 							$inner_block->refresh_context_dependents();
       
   562 						} elseif ( $inner_block->parsed_block !== $source_block ) {
       
   563 							$inner_block->refresh_parsed_block_dependents();
       
   564 						}
   498 
   565 
   499 						$block_content .= $inner_block->render();
   566 						$block_content .= $inner_block->render();
   500 					}
   567 					}
   501 
   568 
   502 					++$index;
   569 					++$index;
   539 			foreach ( $this->block_type->view_script_module_ids as $view_script_module_id ) {
   606 			foreach ( $this->block_type->view_script_module_ids as $view_script_module_id ) {
   540 				wp_enqueue_script_module( $view_script_module_id );
   607 				wp_enqueue_script_module( $view_script_module_id );
   541 			}
   608 			}
   542 		}
   609 		}
   543 
   610 
       
   611 		/*
       
   612 		 * For Core blocks, these styles are only enqueued if `wp_should_load_separate_core_block_assets()` returns
       
   613 		 * true. Otherwise these `wp_enqueue_style()` calls will not have any effect, as the Core blocks are relying on
       
   614 		 * the combined 'wp-block-library' stylesheet instead, which is unconditionally enqueued.
       
   615 		 */
   544 		if ( ( ! empty( $this->block_type->style_handles ) ) ) {
   616 		if ( ( ! empty( $this->block_type->style_handles ) ) ) {
   545 			foreach ( $this->block_type->style_handles as $style_handle ) {
   617 			foreach ( $this->block_type->style_handles as $style_handle ) {
   546 				wp_enqueue_style( $style_handle );
   618 				wp_enqueue_style( $style_handle );
   547 			}
   619 			}
   548 		}
   620 		}