From d10be4251d7b8177e38816f32e12e741818f2d92 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 21 Aug 2025 19:32:21 +0200 Subject: [PATCH 1/4] Do not explose block bindings processor class --- src/wp-includes/class-wp-block.php | 49 +++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-block.php b/src/wp-includes/class-wp-block.php index 173b0dbe80067..4ce213d232ede 100644 --- a/src/wp-includes/class-wp-block.php +++ b/src/wp-includes/class-wp-block.php @@ -417,7 +417,7 @@ private function replace_html( string $block_content, string $attribute_name, $s switch ( $block_type->attributes[ $attribute_name ]['source'] ) { case 'html': case 'rich-text': - $block_reader = WP_Block_Bindings_Processor::create_fragment( $block_content ); + $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. @@ -462,6 +462,53 @@ private function replace_html( string $block_content, string $attribute_name, $s } } + private static function get_block_bindings_processor( string $block_content ) { + $internal_processor_class = new class ('', WP_HTML_Processor::CONSTRUCTOR_UNLOCK_CODE) extends WP_HTML_Processor { + private $output = ''; + private $end_of_flushed = 0; + + public function build() { + return $this->output . substr( $this->get_updated_html(), $this->end_of_flushed ); + } + + /** + * Replace the rich text content between a tag opener and matching closer. + * + * When stopped on a tag opener, replace the content enclosed by it and its + * matching closer with the provided rich text. + * + * @param string $rich_text The rich text to replace the original content with. + * @return bool True on success. + */ + public function replace_rich_text( $rich_text ) { + if ( $this->is_tag_closer() ) { + return false; + } + + $depth = $this->get_current_depth(); + + $this->set_bookmark( '_wp_block_bindings_tag_opener' ); + // The bookmark names are prefixed with `_` so the key below has an extra `_`. + $bm = $this->bookmarks['__wp_block_bindings_tag_opener']; + $this->output .= substr( $this->get_updated_html(), $this->end_of_flushed, $bm->start + $bm->length ); + $this->output .= $rich_text; + $this->release_bookmark( '_wp_block_bindings_tag_opener' ); + + // Find matching tag closer. + while ( $this->next_token() && $this->get_current_depth() >= $depth ) { + } + + $this->set_bookmark( '_wp_block_bindings_tag_closer' ); + $bm = $this->bookmarks['__wp_block_bindings_tag_closer']; + $this->end_of_flushed = $bm->start; + $this->release_bookmark( '_wp_block_bindings_tag_closer' ); + + return true; + } + }; + + return $internal_processor_class::create_fragment( $block_content ); + } /** * Generates the render output for the block. From e0183a4d1800ecdf2af6452434292bfdfb742777 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 21 Aug 2025 19:32:33 +0200 Subject: [PATCH 2/4] Remove block bindings processor class --- .../class-wp-block-bindings-processor.php | 70 ------------------- src/wp-settings.php | 1 - 2 files changed, 71 deletions(-) delete mode 100644 src/wp-includes/class-wp-block-bindings-processor.php diff --git a/src/wp-includes/class-wp-block-bindings-processor.php b/src/wp-includes/class-wp-block-bindings-processor.php deleted file mode 100644 index f833b9ed07562..0000000000000 --- a/src/wp-includes/class-wp-block-bindings-processor.php +++ /dev/null @@ -1,70 +0,0 @@ -output . substr( $this->get_updated_html(), $this->end_of_flushed ); - } - - /** - * Replace the rich text content between a tag opener and matching closer. - * - * When stopped on a tag opener, replace the content enclosed by it and its - * matching closer with the provided rich text. - * - * @param string $rich_text The rich text to replace the original content with. - * @return bool True on success. - */ - public function replace_rich_text( $rich_text ) { - if ( $this->is_tag_closer() ) { - return false; - } - - $depth = $this->get_current_depth(); - - $this->set_bookmark( '_wp_block_bindings_tag_opener' ); - // The bookmark names are prefixed with `_` so the key below has an extra `_`. - $bm = $this->bookmarks['__wp_block_bindings_tag_opener']; - $this->output .= substr( $this->get_updated_html(), $this->end_of_flushed, $bm->start + $bm->length ); - $this->output .= $rich_text; - $this->release_bookmark( '_wp_block_bindings_tag_opener' ); - - // Find matching tag closer. - while ( $this->next_token() && $this->get_current_depth() >= $depth ) { - } - - $this->set_bookmark( '_wp_block_bindings_tag_closer' ); - $bm = $this->bookmarks['__wp_block_bindings_tag_closer']; - $this->end_of_flushed = $bm->start; - $this->release_bookmark( '_wp_block_bindings_tag_closer' ); - - return true; - } -} diff --git a/src/wp-settings.php b/src/wp-settings.php index 6bfa853526ae0..3892b8cd33f91 100644 --- a/src/wp-settings.php +++ b/src/wp-settings.php @@ -346,7 +346,6 @@ require ABSPATH . WPINC . '/sitemaps/providers/class-wp-sitemaps-posts.php'; require ABSPATH . WPINC . '/sitemaps/providers/class-wp-sitemaps-taxonomies.php'; require ABSPATH . WPINC . '/sitemaps/providers/class-wp-sitemaps-users.php'; -require ABSPATH . WPINC . '/class-wp-block-bindings-processor.php'; require ABSPATH . WPINC . '/class-wp-block-bindings-source.php'; require ABSPATH . WPINC . '/class-wp-block-bindings-registry.php'; require ABSPATH . WPINC . '/class-wp-block-editor-context.php'; From dec9570a12031703f8075ee1672c35e0ca390551 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 21 Aug 2025 19:35:36 +0200 Subject: [PATCH 3/4] wpcs --- src/wp-includes/class-wp-block.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/wp-includes/class-wp-block.php b/src/wp-includes/class-wp-block.php index 4ce213d232ede..ed72f90e64005 100644 --- a/src/wp-includes/class-wp-block.php +++ b/src/wp-includes/class-wp-block.php @@ -294,9 +294,9 @@ public function __get( $name ) { * @return array The computed block attributes for the provided block bindings. */ private function process_block_bindings() { - $block_type = $this->name; - $parsed_block = $this->parsed_block; - $computed_attributes = array(); + $block_type = $this->name; + $parsed_block = $this->parsed_block; + $computed_attributes = array(); $supported_block_attributes = self::BLOCK_BINDINGS_SUPPORTED_ATTRIBUTES[ $block_type ] ?? @@ -417,7 +417,7 @@ private function replace_html( string $block_content, string $attribute_name, $s switch ( $block_type->attributes[ $attribute_name ]['source'] ) { case 'html': case 'rich-text': - $block_reader = self::get_block_bindings_processor($block_content); + $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. @@ -463,7 +463,7 @@ private function replace_html( string $block_content, string $attribute_name, $s } private static function get_block_bindings_processor( string $block_content ) { - $internal_processor_class = new class ('', WP_HTML_Processor::CONSTRUCTOR_UNLOCK_CODE) extends WP_HTML_Processor { + $internal_processor_class = new class('', WP_HTML_Processor::CONSTRUCTOR_UNLOCK_CODE) extends WP_HTML_Processor { private $output = ''; private $end_of_flushed = 0; From 7bd16b538e9623d5a670ded89e934050f3726ed8 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 21 Aug 2025 19:36:46 +0200 Subject: [PATCH 4/4] Make the hidden class instance static --- src/wp-includes/class-wp-block.php | 77 ++++++++++++++++-------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/src/wp-includes/class-wp-block.php b/src/wp-includes/class-wp-block.php index ed72f90e64005..b774da74de0c7 100644 --- a/src/wp-includes/class-wp-block.php +++ b/src/wp-includes/class-wp-block.php @@ -463,49 +463,52 @@ private function replace_html( string $block_content, string $attribute_name, $s } private static function get_block_bindings_processor( string $block_content ) { - $internal_processor_class = new class('', WP_HTML_Processor::CONSTRUCTOR_UNLOCK_CODE) extends WP_HTML_Processor { - private $output = ''; - private $end_of_flushed = 0; - - public function build() { - return $this->output . substr( $this->get_updated_html(), $this->end_of_flushed ); - } - - /** - * Replace the rich text content between a tag opener and matching closer. - * - * When stopped on a tag opener, replace the content enclosed by it and its - * matching closer with the provided rich text. - * - * @param string $rich_text The rich text to replace the original content with. - * @return bool True on success. - */ - public function replace_rich_text( $rich_text ) { - if ( $this->is_tag_closer() ) { - return false; + static $internal_processor_class = null; + if ( null === $internal_processor_class ) { + $internal_processor_class = new class('', WP_HTML_Processor::CONSTRUCTOR_UNLOCK_CODE) extends WP_HTML_Processor { + private $output = ''; + private $end_of_flushed = 0; + + public function build() { + return $this->output . substr( $this->get_updated_html(), $this->end_of_flushed ); } - $depth = $this->get_current_depth(); + /** + * Replace the rich text content between a tag opener and matching closer. + * + * When stopped on a tag opener, replace the content enclosed by it and its + * matching closer with the provided rich text. + * + * @param string $rich_text The rich text to replace the original content with. + * @return bool True on success. + */ + public function replace_rich_text( $rich_text ) { + if ( $this->is_tag_closer() ) { + return false; + } - $this->set_bookmark( '_wp_block_bindings_tag_opener' ); - // The bookmark names are prefixed with `_` so the key below has an extra `_`. - $bm = $this->bookmarks['__wp_block_bindings_tag_opener']; - $this->output .= substr( $this->get_updated_html(), $this->end_of_flushed, $bm->start + $bm->length ); - $this->output .= $rich_text; - $this->release_bookmark( '_wp_block_bindings_tag_opener' ); + $depth = $this->get_current_depth(); - // Find matching tag closer. - while ( $this->next_token() && $this->get_current_depth() >= $depth ) { - } + $this->set_bookmark( '_wp_block_bindings_tag_opener' ); + // The bookmark names are prefixed with `_` so the key below has an extra `_`. + $bm = $this->bookmarks['__wp_block_bindings_tag_opener']; + $this->output .= substr( $this->get_updated_html(), $this->end_of_flushed, $bm->start + $bm->length ); + $this->output .= $rich_text; + $this->release_bookmark( '_wp_block_bindings_tag_opener' ); - $this->set_bookmark( '_wp_block_bindings_tag_closer' ); - $bm = $this->bookmarks['__wp_block_bindings_tag_closer']; - $this->end_of_flushed = $bm->start; - $this->release_bookmark( '_wp_block_bindings_tag_closer' ); + // Find matching tag closer. + while ( $this->next_token() && $this->get_current_depth() >= $depth ) { + } - return true; - } - }; + $this->set_bookmark( '_wp_block_bindings_tag_closer' ); + $bm = $this->bookmarks['__wp_block_bindings_tag_closer']; + $this->end_of_flushed = $bm->start; + $this->release_bookmark( '_wp_block_bindings_tag_closer' ); + + return true; + } + }; + } return $internal_processor_class::create_fragment( $block_content ); }