@@ -627,6 +627,15 @@ class WP_HTML_Tag_Processor {
627627 */
628628 private $ token_length ;
629629
630+ /**
631+ * Whether the current tag token has the self-closing flag.
632+ *
633+ * @since 6.9.0
634+ *
635+ * @var bool
636+ */
637+ private $ self_closing_flag = false ;
638+
630639 /**
631640 * Byte offset in input document where current tag name starts.
632641 *
@@ -1079,6 +1088,7 @@ private function base_class_next_token(): bool {
10791088 $ tag_name_starts_at = $ this ->tag_name_starts_at ;
10801089 $ tag_name_length = $ this ->tag_name_length ;
10811090 $ tag_ends_at = $ this ->token_starts_at + $ this ->token_length ;
1091+ $ self_closing_flag = $ this ->self_closing_flag ;
10821092 $ attributes = $ this ->attributes ;
10831093 $ duplicate_attributes = $ this ->duplicate_attributes ;
10841094
@@ -1136,6 +1146,7 @@ private function base_class_next_token(): bool {
11361146 $ this ->text_length = $ this ->tag_name_starts_at - $ this ->text_starts_at ;
11371147 $ this ->tag_name_starts_at = $ tag_name_starts_at ;
11381148 $ this ->tag_name_length = $ tag_name_length ;
1149+ $ this ->self_closing_flag = $ self_closing_flag ;
11391150 $ this ->attributes = $ attributes ;
11401151 $ this ->duplicate_attributes = $ duplicate_attributes ;
11411152
@@ -2143,7 +2154,19 @@ private function parse_next_attribute(): bool {
21432154 $ doc_length = strlen ( $ this ->html );
21442155
21452156 // Skip whitespace and slashes.
2146- $ this ->bytes_already_parsed += strspn ( $ this ->html , " \t\f\r\n/ " , $ this ->bytes_already_parsed );
2157+ $ skipped_start = $ this ->bytes_already_parsed ;
2158+ $ this ->bytes_already_parsed += strspn ( $ this ->html , " \t\f\r\n/ " , $ skipped_start );
2159+
2160+ // A slash inside an unquoted attribute value will not have been skipped here.
2161+ if (
2162+ $ this ->bytes_already_parsed < $ doc_length &&
2163+ $ this ->bytes_already_parsed > $ skipped_start &&
2164+ '/ ' === $ this ->html [ $ this ->bytes_already_parsed - 1 ] &&
2165+ '> ' === $ this ->html [ $ this ->bytes_already_parsed ]
2166+ ) {
2167+ $ this ->self_closing_flag = true ;
2168+ }
2169+
21472170 if ( $ this ->bytes_already_parsed >= $ doc_length ) {
21482171 $ this ->parser_state = self ::STATE_INCOMPLETE_INPUT ;
21492172
@@ -2327,6 +2350,7 @@ private function after_tag(): void {
23272350
23282351 $ this ->token_starts_at = null ;
23292352 $ this ->token_length = null ;
2353+ $ this ->self_closing_flag = false ;
23302354 $ this ->tag_name_starts_at = null ;
23312355 $ this ->tag_name_length = null ;
23322356 $ this ->text_starts_at = 0 ;
@@ -3335,42 +3359,7 @@ public function has_self_closing_flag(): bool {
33353359 return false ;
33363360 }
33373361
3338- /*
3339- * The self-closing flag is the solidus at the _end_ of the tag, not the beginning.
3340- *
3341- * Example:
3342- *
3343- * <figure />
3344- * ^ this appears one character before the end of the closing ">".
3345- */
3346- $ self_closing_flag_at = $ this ->token_starts_at + $ this ->token_length - 2 ;
3347- if ( '/ ' !== $ this ->html [ $ self_closing_flag_at ] ) {
3348- return false ;
3349- }
3350-
3351- foreach ( $ this ->attributes as $ attribute ) {
3352- $ attribute_ends_at = $ attribute ->start + $ attribute ->length ;
3353- if (
3354- $ self_closing_flag_at >= $ attribute ->start &&
3355- $ self_closing_flag_at < $ attribute_ends_at
3356- ) {
3357- return false ;
3358- }
3359- }
3360-
3361- foreach ( $ this ->duplicate_attributes ?? array () as $ duplicate_attributes ) {
3362- foreach ( $ duplicate_attributes as $ attribute ) {
3363- $ attribute_ends_at = $ attribute ->start + $ attribute ->length ;
3364- if (
3365- $ self_closing_flag_at >= $ attribute ->start &&
3366- $ self_closing_flag_at < $ attribute_ends_at
3367- ) {
3368- return false ;
3369- }
3370- }
3371- }
3372-
3373- return true ;
3362+ return $ this ->self_closing_flag ;
33743363 }
33753364
33763365 /**
0 commit comments