diff -r 48c4eec2b7e6 -r 8c2e4d02f4ef wp/wp-includes/class-wp-block.php --- 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 );