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 0b3dab1ad2ae4..ec8855d472b78 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 @@ -1743,6 +1743,31 @@ public function get_tag() { return strtoupper( $tag_name ); } + /** + * Indicates if the currently matched tag contains the self-closing flag. + * + * No HTML elements ought to have the self-closing flag and for those, the self-closing + * flag will be ignored. For void elements this is benign because they "self close" + * automatically. For non-void HTML elements though problems will appear if someone + * intends to use a self-closing element in place of that element with an empty body. + * For HTML foreign elements and custom elements the self-closing flag determines if + * they self-close or not. + * + * This function does not determine if a tag is self-closing, + * but only if the self-closing flag is present in the syntax. + * + * @since 6.3.0 + * + * @return bool Whether the currently matched tag contains the self-closing flag. + */ + public function has_self_closing_flag() { + if ( ! $this->tag_name_starts_at ) { + return false; + } + + return '/' === $this->html[ $this->tag_ends_at - 1 ]; + } + /** * Indicates if the current tag token is a tag closer. * diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index d006b3294c9ea..f938a14441a58 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -51,6 +51,54 @@ public function test_get_tag_returns_open_tag_name() { $this->assertSame( 'DIV', $p->get_tag(), 'Accessing an existing tag name did not return "div"' ); } + /** + * @ticket 58009 TICKET + * + * @covers WP_HTML_Tag_Processor::has_self_closing_flag() + * + * @dataProvider data_has_self_closing_flag + * + * @param string $html input HTML whose first tag might contain the self-closing flag `/`. + * @param bool $flag_is_set whether the input HTML's first tag contains the self-closing flag. + */ + public function test_has_self_closing_flag_matches_input_html( $html, $flag_is_set ) { + $p = new WP_HTML_Tag_Processor( $html ); + $p->next_tag( array( 'tag_closers' => 'visit' ) ); + + if ( $flag_is_set ) { + $this->assertTrue( $p->has_self_closing_flag(), 'Did not find the self-closing tag when it was present.' ); + } else { + $this->assertFalse( $p->has_self_closing_flag(), 'Found the self-closing tag when it was absent.' ); + } + } + + /** + * Data provider. HTML tags which might have a self-closing flag, and an indicator if they do. + * + * @return array[] + */ + public function data_has_self_closing_flag() { + return array( + // These should not have a self-closer, and will leave an element un-closed if it's assumed they are self-closing. + 'Self-closing flag on non-void HTML element' => array( '
', true ), + 'No self-closing flag on non-void HTML element' => array( '