From 763bcc2d17f4f4d269d8a71a8a54d6cc6c430262 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 15 Jan 2026 16:25:25 +0100 Subject: [PATCH 1/4] Block Bindings: Introduce $attribute var in replace_html --- src/wp-includes/class-wp-block.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/wp-includes/class-wp-block.php b/src/wp-includes/class-wp-block.php index f59b770d93b5b..a9b5054786c55 100644 --- a/src/wp-includes/class-wp-block.php +++ b/src/wp-includes/class-wp-block.php @@ -372,19 +372,25 @@ private function process_block_bindings() { */ private function replace_html( string $block_content, string $attribute_name, $source_value ) { $block_type = $this->block_type; - if ( ! isset( $block_type->attributes[ $attribute_name ]['source'] ) ) { + + if ( ! isset( $block_type->attributes[ $attribute_name ] ) ) { + return $block_content; + } + $attribute = $block_type->attributes[ $attribute_name ]; + + if ( ! isset( $attribute['source'] ) ) { return $block_content; } // Depending on the attribute source, the processing will be different. - switch ( $block_type->attributes[ $attribute_name ]['source'] ) { + switch ( $attribute['source'] ) { case 'html': case 'rich-text': $block_reader = self::get_block_bindings_processor( $block_content ); // TODO: Support for CSS selectors whenever they are ready in the HTML API. // In the meantime, support comma-separated selectors by exploding them into an array. - $selectors = explode( ',', $block_type->attributes[ $attribute_name ]['selector'] ); + $selectors = explode( ',', $attribute['selector'] ); // Add a bookmark to the first tag to be able to iterate over the selectors. $block_reader->next_tag(); $block_reader->set_bookmark( 'iterate-selectors' ); @@ -412,12 +418,12 @@ private function replace_html( string $block_content, string $attribute_name, $s if ( ! $amended_content->next_tag( array( // TODO: build the query from CSS selector. - 'tag_name' => $block_type->attributes[ $attribute_name ]['selector'], + 'tag_name' => $attribute['selector'], ) ) ) { return $block_content; } - $amended_content->set_attribute( $block_type->attributes[ $attribute_name ]['attribute'], $source_value ); + $amended_content->set_attribute( $attribute['attribute'], $source_value ); return $amended_content->get_updated_html(); default: From f6035e2758b6132aac1c49a814baf473892c5bd9 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 15 Jan 2026 16:25:58 +0100 Subject: [PATCH 2/4] Block Bindings: Allow filtering attributes that are replaced in markup --- src/wp-includes/class-wp-block.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wp-includes/class-wp-block.php b/src/wp-includes/class-wp-block.php index a9b5054786c55..7ce2ea4c8d624 100644 --- a/src/wp-includes/class-wp-block.php +++ b/src/wp-includes/class-wp-block.php @@ -377,6 +377,7 @@ private function replace_html( string $block_content, string $attribute_name, $s return $block_content; } $attribute = $block_type->attributes[ $attribute_name ]; + $attribute = apply_filters( 'block_bindings_attribute_replaced_in_markup', $attribute, $attribute_name, $this->name ); if ( ! isset( $attribute['source'] ) ) { return $block_content; From 8306e2290fc55a056e5f102383485141f1927a06 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 15 Jan 2026 16:46:43 +0100 Subject: [PATCH 3/4] Add explanatory comment --- src/wp-includes/class-wp-block.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/wp-includes/class-wp-block.php b/src/wp-includes/class-wp-block.php index 7ce2ea4c8d624..5abc2e711de32 100644 --- a/src/wp-includes/class-wp-block.php +++ b/src/wp-includes/class-wp-block.php @@ -377,6 +377,30 @@ private function replace_html( string $block_content, string $attribute_name, $s return $block_content; } $attribute = $block_type->attributes[ $attribute_name ]; + /** + * Modify an attribute's properties (for the purposes of being replaced in the block markup). + * + * By default, Block Bindings will replace sourced attributes in the markup with + * the value from the source. However, some blocks persist attribute values explicitly + * and still duplicate them in the markup. In those cases, this filter allows marking + * them as "pseudo-sourced", so that they will also be replaced with the bound value. + * + * @since 7.0.0 + * + * @example function( $attribute, $attribute_name, $block_name ) { + * if ( 'core/cover' === $block_name && 'url' === $attribute_name ) { + * $attribute['source'] = 'attribute'; + * $attribute['selector'] = 'img'; + * $attribute['attribute'] = 'src'; + * } + * return $attribute; + * } + * + * @param array $attribute The attribute properties. + * @param string $attribute_name The attribute name. + * @param string $block_name The block name. + * @return array The modified attribute properties. + */ $attribute = apply_filters( 'block_bindings_attribute_replaced_in_markup', $attribute, $attribute_name, $this->name ); if ( ! isset( $attribute['source'] ) ) { From 97cfc85282db0aefb3082b112da1f3b837a897f6 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 15 Jan 2026 16:47:38 +0100 Subject: [PATCH 4/4] Add newline --- src/wp-includes/class-wp-block.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wp-includes/class-wp-block.php b/src/wp-includes/class-wp-block.php index 5abc2e711de32..a8662d698ef96 100644 --- a/src/wp-includes/class-wp-block.php +++ b/src/wp-includes/class-wp-block.php @@ -377,6 +377,7 @@ private function replace_html( string $block_content, string $attribute_name, $s return $block_content; } $attribute = $block_type->attributes[ $attribute_name ]; + /** * Modify an attribute's properties (for the purposes of being replaced in the block markup). *