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 cb581fac3988f..bca44cbb670ea 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -256,6 +256,16 @@ class WP_HTML_Processor extends WP_HTML_Tag_Processor { */ private $context_node = null; + /** + * @var WP_HTML_Token[] + */ + private $after_body_comments = array(); + + /** + * @var WP_HTML_Token[] + */ + private $after_after_body_comments = array(); + /* * Public Interface Functions */ @@ -639,12 +649,34 @@ public function next_token(): bool { // Process the next event on the queue. $this->current_element = array_shift( $this->element_queue ); if ( ! isset( $this->current_element ) ) { - // There are no tokens left, so close all remaining open elements. + // The document has been fully processed. Perform final actions. + + // Close out the body: + if ( $this->state->stack_of_open_elements->contains( 'BODY' ) ) { + $this->state->stack_of_open_elements->pop_until( 'BODY' ); + } + + // Deal with after body comments: + foreach ( $this->after_body_comments as $token ) { + $this->insert_html_element( $token ); + } + $this->after_body_comments = array(); + + // Close out everything on the stack of open elements: while ( $this->state->stack_of_open_elements->pop() ) { continue; } + // Deal with after after body comments: + foreach ( $this->after_after_body_comments as $token ) { + $this->insert_html_element( $token ); + } + $this->after_after_body_comments = array(); - return empty( $this->element_queue ) ? false : $this->next_token(); + if ( ! empty( $this->element_queue ) ) { + return $this->next_token(); + } + + return false; } $is_pop = WP_HTML_Stack_Event::POP === $this->current_element->operation; @@ -868,6 +900,9 @@ public function step( $node_to_process = self::PROCESS_NEXT_NODE ): bool { $this->has_self_closing_flag(), $this->release_internal_bookmark_on_destruct ); + if ( '#comment' === $token_name ) { + $this->state->current_token->comment_type = $this->get_comment_type(); + } } $parse_in_current_insertion_mode = ( @@ -3964,8 +3999,8 @@ private function step_after_body(): bool { case '#comment': case '#funky-comment': case '#presumptuous-tag': - $this->bail( 'Content outside of BODY is unsupported.' ); - break; + $this->after_body_comments[] = $this->state->current_token; + return $this->step(); /* * > A DOCTYPE token @@ -4040,7 +4075,7 @@ private function step_in_frameset(): bool { if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) { return $this->step_in_body(); } - $this->bail( 'Non-whitespace characters cannot be handled in frameset.' ); + goto in_frameset_anything_else; break; /* @@ -4120,6 +4155,7 @@ private function step_in_frameset(): bool { return $this->step_in_head(); } + in_frameset_anything_else: // Parse error: ignore the token. return $this->step(); } @@ -4159,7 +4195,7 @@ private function step_after_frameset(): bool { if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) { return $this->step_in_body(); } - $this->bail( 'Non-whitespace characters cannot be handled in after frameset' ); + goto after_frameset_anything_else; break; /* @@ -4198,6 +4234,7 @@ private function step_after_frameset(): bool { return $this->step_in_head(); } + after_frameset_anything_else: // Parse error: ignore the token. return $this->step(); } @@ -4230,8 +4267,8 @@ private function step_after_after_body(): bool { case '#comment': case '#funky-comment': case '#presumptuous-tag': - $this->bail( 'Content outside of HTML is unsupported.' ); - break; + $this->after_after_body_comments[] = $this->state->current_token; + return $this->step(); /* * > A DOCTYPE token @@ -4293,8 +4330,8 @@ private function step_after_after_frameset(): bool { case '#comment': case '#funky-comment': case '#presumptuous-tag': - $this->bail( 'Content outside of HTML is unsupported.' ); - break; + $this->insert_html_element( $this->state->current_token ); + return true; /* * > A DOCTYPE token @@ -4319,7 +4356,7 @@ private function step_after_after_frameset(): bool { if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) { return $this->step_in_body(); } - $this->bail( 'Non-whitespace characters cannot be handled in after after frameset.' ); + goto after_after_frameset_anything_else; break; /* @@ -4329,6 +4366,7 @@ private function step_after_after_frameset(): bool { return $this->step_in_head(); } + after_after_frameset_anything_else: // Parse error: ignore the token. return $this->step(); } diff --git a/src/wp-includes/html-api/class-wp-html-token.php b/src/wp-includes/html-api/class-wp-html-token.php index d5e51ac29007f..4bfa9eb9e6ada 100644 --- a/src/wp-includes/html-api/class-wp-html-token.php +++ b/src/wp-includes/html-api/class-wp-html-token.php @@ -46,6 +46,17 @@ class WP_HTML_Token { */ public $node_name = null; + /** + * Comment type + * + * @since 6.7.0 + * + * @see WP_HTML_Processor::get_comment_type() + * + * @var string|null + */ + public $comment_type = null; + /** * Whether node contains the self-closing flag. * diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessorHtml5lib.php b/tests/phpunit/tests/html-api/wpHtmlProcessorHtml5lib.php index 54d60f8c78a66..5267f537ac778 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessorHtml5lib.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessorHtml5lib.php @@ -33,6 +33,8 @@ class Tests_HtmlApi_Html5lib extends WP_UnitTestCase { 'tests14/line0055' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.', 'tests19/line0488' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.', 'tests19/line0500' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.', + 'tests19/line0488' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.', + 'tests19/line0500' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.', 'tests19/line1079' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.', 'tests2/line0207' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.', 'tests2/line0686' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',