wp/wp-includes/class-wp-block.php
changeset 22 8c2e4d02f4ef
parent 21 48c4eec2b7e6
--- a/wp/wp-includes/class-wp-block.php	Fri Sep 05 18:40:08 2025 +0200
+++ b/wp/wp-includes/class-wp-block.php	Fri Sep 05 18:52:52 2025 +0200
@@ -56,7 +56,7 @@
 	 * @var array
 	 * @access protected
 	 */
-	protected $available_context;
+	protected $available_context = array();
 
 	/**
 	 * Block type registry.
@@ -114,7 +114,7 @@
 	 * @since 5.5.0
 	 *
 	 * @param array                  $block             {
-	 *     A representative array of a single parsed block object. See WP_Block_Parser_Block.
+	 *     An associative array of a single parsed block object. See WP_Block_Parser_Block.
 	 *
 	 *     @type string   $blockName    Name of block.
 	 *     @type array    $attrs        Attributes from block comment delimiters.
@@ -140,6 +140,28 @@
 
 		$this->available_context = $available_context;
 
+		$this->refresh_context_dependents();
+	}
+
+	/**
+	 * Updates the context for the current block and its inner blocks.
+	 *
+	 * The method updates the context of inner blocks, if any, by passing down
+	 * any context values the block provides (`provides_context`).
+	 *
+	 * If the block has inner blocks, the method recursively processes them by creating new instances of `WP_Block`
+	 * for each inner block and updating their context based on the block's `provides_context` property.
+	 *
+	 * @since 6.8.0
+	 */
+	public function refresh_context_dependents() {
+		/*
+		 * Merging the `$context` property here is not ideal, but for now needs to happen because of backward compatibility.
+		 * Ideally, the `$context` property itself would not be filterable directly and only the `$available_context` would be filterable.
+		 * However, this needs to be separately explored whether it's possible without breakage.
+		 */
+		$this->available_context = array_merge( $this->available_context, $this->context );
+
 		if ( ! empty( $this->block_type->uses_context ) ) {
 			foreach ( $this->block_type->uses_context as $context_name ) {
 				if ( array_key_exists( $context_name, $this->available_context ) ) {
@@ -148,7 +170,23 @@
 			}
 		}
 
-		if ( ! empty( $block['innerBlocks'] ) ) {
+		$this->refresh_parsed_block_dependents();
+	}
+
+	/**
+	 * Updates the parsed block content for the current block and its inner blocks.
+	 *
+	 * This method sets the `inner_html` and `inner_content` properties of the block based on the parsed
+	 * block content provided during initialization. It ensures that the block instance reflects the
+	 * most up-to-date content for both the inner HTML and any string fragments around inner blocks.
+	 *
+	 * If the block has inner blocks, this method initializes a new `WP_Block_List` for them, ensuring the
+	 * correct content and context are updated for each nested block.
+	 *
+	 * @since 6.8.0
+	 */
+	public function refresh_parsed_block_dependents() {
+		if ( ! empty( $this->parsed_block['innerBlocks'] ) ) {
 			$child_context = $this->available_context;
 
 			if ( ! empty( $this->block_type->provides_context ) ) {
@@ -159,15 +197,15 @@
 				}
 			}
 
-			$this->inner_blocks = new WP_Block_List( $block['innerBlocks'], $child_context, $registry );
+			$this->inner_blocks = new WP_Block_List( $this->parsed_block['innerBlocks'], $child_context, $this->registry );
 		}
 
-		if ( ! empty( $block['innerHTML'] ) ) {
-			$this->inner_html = $block['innerHTML'];
+		if ( ! empty( $this->parsed_block['innerHTML'] ) ) {
+			$this->inner_html = $this->parsed_block['innerHTML'];
 		}
 
-		if ( ! empty( $block['innerContent'] ) ) {
-			$this->inner_content = $block['innerContent'];
+		if ( ! empty( $this->parsed_block['innerContent'] ) ) {
+			$this->inner_content = $this->parsed_block['innerContent'];
 		}
 	}
 
@@ -237,6 +275,7 @@
 	 *
 	 * @since 6.5.0
 	 * @since 6.6.0 Handle the `__default` attribute for pattern overrides.
+	 * @since 6.7.0 Return any updated bindings metadata in the computed attributes.
 	 *
 	 * @return array The computed block attributes for the provided block bindings.
 	 */
@@ -284,6 +323,14 @@
 					: array( 'source' => 'core/pattern-overrides' );
 			}
 			$bindings = $updated_bindings;
+			/*
+			 * Update the bindings metadata of the computed attributes.
+			 * This ensures the block receives the expanded __default binding metadata when it renders.
+			 */
+			$computed_attributes['metadata'] = array_merge(
+				$parsed_block['attrs']['metadata'],
+				array( 'bindings' => $bindings )
+			);
 		}
 
 		foreach ( $bindings as $attribute_name => $block_binding ) {
@@ -301,6 +348,15 @@
 				continue;
 			}
 
+			// Adds the necessary context defined by the source.
+			if ( ! empty( $block_binding_source->uses_context ) ) {
+				foreach ( $block_binding_source->uses_context as $context_name ) {
+					if ( array_key_exists( $context_name, $this->available_context ) ) {
+						$this->context[ $context_name ] = $this->available_context[ $context_name ];
+					}
+				}
+			}
+
 			$source_args  = ! empty( $block_binding['args'] ) && is_array( $block_binding['args'] ) ? $block_binding['args'] : array();
 			$source_value = $block_binding_source->get_value( $source_args, $this, $attribute_name );
 
@@ -356,7 +412,7 @@
 
 				foreach ( $selectors as $selector ) {
 					// If the parent tag, or any of its children, matches the selector, replace the HTML.
-					if ( strcasecmp( $block_reader->get_tag( $selector ), $selector ) === 0 || $block_reader->next_tag(
+					if ( strcasecmp( $block_reader->get_tag(), $selector ) === 0 || $block_reader->next_tag(
 						array(
 							'tag_name' => $selector,
 						)
@@ -488,7 +544,8 @@
 					if ( ! is_null( $pre_render ) ) {
 						$block_content .= $pre_render;
 					} else {
-						$source_block = $inner_block->parsed_block;
+						$source_block        = $inner_block->parsed_block;
+						$inner_block_context = $inner_block->context;
 
 						/** This filter is documented in wp-includes/blocks.php */
 						$inner_block->parsed_block = apply_filters( 'render_block_data', $inner_block->parsed_block, $source_block, $parent_block );
@@ -496,6 +553,16 @@
 						/** This filter is documented in wp-includes/blocks.php */
 						$inner_block->context = apply_filters( 'render_block_context', $inner_block->context, $inner_block->parsed_block, $parent_block );
 
+						/*
+						 * The `refresh_context_dependents()` method already calls `refresh_parsed_block_dependents()`.
+						 * Therefore the second condition is irrelevant if the first one is satisfied.
+						 */
+						if ( $inner_block->context !== $inner_block_context ) {
+							$inner_block->refresh_context_dependents();
+						} elseif ( $inner_block->parsed_block !== $source_block ) {
+							$inner_block->refresh_parsed_block_dependents();
+						}
+
 						$block_content .= $inner_block->render();
 					}
 
@@ -541,6 +608,11 @@
 			}
 		}
 
+		/*
+		 * For Core blocks, these styles are only enqueued if `wp_should_load_separate_core_block_assets()` returns
+		 * true. Otherwise these `wp_enqueue_style()` calls will not have any effect, as the Core blocks are relying on
+		 * the combined 'wp-block-library' stylesheet instead, which is unconditionally enqueued.
+		 */
 		if ( ( ! empty( $this->block_type->style_handles ) ) ) {
 			foreach ( $this->block_type->style_handles as $style_handle ) {
 				wp_enqueue_style( $style_handle );