diff --git a/wp-includes/html-api/class-wp-html-tag-processor.php b/wp-includes/html-api/class-wp-html-tag-processor.php
index 31352d2e88..d4223a3b9a 100644
--- a/wp-includes/html-api/class-wp-html-tag-processor.php
+++ b/wp-includes/html-api/class-wp-html-tag-processor.php
@@ -971,6 +971,7 @@ class WP_HTML_Tag_Processor {
* closing `>`; these are left for other methods.
*
* @since 6.2.0
+ * @since 6.2.1 Support abruptly-closed comments, invalid-tag-closer-comments, and empty elements.
*
* @return bool Whether a tag was found before the end of the document.
*/
@@ -1039,13 +1040,42 @@ class WP_HTML_Tag_Processor {
'-' === $html[ $at + 2 ] &&
'-' === $html[ $at + 3 ]
) {
- $closer_at = strpos( $html, '-->', $at + 4 );
- if ( false === $closer_at ) {
+ $closer_at = $at + 4;
+ // If it's not possible to close the comment then there is nothing more to scan.
+ if ( strlen( $html ) <= $closer_at ) {
return false;
}
- $at = $closer_at + 3;
- continue;
+ // Abruptly-closed empty comments are a sequence of dashes followed by `>`.
+ $span_of_dashes = strspn( $html, '-', $closer_at );
+ if ( '>' === $html[ $closer_at + $span_of_dashes ] ) {
+ $at = $closer_at + $span_of_dashes + 1;
+ continue;
+ }
+
+ /*
+ * Comments may be closed by either a --> or an invalid --!>.
+ * The first occurrence closes the comment.
+ *
+ * See https://html.spec.whatwg.org/#parse-error-incorrectly-closed-comment
+ */
+ $closer_at--; // Pre-increment inside condition below reduces risk of accidental infinite looping.
+ while ( ++$closer_at < strlen( $html ) ) {
+ $closer_at = strpos( $html, '--', $closer_at );
+ if ( false === $closer_at ) {
+ return false;
+ }
+
+ if ( $closer_at + 2 < strlen( $html ) && '>' === $html[ $closer_at + 2 ] ) {
+ $at = $closer_at + 3;
+ continue 2;
+ }
+
+ if ( $closer_at + 3 < strlen( $html ) && '!' === $html[ $closer_at + 2 ] && '>' === $html[ $closer_at + 3 ] ) {
+ $at = $closer_at + 4;
+ continue 2;
+ }
+ }
}
/*
@@ -1104,9 +1134,19 @@ class WP_HTML_Tag_Processor {
continue;
}
+ /*
+ * > is a missing end tag name, which is ignored.
+ *
+ * See https://html.spec.whatwg.org/#parse-error-missing-end-tag-name
+ */
+ if ( '>' === $html[ $at + 1 ] ) {
+ $at++;
+ continue;
+ }
+
/*
* transitions to a bogus comment state – skip to the nearest >
- * https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state
+ * See https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state
*/
if ( '?' === $html[ $at + 1 ] ) {
$closer_at = strpos( $html, '>', $at + 2 );
@@ -1118,6 +1158,22 @@ class WP_HTML_Tag_Processor {
continue;
}
+ /*
+ * If a non-alpha starts the tag name in a tag closer it's a comment.
+ * Find the first `>`, which closes the comment.
+ *
+ * See https://html.spec.whatwg.org/#parse-error-invalid-first-character-of-tag-name
+ */
+ if ( $this->is_closing_tag ) {
+ $closer_at = strpos( $html, '>', $at + 3 );
+ if ( false === $closer_at ) {
+ return false;
+ }
+
+ $at = $closer_at + 1;
+ continue;
+ }
+
++$at;
}
diff --git a/wp-includes/version.php b/wp-includes/version.php
index 3973b45076..590ff7a391 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
-$wp_version = '6.3-alpha-55666';
+$wp_version = '6.3-alpha-55667';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.