From 2c9a17d4256afa0327d76c939b89cefd19ebb10a Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 10 Dec 2025 13:59:31 +0100 Subject: [PATCH 01/15] Fix group -> ticket test annotation --- tests/phpunit/tests/html-api/wpHtmlProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php index 13e0728ca912a..b5cf33b4f406e 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php @@ -1068,7 +1068,7 @@ public function test_ensure_next_token_method_extensibility( $html, $expected_to /** * Ensure that lowercased tag_name query matches tags case-insensitively. * - * @group 62427 + * @ticket 62427 */ public function test_next_tag_lowercase_tag_name() { // The upper case
is irrelevant but illustrates the case-insentivity. From da5375275d4b565bf5ab4b15afd1fd6a7312ac8a Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 10 Dec 2025 13:59:56 +0100 Subject: [PATCH 02/15] Add failing test for deep nesting --- .../tests/html-api/wpHtmlProcessor.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php index b5cf33b4f406e..4d95e637c8533 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php @@ -1079,4 +1079,23 @@ public function test_next_tag_lowercase_tag_name() { $processor = WP_HTML_Processor::create_fragment( '' ); $this->assertTrue( $processor->next_tag( array( 'tag_name' => 'rect' ) ) ); } + + /** + * Ensure that the processor does not throw errors in cases of extreme HTML nesting. + * + * @ticket TBD + * + * @expectedIncorrectUsage WP_HTML_Tag_Processor::set_bookmark + */ + public function test_deep_nesting_fails_process_without_error() { + $html = str_repeat( '', WP_HTML_Processor::MAX_BOOKMARKS * 2 ); + $processor = WP_HTML_Processor::create_fragment( $html ); + + // The fragment parser starts with a few context tokens already bookmarked. + $reached_tokens = ( fn() => count( $this->bookmarks ) )->call( $processor ); + while ( $processor->next_token() ) { + ++$reached_tokens; + } + $this->assertSame( WP_HTML_Processor::MAX_BOOKMARKS, $reached_tokens ); + } } From 0337b133e05144f70d04f0b4e99666275eb5d447 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 10 Dec 2025 14:00:39 +0100 Subject: [PATCH 03/15] Handle Exception thrown by bookmark_token() --- src/wp-includes/html-api/class-wp-html-processor.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/html-api/class-wp-html-processor.php b/src/wp-includes/html-api/class-wp-html-processor.php index 55f955f2c1a9a..006d11f2fb1c3 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -1040,8 +1040,17 @@ public function step( $node_to_process = self::PROCESS_NEXT_NODE ): bool { $token_name = $this->get_token_name(); if ( self::REPROCESS_CURRENT_NODE !== $node_to_process ) { + try { + $bookmark_name = $this->bookmark_token(); + } catch ( Exception $e ) { + if ( self::ERROR_EXCEEDED_MAX_BOOKMARKS === $this->last_error ) { + return false; + } + throw $e; + } + $this->state->current_token = new WP_HTML_Token( - $this->bookmark_token(), + $bookmark_name, $token_name, $this->has_self_closing_flag(), $this->release_internal_bookmark_on_destruct From 410123577d7aa06f28b84973696b954b99334ed2 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 10 Dec 2025 14:00:55 +0100 Subject: [PATCH 04/15] Add failing test for virtual tokens --- .../tests/html-api/wpHtmlProcessor.php | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php index 4d95e637c8533..7fd6efe4878d7 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php @@ -1098,4 +1098,38 @@ public function test_deep_nesting_fails_process_without_error() { } $this->assertSame( WP_HTML_Processor::MAX_BOOKMARKS, $reached_tokens ); } + + /** + * @ticket TBD + * + * @expectedIncorrectUsage WP_HTML_Tag_Processor::set_bookmark + */ + public function test_deep_nesting_fails_processing_virtual_tokens_without_error() { + $html = str_repeat( '
', WP_HTML_Processor::MAX_BOOKMARKS ); + $processor = WP_HTML_Processor::create_fragment( $html ); + + // The fragment parser starts with a few context tokens already bookmarked. + $reached_tokens = ( fn() => count( $this->bookmarks ) )->call( $processor ); + while ( $processor->next_token() ) { + ++$reached_tokens; + } + + /* + * This test has some variability depending on how the virtual tokens align. + * It will produce 1 real, 2 virtual, 1 real. + * + * "
…" produces: + * └─TABLE + * └─TBODY (virtual) + * └─TR (virtual) + * └─TD + * └─TABLE + * └─TBODY (virtual) + * └─TR (virtual) + * └─TD + * └─… + */ + $this->assertGreaterThanOrEqual( WP_HTML_Processor::MAX_BOOKMARKS - 1, $reached_tokens ); + $this->assertLessThanOrEqual( WP_HTML_Processor::MAX_BOOKMARKS + 1, $reached_tokens ); + } } From e7d649c9cafb04f7d45d76b6c3a32f6bc6f2f8a6 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 10 Dec 2025 15:55:06 +0100 Subject: [PATCH 05/15] Handle insert_virtual_node exceptions --- src/wp-includes/html-api/class-wp-html-processor.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/wp-includes/html-api/class-wp-html-processor.php b/src/wp-includes/html-api/class-wp-html-processor.php index 006d11f2fb1c3..21ad513e4caf3 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -1160,6 +1160,14 @@ public function step( $node_to_process = self::PROCESS_NEXT_NODE ): bool { * otherwise might involve messier calling and return conventions. */ return false; + } catch ( Exception $e ) { + if ( self::ERROR_EXCEEDED_MAX_BOOKMARKS === $this->last_error ) { + return false; + } + /* + * Rethrow any other exceptions for higher-level handling. + */ + throw $e; } } @@ -6296,6 +6304,8 @@ private function insert_foreign_element( WP_HTML_Token $token, bool $only_add_to * * @since 6.7.0 * + * @throws Exception When unable to allocate a bookmark for the next token in the input HTML document. + * * @param string $token_name Name of token to create and insert into the stack of open elements. * @param string|null $bookmark_name Optional. Name to give bookmark for created virtual node. * Defaults to auto-creating a bookmark name. From 1cfeb856c533b24383bbca936aa96e1f04d75544 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 10 Dec 2025 17:41:00 +0100 Subject: [PATCH 06/15] Fix php 7.x compat --- tests/phpunit/tests/html-api/wpHtmlProcessor.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php index 7fd6efe4878d7..6ff77fcbc355d 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php @@ -1092,7 +1092,9 @@ public function test_deep_nesting_fails_process_without_error() { $processor = WP_HTML_Processor::create_fragment( $html ); // The fragment parser starts with a few context tokens already bookmarked. - $reached_tokens = ( fn() => count( $this->bookmarks ) )->call( $processor ); + $reached_tokens = ( function () { + return count( $this->bookmarks ); + } )->call( $processor ); while ( $processor->next_token() ) { ++$reached_tokens; } @@ -1109,7 +1111,9 @@ public function test_deep_nesting_fails_processing_virtual_tokens_without_error( $processor = WP_HTML_Processor::create_fragment( $html ); // The fragment parser starts with a few context tokens already bookmarked. - $reached_tokens = ( fn() => count( $this->bookmarks ) )->call( $processor ); + $reached_tokens = ( function () { + return count( $this->bookmarks ); + } )->call( $processor ); while ( $processor->next_token() ) { ++$reached_tokens; } From 17bbca861c258a665a3164ff61ff1455b156e01f Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 10 Dec 2025 17:41:32 +0100 Subject: [PATCH 07/15] Update test ticket annotation --- tests/phpunit/tests/html-api/wpHtmlProcessor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php index 6ff77fcbc355d..3ab09c4ba7678 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php @@ -1083,7 +1083,7 @@ public function test_next_tag_lowercase_tag_name() { /** * Ensure that the processor does not throw errors in cases of extreme HTML nesting. * - * @ticket TBD + * @ticket 64394 * * @expectedIncorrectUsage WP_HTML_Tag_Processor::set_bookmark */ @@ -1102,7 +1102,7 @@ public function test_deep_nesting_fails_process_without_error() { } /** - * @ticket TBD + * @ticket 64394 * * @expectedIncorrectUsage WP_HTML_Tag_Processor::set_bookmark */ From ba480a51cd1bb00f053deaffd5f6d834af47b887 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 10 Dec 2025 17:44:28 +0100 Subject: [PATCH 08/15] Increase virtual token HTML size --- tests/phpunit/tests/html-api/wpHtmlProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php index 3ab09c4ba7678..5391063a1184e 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php @@ -1107,7 +1107,7 @@ public function test_deep_nesting_fails_process_without_error() { * @expectedIncorrectUsage WP_HTML_Tag_Processor::set_bookmark */ public function test_deep_nesting_fails_processing_virtual_tokens_without_error() { - $html = str_repeat( '
', WP_HTML_Processor::MAX_BOOKMARKS ); + $html = str_repeat( '
', WP_HTML_Processor::MAX_BOOKMARKS * 2 ); $processor = WP_HTML_Processor::create_fragment( $html ); // The fragment parser starts with a few context tokens already bookmarked. From ff7657fc1ce2020162e95863f9519e9929f13484 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Fri, 12 Dec 2025 13:18:23 +0100 Subject: [PATCH 09/15] Use single-line comment Co-authored-by: Weston Ruter --- src/wp-includes/html-api/class-wp-html-processor.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/wp-includes/html-api/class-wp-html-processor.php b/src/wp-includes/html-api/class-wp-html-processor.php index 21ad513e4caf3..5d11fe441283a 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -1164,9 +1164,7 @@ public function step( $node_to_process = self::PROCESS_NEXT_NODE ): bool { if ( self::ERROR_EXCEEDED_MAX_BOOKMARKS === $this->last_error ) { return false; } - /* - * Rethrow any other exceptions for higher-level handling. - */ + // Rethrow any other exceptions for higher-level handling. throw $e; } } From 9e042f3769292ed966e7b36ebeebac8631480c0f Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 29 Jan 2026 19:08:27 +0100 Subject: [PATCH 10/15] Return false or throw unsupported exception where available --- .../html-api/class-wp-html-processor.php | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/wp-includes/html-api/class-wp-html-processor.php b/src/wp-includes/html-api/class-wp-html-processor.php index 5d11fe441283a..e2ee09eb0883d 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -1040,13 +1040,9 @@ public function step( $node_to_process = self::PROCESS_NEXT_NODE ): bool { $token_name = $this->get_token_name(); if ( self::REPROCESS_CURRENT_NODE !== $node_to_process ) { - try { - $bookmark_name = $this->bookmark_token(); - } catch ( Exception $e ) { - if ( self::ERROR_EXCEEDED_MAX_BOOKMARKS === $this->last_error ) { - return false; - } - throw $e; + $bookmark_name = $this->bookmark_token(); + if ( false === $bookmark_name ) { + return false; } $this->state->current_token = new WP_HTML_Token( @@ -5115,14 +5111,12 @@ private function step_in_foreign_content(): bool { * @since 6.4.0 * @since 6.5.0 Renamed from bookmark_tag() to bookmark_token(). * - * @throws Exception When unable to allocate requested bookmark. - * * @return string|false Name of created bookmark, or false if unable to create. */ private function bookmark_token() { if ( ! parent::set_bookmark( ++$this->bookmark_counter ) ) { $this->last_error = self::ERROR_EXCEEDED_MAX_BOOKMARKS; - throw new Exception( 'could not allocate bookmark' ); + return false; } return "{$this->bookmark_counter}"; @@ -6302,7 +6296,7 @@ private function insert_foreign_element( WP_HTML_Token $token, bool $only_add_to * * @since 6.7.0 * - * @throws Exception When unable to allocate a bookmark for the next token in the input HTML document. + * @throws WP_HTML_Unsupported_Exception When unable to allocate a bookmark for the next token in the input HTML document. * * @param string $token_name Name of token to create and insert into the stack of open elements. * @param string|null $bookmark_name Optional. Name to give bookmark for created virtual node. @@ -6312,6 +6306,9 @@ private function insert_foreign_element( WP_HTML_Token $token, bool $only_add_to private function insert_virtual_node( $token_name, $bookmark_name = null ): WP_HTML_Token { $here = $this->bookmarks[ $this->state->current_token->bookmark_name ]; $name = $bookmark_name ?? $this->bookmark_token(); + if ( false === $name ) { + $this->bail( 'Unable to insert virtual node, bookmarks exhausted.' ); + } $this->bookmarks[ $name ] = new WP_HTML_Span( $here->start, 0 ); From c7710aa1438464f9cc2aa58bbbd9c010b9a2f7a8 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 29 Jan 2026 19:09:04 +0100 Subject: [PATCH 11/15] Remove general exception catching --- src/wp-includes/html-api/class-wp-html-processor.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/wp-includes/html-api/class-wp-html-processor.php b/src/wp-includes/html-api/class-wp-html-processor.php index e2ee09eb0883d..15346a7a82faa 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -1156,12 +1156,6 @@ public function step( $node_to_process = self::PROCESS_NEXT_NODE ): bool { * otherwise might involve messier calling and return conventions. */ return false; - } catch ( Exception $e ) { - if ( self::ERROR_EXCEEDED_MAX_BOOKMARKS === $this->last_error ) { - return false; - } - // Rethrow any other exceptions for higher-level handling. - throw $e; } } From 1681fed0bf9fbd31478b1c701837d763ed8e2943 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 29 Jan 2026 19:17:14 +0100 Subject: [PATCH 12/15] Avoid throwing unsupported exception when tokens exceeded --- .../html-api/class-wp-html-processor.php | 36 ++++++++++++------- .../tests/html-api/wpHtmlProcessor.php | 3 ++ 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/wp-includes/html-api/class-wp-html-processor.php b/src/wp-includes/html-api/class-wp-html-processor.php index 15346a7a82faa..1de2cef57ccbe 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -989,8 +989,6 @@ public function expects_closer( ?WP_HTML_Token $node = null ): ?bool { * * @since 6.4.0 * - * @throws Exception When unable to allocate a bookmark for the next token in the input HTML document. - * * @see self::PROCESS_NEXT_NODE * @see self::REPROCESS_CURRENT_NODE * @@ -1605,7 +1603,9 @@ private function step_before_html(): bool { * > Switch the insertion mode to "before head", then reprocess the token. */ before_html_anything_else: - $this->insert_virtual_node( 'HTML' ); + if ( ! $this->insert_virtual_node( 'HTML' ) ) { + return false; + } $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_BEFORE_HEAD; return $this->step( self::REPROCESS_CURRENT_NODE ); } @@ -1702,7 +1702,11 @@ private function step_before_head(): bool { * > Insert an HTML element for a "head" start tag token with no attributes. */ before_head_anything_else: - $this->state->head_element = $this->insert_virtual_node( 'HEAD' ); + $head_element = $this->insert_virtual_node( 'HEAD' ); + if ( ! $head_element ) { + return false; + } + $this->state->head_element = $head_element; $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_HEAD; return $this->step( self::REPROCESS_CURRENT_NODE ); } @@ -2171,7 +2175,9 @@ private function step_after_head(): bool { * > Insert an HTML element for a "body" start tag token with no attributes. */ after_head_anything_else: - $this->insert_virtual_node( 'BODY' ); + if ( ! $this->insert_virtual_node( 'BODY' ) ) { + return false; + } $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_BODY; return $this->step( self::REPROCESS_CURRENT_NODE ); } @@ -3323,7 +3329,9 @@ private function step_in_table(): bool { * > Insert an HTML element for a "colgroup" start tag token with no attributes, * > then switch the insertion mode to "in column group". */ - $this->insert_virtual_node( 'COLGROUP' ); + if ( ! $this->insert_virtual_node( 'COLGROUP' ) ) { + return false; + } $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_COLUMN_GROUP; return $this->step( self::REPROCESS_CURRENT_NODE ); @@ -3349,7 +3357,9 @@ private function step_in_table(): bool { * > Insert an HTML element for a "tbody" start tag token with no attributes, * > then switch the insertion mode to "in table body". */ - $this->insert_virtual_node( 'TBODY' ); + if ( ! $this->insert_virtual_node( 'TBODY' ) ) { + return false; + } $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE_BODY; return $this->step( self::REPROCESS_CURRENT_NODE ); @@ -3704,7 +3714,9 @@ private function step_in_table_body(): bool { case '+TD': // @todo Indicate a parse error once it's possible. $this->state->stack_of_open_elements->clear_to_table_body_context(); - $this->insert_virtual_node( 'TR' ); + if ( ! $this->insert_virtual_node( 'TR' ) ) { + return false; + } $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_ROW; return $this->step( self::REPROCESS_CURRENT_NODE ); @@ -6290,18 +6302,16 @@ private function insert_foreign_element( WP_HTML_Token $token, bool $only_add_to * * @since 6.7.0 * - * @throws WP_HTML_Unsupported_Exception When unable to allocate a bookmark for the next token in the input HTML document. - * * @param string $token_name Name of token to create and insert into the stack of open elements. * @param string|null $bookmark_name Optional. Name to give bookmark for created virtual node. * Defaults to auto-creating a bookmark name. - * @return WP_HTML_Token Newly-created virtual token. + * @return WP_HTML_Token|false Newly-created virtual token or false on failure. */ - private function insert_virtual_node( $token_name, $bookmark_name = null ): WP_HTML_Token { + private function insert_virtual_node( $token_name, $bookmark_name = null ): WP_HTML_Token|bool { $here = $this->bookmarks[ $this->state->current_token->bookmark_name ]; $name = $bookmark_name ?? $this->bookmark_token(); if ( false === $name ) { - $this->bail( 'Unable to insert virtual node, bookmarks exhausted.' ); + return false; } $this->bookmarks[ $name ] = new WP_HTML_Span( $here->start, 0 ); diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php index 5391063a1184e..23cc78e64652c 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php @@ -1099,6 +1099,7 @@ public function test_deep_nesting_fails_process_without_error() { ++$reached_tokens; } $this->assertSame( WP_HTML_Processor::MAX_BOOKMARKS, $reached_tokens ); + $this->assertSame( 'exceeded-max-bookmarks', $processor->get_last_error() ); } /** @@ -1135,5 +1136,7 @@ public function test_deep_nesting_fails_processing_virtual_tokens_without_error( */ $this->assertGreaterThanOrEqual( WP_HTML_Processor::MAX_BOOKMARKS - 1, $reached_tokens ); $this->assertLessThanOrEqual( WP_HTML_Processor::MAX_BOOKMARKS + 1, $reached_tokens ); + + $this->assertSame( 'exceeded-max-bookmarks', $processor->get_last_error() ); } } From aefc5bf126f5ea782462c1cf4b568bfa47826445 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 29 Jan 2026 19:25:21 +0100 Subject: [PATCH 13/15] Remove unsupported union return type --- src/wp-includes/html-api/class-wp-html-processor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/html-api/class-wp-html-processor.php b/src/wp-includes/html-api/class-wp-html-processor.php index 1de2cef57ccbe..aa6c86c1195ea 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -6307,7 +6307,7 @@ private function insert_foreign_element( WP_HTML_Token $token, bool $only_add_to * Defaults to auto-creating a bookmark name. * @return WP_HTML_Token|false Newly-created virtual token or false on failure. */ - private function insert_virtual_node( $token_name, $bookmark_name = null ): WP_HTML_Token|bool { + private function insert_virtual_node( $token_name, $bookmark_name = null ) { $here = $this->bookmarks[ $this->state->current_token->bookmark_name ]; $name = $bookmark_name ?? $this->bookmark_token(); if ( false === $name ) { From 6d1f86078e4552be415295e1be479c873dafc85c Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Fri, 30 Jan 2026 16:18:34 +0100 Subject: [PATCH 14/15] =?UTF-8?q?Use=20arrow=20functions=20=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Weston Ruter --- tests/phpunit/tests/html-api/wpHtmlProcessor.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php index 23cc78e64652c..b8227fc823f07 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php @@ -1092,9 +1092,7 @@ public function test_deep_nesting_fails_process_without_error() { $processor = WP_HTML_Processor::create_fragment( $html ); // The fragment parser starts with a few context tokens already bookmarked. - $reached_tokens = ( function () { - return count( $this->bookmarks ); - } )->call( $processor ); + $reached_tokens = ( fn() => count( $this->bookmarks ) )->call( $processor ); while ( $processor->next_token() ) { ++$reached_tokens; } @@ -1112,9 +1110,7 @@ public function test_deep_nesting_fails_processing_virtual_tokens_without_error( $processor = WP_HTML_Processor::create_fragment( $html ); // The fragment parser starts with a few context tokens already bookmarked. - $reached_tokens = ( function () { - return count( $this->bookmarks ); - } )->call( $processor ); + $reached_tokens = ( fn() => count( $this->bookmarks ) )->call( $processor ); while ( $processor->next_token() ) { ++$reached_tokens; } From cbab9c1892cfada96f6ff93aa678ff7e6ac01254 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Fri, 30 Jan 2026 18:23:06 +0100 Subject: [PATCH 15/15] Add assertion message and use class constant --- tests/phpunit/tests/html-api/wpHtmlProcessor.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php index b8227fc823f07..32ed8b92b7fdb 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php @@ -1097,7 +1097,11 @@ public function test_deep_nesting_fails_process_without_error() { ++$reached_tokens; } $this->assertSame( WP_HTML_Processor::MAX_BOOKMARKS, $reached_tokens ); - $this->assertSame( 'exceeded-max-bookmarks', $processor->get_last_error() ); + $this->assertSame( + WP_HTML_Processor::ERROR_EXCEEDED_MAX_BOOKMARKS, + $processor->get_last_error(), + 'Failed to report exceeded-max-bookmarks error.' + ); } /** @@ -1132,7 +1136,10 @@ public function test_deep_nesting_fails_processing_virtual_tokens_without_error( */ $this->assertGreaterThanOrEqual( WP_HTML_Processor::MAX_BOOKMARKS - 1, $reached_tokens ); $this->assertLessThanOrEqual( WP_HTML_Processor::MAX_BOOKMARKS + 1, $reached_tokens ); - - $this->assertSame( 'exceeded-max-bookmarks', $processor->get_last_error() ); + $this->assertSame( + WP_HTML_Processor::ERROR_EXCEEDED_MAX_BOOKMARKS, + $processor->get_last_error(), + 'Failed to report exceeded-max-bookmarks error.' + ); } }