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.',