From 20fabdc165bb68783f089cf15b308c3343136d8b Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Wed, 14 Aug 2024 15:49:20 -0700 Subject: [PATCH 1/4] HTML API: Add new is_self_contained() method to Tag Processor. This new method will help calling code trying to determine whether or not to expect to find a closing tag, since the Tag Processor consumes the entire element (including the closing tag) when it encounters one. --- .../html-api/class-wp-html-tag-processor.php | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/wp-includes/html-api/class-wp-html-tag-processor.php b/src/wp-includes/html-api/class-wp-html-tag-processor.php index e6e704e71cd0f..10940ace54958 100644 --- a/src/wp-includes/html-api/class-wp-html-tag-processor.php +++ b/src/wp-includes/html-api/class-wp-html-tag-processor.php @@ -3179,6 +3179,32 @@ public function has_self_closing_flag(): bool { return '/' === $this->html[ $this->token_starts_at + $this->token_length - 2 ]; } + /** + * Indicates if the currently-matched token is a self-contained element, + * i.e. a SCRIPT, STYLE, TEXTAREA, or TITLE element etc… + * + * When the HTML API finds one of these elements it will consume the entire + * content up to and including the closing tag. They act like void tags, even + * though they expect closing tags in input HTML. They are treated this way + * because they cannot contain other HTML tags inside of them; their input is + * always text content only, with or without replacement of character + * references depending on which element it is. + * + * To get the contents of these elements, call {@see static::get_modifiable_text}. + * + * @since 6.8.0 + * + * @return bool Whether the currently-matched token is a self-contained element. + */ + public function is_self_contained(): bool { + return ( + self::STATE_MATCHED_TAG === $this->parser_state && + ! $this->is_tag_closer() && + 'html' === $this->get_namespace() && + in_array( $this->get_tag(), array( 'IFRAME', 'NOEMBED', 'NOFRAMES', 'SCRIPT', 'STYLE', 'TEXTAREA', 'TITLE', 'XMP' ), true ) + ); + } + /** * Indicates if the current tag token is a tag closer. * From 783c563973bde394887185188c29e901c648fa10 Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Wed, 14 Aug 2024 16:12:21 -0700 Subject: [PATCH 2/4] Wrong WP version --- src/wp-includes/html-api/class-wp-html-tag-processor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/html-api/class-wp-html-tag-processor.php b/src/wp-includes/html-api/class-wp-html-tag-processor.php index 10940ace54958..d80e06b1e8e3b 100644 --- a/src/wp-includes/html-api/class-wp-html-tag-processor.php +++ b/src/wp-includes/html-api/class-wp-html-tag-processor.php @@ -3192,7 +3192,7 @@ public function has_self_closing_flag(): bool { * * To get the contents of these elements, call {@see static::get_modifiable_text}. * - * @since 6.8.0 + * @since 6.7.0 * * @return bool Whether the currently-matched token is a self-contained element. */ From 67a0ad0f077530b77b91558d69c2986d59f5fd90 Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Wed, 21 Aug 2024 10:11:54 -0700 Subject: [PATCH 3/4] Rename method to is_self_contained_tag(). --- src/wp-includes/html-api/class-wp-html-tag-processor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/html-api/class-wp-html-tag-processor.php b/src/wp-includes/html-api/class-wp-html-tag-processor.php index d80e06b1e8e3b..b6f8948c0fded 100644 --- a/src/wp-includes/html-api/class-wp-html-tag-processor.php +++ b/src/wp-includes/html-api/class-wp-html-tag-processor.php @@ -3196,7 +3196,7 @@ public function has_self_closing_flag(): bool { * * @return bool Whether the currently-matched token is a self-contained element. */ - public function is_self_contained(): bool { + public function is_self_contained_tag(): bool { return ( self::STATE_MATCHED_TAG === $this->parser_state && ! $this->is_tag_closer() && From f7b17a29ab4745323ac33dd2c0d027856193e68a Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Mon, 26 Aug 2024 21:18:40 -0500 Subject: [PATCH 4/4] Use new method in HTML Processor, drop requirement of being a tag opener. --- src/wp-includes/html-api/class-wp-html-processor.php | 2 +- src/wp-includes/html-api/class-wp-html-tag-processor.php | 1 - 2 files changed, 1 insertion(+), 2 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 168b8ace4c394..302b524e96902 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -800,7 +800,7 @@ public function expects_closer( WP_HTML_Token $node = null ): ?bool { // Void elements. self::is_void( $token_name ) || // Special atomic elements. - ( 'html' === $token_namespace && in_array( $token_name, array( 'IFRAME', 'NOEMBED', 'NOFRAMES', 'SCRIPT', 'STYLE', 'TEXTAREA', 'TITLE', 'XMP' ), true ) ) || + parent::is_self_contained_tag() || // Self-closing elements in foreign content. ( 'html' !== $token_namespace && $token_has_self_closing ) ); diff --git a/src/wp-includes/html-api/class-wp-html-tag-processor.php b/src/wp-includes/html-api/class-wp-html-tag-processor.php index acdbf49892cd1..6be123fdc3774 100644 --- a/src/wp-includes/html-api/class-wp-html-tag-processor.php +++ b/src/wp-includes/html-api/class-wp-html-tag-processor.php @@ -3199,7 +3199,6 @@ public function has_self_closing_flag(): bool { public function is_self_contained_tag(): bool { return ( self::STATE_MATCHED_TAG === $this->parser_state && - ! $this->is_tag_closer() && 'html' === $this->get_namespace() && in_array( $this->get_tag(), array( 'IFRAME', 'NOEMBED', 'NOFRAMES', 'SCRIPT', 'STYLE', 'TEXTAREA', 'TITLE', 'XMP' ), true ) );