From 38a7717b42b7089d6636097b749140f47b2766cb Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Sat, 13 Jan 2024 08:07:32 -0600 Subject: [PATCH 1/6] WIP: Add support for the rest of the common IN BODY tags. --- ...ass-wp-html-active-formatting-elements.php | 10 ++ .../html-api/class-wp-html-open-elements.php | 14 +- .../html-api/class-wp-html-processor.php | 122 +++++++++++++++--- .../tests/html-api/wpHtmlProcessor.php | 13 -- .../html-api/wpHtmlProcessorBreadcrumbs.php | 28 ++-- .../wpHtmlSupportRequiredOpenElements.php | 21 --- 6 files changed, 135 insertions(+), 73 deletions(-) diff --git a/src/wp-includes/html-api/class-wp-html-active-formatting-elements.php b/src/wp-includes/html-api/class-wp-html-active-formatting-elements.php index 9f7fee9076243..1d7bd8e54fc1f 100644 --- a/src/wp-includes/html-api/class-wp-html-active-formatting-elements.php +++ b/src/wp-includes/html-api/class-wp-html-active-formatting-elements.php @@ -86,6 +86,16 @@ public function current_node() { return $current_node ? $current_node : null; } + /** + * Inserts a marker at the end of the list of active formatting elements. + * + * @since 6.5.0 + */ + public function insert_marker() { + $marker = new WP_HTML_Token( null, 'marker', false ); + $this->push( $marker ); + } + /** * Pushes a node onto the stack of active formatting elements. * diff --git a/src/wp-includes/html-api/class-wp-html-open-elements.php b/src/wp-includes/html-api/class-wp-html-open-elements.php index 1234abcb9dfe4..ab40c0c09d669 100644 --- a/src/wp-includes/html-api/class-wp-html-open-elements.php +++ b/src/wp-includes/html-api/class-wp-html-open-elements.php @@ -150,14 +150,9 @@ public function has_element_in_scope( $tag_name ) { return $this->has_element_in_specific_scope( $tag_name, array( - - /* - * Because it's not currently possible to encounter - * one of the termination elements, they don't need - * to be listed here. If they were, they would be - * unreachable and only waste CPU cycles while - * scanning through HTML. - */ + 'APPLET', + 'MARQUEE', + 'OBJECT', ) ); } @@ -421,7 +416,10 @@ public function after_element_push( $item ) { * cases where the precalculated value needs to change. */ switch ( $item->node_name ) { + case 'APPLET': case 'BUTTON': + case 'MARQUEE': + case 'OBJECT': $this->has_p_in_button_scope = false; break; 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 cce26a60c5350..7d1c9f8bdf65f 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -516,7 +516,26 @@ public function step( $node_to_process = self::PROCESS_NEXT_NODE ) { * is provided in the opening tag, otherwise it expects a tag closer. */ $top_node = $this->state->stack_of_open_elements->current_node(); - if ( $top_node && self::is_void( $top_node->node_name ) ) { + if ( + $top_node && + ( + self::is_void( $top_node->node_name ) || + + // Special: Skips SCRIPT data in Tag Processor. + 'SCRIPT' === $top_node->node_name || + + // Special: Skips RCDATA data in Tag Processor. + 'TEXTAREA' === $top_node->node_name || + 'TITLE' === $top_node->node_name || + + // Special: Skips RAWTEXT data in Tag Processor. + 'IFRAME' === $top_node->node_name || + 'NOEMBED' === $top_node->node_name || + 'NOFRAMES' === $top_node->node_name || + 'STYLE' === $top_node->node_name || + 'XMP' === $top_node->node_name + ) + ) { $this->state->stack_of_open_elements->pop(); } @@ -688,6 +707,7 @@ private function step_in_body() { case '-MENU': case '-NAV': case '-OL': + case '-PRE': case '-SEARCH': case '-SECTION': case '-SUMMARY': @@ -732,6 +752,17 @@ private function step_in_body() { $this->insert_html_element( $this->state->current_token ); return true; + /* + * > A start tag whose tag name is one of: "pre", "listing" + */ + case '+PRE': + if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) { + $this->close_a_p_element(); + } + $this->insert_html_element( $this->state->current_token ); + $this->state->frameset_ok = false; + return true; + /* * > An end tag whose tag name is one of: "h1", "h2", "h3", "h4", "h5", "h6" */ @@ -934,12 +965,84 @@ private function step_in_body() { $this->run_adoption_agency_algorithm(); return true; + /* + * > A start tag whose tag name is one of: "applet", "marquee", "object" + */ + case '+APPLET': + case '+MARQUEE': + case '+OBJECT': + $this->reconstruct_active_formatting_elements(); + $this->insert_html_element( $this->state->current_token ); + $this->state->active_formatting_elements->insert_marker(); + $this->state->frameset_ok = false; + return true; + + /* + * > An end tag whose tag name is "br" + * + * This is supposed to create a BR element with no attributes, + * which the HTML Processor doesn't currently have a way to + * represent. + */ + case '-BR': + $this->last_error = self::ERROR_UNSUPPORTED; + throw new WP_HTML_Unsupported_Exception( 'Cannot process unexpecdted BR closer' ); + /* * > A start tag whose tag name is one of: "area", "br", "embed", "img", "keygen", "wbr" */ + case '+AREA': + case '+BR': + case '+EMBED': case '+IMG': + case '+WBR': $this->reconstruct_active_formatting_elements(); $this->insert_html_element( $this->state->current_token ); + $this->state->frameset_ok = false; + return true; + + /* + * > A start tag whose tag name is "hr" + */ + case '+HR': + if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) { + $this->close_a_p_element(); + } + $this->insert_html_element( $this->state->current_token ); + $this->state->frameset_ok = false; + return true; + + /* + * > A start tag whose tag name is "textarea" + */ + case '+TEXTAREA': + $this->insert_html_element( $this->state->current_token ); + $this->state->frameset_ok = false; + return true; + + /* + * > A start tag whose tag name is "xmp" + */ + case '+XMP': + if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) { + $this->close_a_p_element(); + } + $this->reconstruct_active_formatting_elements(); + $this->insert_html_element( $this->state->current_token ); + $this->state->frameset_ok = false; + return true; + + /* + * > A start tag whose tag name is "iframe" + */ + case '+IFRAME': + $this->state->frameset_ok = false; + return true; + + /* + * > A start tag whose tag name is "noembed" + */ + case '+NOEMBED': return true; } @@ -960,45 +1063,32 @@ private function step_in_body() { * @see https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inbody */ switch ( $tag_name ) { - case 'APPLET': case 'AREA': case 'BASE': case 'BASEFONT': case 'BGSOUND': case 'BODY': - case 'BR': case 'CAPTION': case 'COL': case 'COLGROUP': - case 'DD': - case 'DT': - case 'EMBED': case 'FORM': case 'FRAME': case 'FRAMESET': case 'HEAD': - case 'HR': case 'HTML': - case 'IFRAME': case 'INPUT': case 'KEYGEN': - case 'LI': case 'LINK': case 'LISTING': - case 'MARQUEE': case 'MATH': case 'META': case 'NOBR': - case 'NOEMBED': case 'NOFRAMES': case 'NOSCRIPT': - case 'OBJECT': - case 'OL': case 'OPTGROUP': case 'OPTION': case 'PARAM': case 'PLAINTEXT': - case 'PRE': case 'RB': case 'RP': case 'RT': @@ -1013,7 +1103,6 @@ private function step_in_body() { case 'TBODY': case 'TD': case 'TEMPLATE': - case 'TEXTAREA': case 'TFOOT': case 'TH': case 'THEAD': @@ -1021,8 +1110,6 @@ private function step_in_body() { case 'TR': case 'TRACK': case 'UL': - case 'WBR': - case 'XMP': $this->last_error = self::ERROR_UNSUPPORTED; throw new WP_HTML_Unsupported_Exception( "Cannot process {$tag_name} element." ); } @@ -1682,6 +1769,7 @@ public static function is_void( $tag_name ) { 'IMG' === $tag_name || 'INPUT' === $tag_name || 'LINK' === $tag_name || + 'KEYGEN' === $tag_name || 'META' === $tag_name || 'SOURCE' === $tag_name || 'TRACK' === $tag_name || diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php index d9f1357b5c66f..411b3a1ad7d27 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php @@ -158,41 +158,31 @@ public function test_step_in_body_fails_on_unsupported_tags( $tag_name ) { */ public function data_unsupported_special_in_body_tags() { return array( - 'APPLET' => array( 'APPLET' ), - 'AREA' => array( 'AREA' ), 'BASE' => array( 'BASE' ), 'BASEFONT' => array( 'BASEFONT' ), 'BGSOUND' => array( 'BGSOUND' ), 'BODY' => array( 'BODY' ), - 'BR' => array( 'BR' ), 'CAPTION' => array( 'CAPTION' ), 'COL' => array( 'COL' ), 'COLGROUP' => array( 'COLGROUP' ), - 'EMBED' => array( 'EMBED' ), 'FORM' => array( 'FORM' ), 'FRAME' => array( 'FRAME' ), 'FRAMESET' => array( 'FRAMESET' ), 'HEAD' => array( 'HEAD' ), - 'HR' => array( 'HR' ), 'HTML' => array( 'HTML' ), - 'IFRAME' => array( 'IFRAME' ), 'INPUT' => array( 'INPUT' ), 'KEYGEN' => array( 'KEYGEN' ), 'LINK' => array( 'LINK' ), 'LISTING' => array( 'LISTING' ), - 'MARQUEE' => array( 'MARQUEE' ), 'MATH' => array( 'MATH' ), 'META' => array( 'META' ), 'NOBR' => array( 'NOBR' ), - 'NOEMBED' => array( 'NOEMBED' ), 'NOFRAMES' => array( 'NOFRAMES' ), 'NOSCRIPT' => array( 'NOSCRIPT' ), - 'OBJECT' => array( 'OBJECT' ), 'OPTGROUP' => array( 'OPTGROUP' ), 'OPTION' => array( 'OPTION' ), 'PARAM' => array( 'PARAM' ), 'PLAINTEXT' => array( 'PLAINTEXT' ), - 'PRE' => array( 'PRE' ), 'RB' => array( 'RB' ), 'RP' => array( 'RP' ), 'RT' => array( 'RT' ), @@ -207,15 +197,12 @@ public function data_unsupported_special_in_body_tags() { 'TBODY' => array( 'TBODY' ), 'TD' => array( 'TD' ), 'TEMPLATE' => array( 'TEMPLATE' ), - 'TEXTAREA' => array( 'TEXTAREA' ), 'TFOOT' => array( 'TFOOT' ), 'TH' => array( 'TH' ), 'THEAD' => array( 'THEAD' ), 'TITLE' => array( 'TITLE' ), 'TR' => array( 'TR' ), 'TRACK' => array( 'TRACK' ), - 'WBR' => array( 'WBR' ), - 'XMP' => array( 'XMP' ), ); } } diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php b/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php index 15d38d6f70c6c..cbb45977f2256 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php @@ -40,6 +40,8 @@ public function data_single_tag_of_supported_elements() { 'ABBR', 'ACRONYM', // Neutralized. 'ADDRESS', + 'APPLET', // Deprecated. + 'AREA', 'ARTICLE', 'ASIDE', 'AUDIO', @@ -48,6 +50,7 @@ public function data_single_tag_of_supported_elements() { 'BDO', 'BIG', 'BLINK', // Deprecated. + 'BR', 'BUTTON', 'CANVAS', 'CENTER', // Neutralized. @@ -65,6 +68,7 @@ public function data_single_tag_of_supported_elements() { 'DL', 'DT', 'EM', + 'EMBED', 'FIELDSET', 'FIGCAPTION', 'FIGURE', @@ -78,26 +82,30 @@ public function data_single_tag_of_supported_elements() { 'H6', 'HEADER', 'HGROUP', + 'HR', 'I', 'IMG', 'INS', - 'LI', 'ISINDEX', // Deprecated + 'LI', 'KBD', 'LABEL', 'LEGEND', 'MAIN', 'MAP', 'MARK', + 'MARQUEE', // Deprecated. 'MENU', 'METER', 'MULTICOL', // Deprecated 'NAV', 'NEXTID', // Deprecated + 'OBJECT', 'OL', 'OUTPUT', 'P', 'PICTURE', + 'PRE', 'PROGRESS', 'Q', 'RUBY', @@ -119,6 +127,7 @@ public function data_single_tag_of_supported_elements() { 'UL', 'VAR', 'VIDEO', + 'WBR', ); $data = array(); @@ -126,7 +135,11 @@ public function data_single_tag_of_supported_elements() { $data[ $tag_name ] = array( "<{$tag_name}>", $tag_name ); } + $data['IFRAME'] = array( '', 'IFRAME' ); $data['IMAGE (treated as an IMG)'] = array( '', 'IMG' ); + $data['NOEMBED'] = array( '', 'NOEMBED' ); // Neutralized. + $data['TEXTAREA'] = array( '', 'TEXTAREA' ); + $data['XMP'] = array( '', 'XMP' ); // Deprecated, use PRE instead. return $data; } @@ -161,39 +174,29 @@ public function test_fails_when_encountering_unsupported_tag( $html ) { */ public function data_unsupported_elements() { $unsupported_elements = array( - 'APPLET', // Deprecated. - 'AREA', 'BASE', 'BGSOUND', // Deprecated; self-closing if self-closing flag provided, otherwise normal. 'BODY', - 'BR', 'CAPTION', 'COL', 'COLGROUP', - 'EMBED', 'FORM', 'FRAME', 'FRAMESET', 'HEAD', - 'HR', 'HTML', - 'IFRAME', 'INPUT', 'KEYGEN', // Deprecated; void. 'LINK', 'LISTING', // Deprecated, use PRE instead. - 'MARQUEE', // Deprecated. 'MATH', 'META', 'NOBR', // Neutralized. - 'NOEMBED', // Neutralized. 'NOFRAMES', // Neutralized. 'NOSCRIPT', - 'OBJECT', 'OPTGROUP', 'OPTION', 'PLAINTEXT', // Neutralized. - 'PRE', 'RB', // Neutralized. 'RP', 'RT', @@ -207,15 +210,12 @@ public function data_unsupported_elements() { 'TBODY', 'TD', 'TEMPLATE', - 'TEXTAREA', 'TFOOT', 'TH', 'THEAD', 'TITLE', 'TR', 'TRACK', - 'WBR', - 'XMP', // Deprecated, use PRE instead. ); $data = array(); diff --git a/tests/phpunit/tests/html-api/wpHtmlSupportRequiredOpenElements.php b/tests/phpunit/tests/html-api/wpHtmlSupportRequiredOpenElements.php index 0a05629e024bd..1bb36647c98b1 100644 --- a/tests/phpunit/tests/html-api/wpHtmlSupportRequiredOpenElements.php +++ b/tests/phpunit/tests/html-api/wpHtmlSupportRequiredOpenElements.php @@ -62,14 +62,11 @@ private function ensure_support_is_added_everywhere( $tag_name ) { */ public function test_has_element_in_scope_needs_support() { // These elements impact all scopes. - $this->ensure_support_is_added_everywhere( 'APPLET' ); $this->ensure_support_is_added_everywhere( 'CAPTION' ); $this->ensure_support_is_added_everywhere( 'HTML' ); $this->ensure_support_is_added_everywhere( 'TABLE' ); $this->ensure_support_is_added_everywhere( 'TD' ); $this->ensure_support_is_added_everywhere( 'TH' ); - $this->ensure_support_is_added_everywhere( 'MARQUEE' ); - $this->ensure_support_is_added_everywhere( 'OBJECT' ); $this->ensure_support_is_added_everywhere( 'TEMPLATE' ); // MathML Elements: MI, MO, MN, MS, MTEXT, ANNOTATION-XML. @@ -100,14 +97,11 @@ public function test_has_element_in_scope_needs_support() { */ public function test_has_element_in_list_item_scope_needs_support() { // These elements impact all scopes. - $this->ensure_support_is_added_everywhere( 'APPLET' ); $this->ensure_support_is_added_everywhere( 'CAPTION' ); $this->ensure_support_is_added_everywhere( 'HTML' ); $this->ensure_support_is_added_everywhere( 'TABLE' ); $this->ensure_support_is_added_everywhere( 'TD' ); $this->ensure_support_is_added_everywhere( 'TH' ); - $this->ensure_support_is_added_everywhere( 'MARQUEE' ); - $this->ensure_support_is_added_everywhere( 'OBJECT' ); $this->ensure_support_is_added_everywhere( 'TEMPLATE' ); // MathML Elements: MI, MO, MN, MS, MTEXT, ANNOTATION-XML. @@ -134,14 +128,11 @@ public function test_has_element_in_list_item_scope_needs_support() { */ public function test_has_element_in_button_scope_needs_support() { // These elements impact all scopes. - $this->ensure_support_is_added_everywhere( 'APPLET' ); $this->ensure_support_is_added_everywhere( 'CAPTION' ); $this->ensure_support_is_added_everywhere( 'HTML' ); $this->ensure_support_is_added_everywhere( 'TABLE' ); $this->ensure_support_is_added_everywhere( 'TD' ); $this->ensure_support_is_added_everywhere( 'TH' ); - $this->ensure_support_is_added_everywhere( 'MARQUEE' ); - $this->ensure_support_is_added_everywhere( 'OBJECT' ); $this->ensure_support_is_added_everywhere( 'TEMPLATE' ); // MathML Elements: MI, MO, MN, MS, MTEXT, ANNOTATION-XML. @@ -169,14 +160,11 @@ public function test_has_element_in_button_scope_needs_support() { */ public function test_after_element_pop_must_maintain_p_in_button_scope_flag() { // These elements impact all scopes. - $this->ensure_support_is_added_everywhere( 'APPLET' ); $this->ensure_support_is_added_everywhere( 'CAPTION' ); $this->ensure_support_is_added_everywhere( 'HTML' ); $this->ensure_support_is_added_everywhere( 'TABLE' ); $this->ensure_support_is_added_everywhere( 'TD' ); $this->ensure_support_is_added_everywhere( 'TH' ); - $this->ensure_support_is_added_everywhere( 'MARQUEE' ); - $this->ensure_support_is_added_everywhere( 'OBJECT' ); $this->ensure_support_is_added_everywhere( 'TEMPLATE' ); // MathML Elements: MI, MO, MN, MS, MTEXT, ANNOTATION-XML. @@ -204,14 +192,11 @@ public function test_after_element_pop_must_maintain_p_in_button_scope_flag() { */ public function test_after_element_push_must_maintain_p_in_button_scope_flag() { // These elements impact all scopes. - $this->ensure_support_is_added_everywhere( 'APPLET' ); $this->ensure_support_is_added_everywhere( 'CAPTION' ); $this->ensure_support_is_added_everywhere( 'HTML' ); $this->ensure_support_is_added_everywhere( 'TABLE' ); $this->ensure_support_is_added_everywhere( 'TD' ); $this->ensure_support_is_added_everywhere( 'TH' ); - $this->ensure_support_is_added_everywhere( 'MARQUEE' ); - $this->ensure_support_is_added_everywhere( 'OBJECT' ); $this->ensure_support_is_added_everywhere( 'TEMPLATE' ); // MathML Elements: MI, MO, MN, MS, MTEXT, ANNOTATION-XML. @@ -238,14 +223,11 @@ public function test_after_element_push_must_maintain_p_in_button_scope_flag() { */ public function test_has_element_in_table_scope_needs_support() { // These elements impact all scopes. - $this->ensure_support_is_added_everywhere( 'APPLET' ); $this->ensure_support_is_added_everywhere( 'CAPTION' ); $this->ensure_support_is_added_everywhere( 'HTML' ); $this->ensure_support_is_added_everywhere( 'TABLE' ); $this->ensure_support_is_added_everywhere( 'TD' ); $this->ensure_support_is_added_everywhere( 'TH' ); - $this->ensure_support_is_added_everywhere( 'MARQUEE' ); - $this->ensure_support_is_added_everywhere( 'OBJECT' ); $this->ensure_support_is_added_everywhere( 'TEMPLATE' ); // MathML Elements: MI, MO, MN, MS, MTEXT, ANNOTATION-XML. @@ -288,14 +270,11 @@ public function test_has_element_in_table_scope_needs_support() { */ public function test_has_element_in_select_scope_needs_support() { // These elements impact all scopes. - $this->ensure_support_is_added_everywhere( 'APPLET' ); $this->ensure_support_is_added_everywhere( 'CAPTION' ); $this->ensure_support_is_added_everywhere( 'HTML' ); $this->ensure_support_is_added_everywhere( 'TABLE' ); $this->ensure_support_is_added_everywhere( 'TD' ); $this->ensure_support_is_added_everywhere( 'TH' ); - $this->ensure_support_is_added_everywhere( 'MARQUEE' ); - $this->ensure_support_is_added_everywhere( 'OBJECT' ); $this->ensure_support_is_added_everywhere( 'TEMPLATE' ); // MathML Elements: MI, MO, MN, MS, MTEXT, ANNOTATION-XML. From 06287d16903a8b11106d387c65d79f402697891e Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Sat, 13 Jan 2024 08:38:56 -0600 Subject: [PATCH 2/6] HTML API: Implement active format reconstruction --- ...ass-wp-html-active-formatting-elements.php | 14 ++++++ .../html-api/class-wp-html-processor.php | 43 +++++++++++++++++-- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/html-api/class-wp-html-active-formatting-elements.php b/src/wp-includes/html-api/class-wp-html-active-formatting-elements.php index 1d7bd8e54fc1f..0d3114b075338 100644 --- a/src/wp-includes/html-api/class-wp-html-active-formatting-elements.php +++ b/src/wp-includes/html-api/class-wp-html-active-formatting-elements.php @@ -43,6 +43,20 @@ class WP_HTML_Active_Formatting_Elements { */ private $stack = array(); + /** + * Returns the node at the given index in the list of active formatting elements. + * + * Do not use this method; it is meant to be used only by the HTML Processor. + * + * @access private + * + * @param int $index Number of nodes from the top node to return. + * @return WP_HTML_Token|null Node at the given index in the stack, if one exists, otherwise null. + */ + public function at( $index ) { + return $this->stack[ $index ]; + } + /** * Reports if a specific node is in the stack of active formatting elements. * 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 7d1c9f8bdf65f..f5aa4e43dec84 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -1472,15 +1472,19 @@ private function generate_implied_end_tags_thoroughly() { * @return bool Whether any formatting elements needed to be reconstructed. */ private function reconstruct_active_formatting_elements() { + $count = $this->state->active_formatting_elements->count(); + /* * > If there are no entries in the list of active formatting elements, then there is nothing * > to reconstruct; stop this algorithm. */ - if ( 0 === $this->state->active_formatting_elements->count() ) { + if ( 0 === $count ) { return false; } - $last_entry = $this->state->active_formatting_elements->current_node(); + // Start at the last node in the list of active formatting elements. + $currently_at = $count - 1; + $last_entry = $this->state->active_formatting_elements->at( $currently_at ); if ( /* @@ -1499,8 +1503,39 @@ private function reconstruct_active_formatting_elements() { return false; } - $this->last_error = self::ERROR_UNSUPPORTED; - throw new WP_HTML_Unsupported_Exception( 'Cannot reconstruct active formatting elements when advancing and rewinding is required.' ); + $entry = $last_entry; + + while ( $currently_at >= 0 ) { + if ( 0 === $currently_at ) { + goto create; + } + $entry = $this->state->active_formatting_elements->at( --$currently_at ); + + /* + * > If entry is neither a marker nor an element that is also in the stack of open elements, + * > go to the step labeled rewind. + */ + if ( 'marker' === $entry->node_name || $this->state->stack_of_open_elements->contains_node( $entry ) ) { + break; + } + } + + advance: + $entry = $this->state->active_formatting_elements->at( ++$currently_at ); + + create: + $this->insert_html_element( $entry ); + + /* + * > Replace the entry for entry in the list with an entry for new element. + * This doesn't need to happen here since no DOM is being created. + */ + + if ( $count - 1 !== $currently_at ) { + goto advance; + } + + return true; } /** From d57744f4a1634af0654e8c35b2ca863b6f479ee9 Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Tue, 2 Jul 2024 16:13:14 -0700 Subject: [PATCH 3/6] Continue updating patch. --- .../html-api/class-wp-html-processor.php | 2 + .../tests/html-api/wpHtmlProcessor.php | 15 +++-- .../html-api/wpHtmlProcessorBreadcrumbs.php | 66 +++++++++++-------- 3 files changed, 50 insertions(+), 33 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 73eceac3946a0..a469ba6260195 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -1373,6 +1373,7 @@ private function step_in_body() { * > A start tag whose tag name is "iframe" */ case '+IFRAME': + $this->insert_html_element( $this->state->current_token ); $this->state->frameset_ok = false; return true; @@ -1380,6 +1381,7 @@ private function step_in_body() { * > A start tag whose tag name is "noembed" */ case '+NOEMBED': + $this->insert_html_element( $this->state->current_token ); return true; } diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php index 8cec7de2ef73b..c230a03849575 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php @@ -112,18 +112,23 @@ public function test_clear_to_navigate_after_seeking() { } /** - * Ensures that support is added for reconstructing active formatting elements - * before the HTML Processor handles situations with unclosed formats requiring it. + * Ensures that support is added for reconstructing active formatting elements. * * @ticket 58517 * * @covers WP_HTML_Processor::reconstruct_active_formatting_elements */ - public function test_fails_to_reconstruct_formatting_elements() { - $processor = WP_HTML_Processor::create_fragment( '

One

Two

Three

Four' ); + public function test_reconstructs_formatting_elements() { + $processor = WP_HTML_Processor::create_fragment( '

One

Two

Three

Four' ); $this->assertTrue( $processor->next_tag( 'EM' ), 'Could not find first EM.' ); - $this->assertFalse( $processor->next_tag( 'EM' ), 'Should have aborted before finding second EM as it required reconstructing the first EM.' ); + $this->assertSame( array( 'HTML', 'BODY', 'P', 'EM' ), $processor->get_breadcrumbs(), 'Found incorrect breadcrumbs for first EM.' ); + $this->assertTrue( $processor->next_tag( 'SPAN' ), 'Could not find test span.' ); + $this->assertSame( + array( 'HTML', 'BODY', 'P', 'EM', 'EM', 'SPAN' ), + $processor->get_breadcrumbs(), + 'Found incorrect breadcrumbs for test SPAN; should have created two EMs.' + ); } /** diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php b/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php index c509792aad887..5bec52bf8051d 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php @@ -224,45 +224,55 @@ public static function data_unsupported_elements() { } /** - * @ticket 58517 - * - * @dataProvider data_unsupported_markup + * Ensures that formats inside unclosed A elements are reconstructed. * - * @param string $html HTML containing unsupported markup. + * @ticket {TICKET_NUMBER} */ - public function test_fails_when_encountering_unsupported_markup( $html, $description ) { - $processor = WP_HTML_Processor::create_fragment( $html ); - - while ( $processor->next_token() && null === $processor->get_attribute( 'supported' ) ) { - continue; - } + public function test_reconstructs_formatting_from_unclosed_a_elements() { + $processor = WP_HTML_Processor::create_fragment( 'Click Here' ); - $this->assertNull( - $processor->get_last_error(), - 'Bailed on unsupported input before finding supported checkpoint: check test code.' + $processor->next_tag( 'STRONG' ); + $this->assertSame( + array( 'HTML', 'BODY', 'A', 'STRONG' ), + $processor->get_breadcrumbs(), + 'Failed to construct starting breadcrumbs properly.' ); - $this->assertTrue( $processor->get_attribute( 'supported' ), 'Did not find required supported element.' ); - $processor->next_token(); - $this->assertNotNull( $processor->get_last_error(), "Didn't properly reject unsupported markup: {$description}" ); + $processor->next_tag( 'BIG' ); + $this->assertSame( + array( 'HTML', 'BODY', 'STRONG', 'A', 'BIG' ), + $processor->get_breadcrumbs(), + 'Failed to reconstruct the active formatting elements after an unclosed A element.' + ); } /** - * Data provider. + * Ensures that unclosed A elements are reconstructed. * - * @return array[] + * @ticket {TICKET_NUMBER} */ - public static function data_unsupported_markup() { - return array( - 'A with formatting following unclosed A' => array( - 'Click Here', - 'Unclosed formatting requires complicated reconstruction.', - ), + public function test_reconstructs_unclosed_a_elements() { + $processor = WP_HTML_Processor::create_fragment( '

' ); - 'A after unclosed A inside DIV' => array( - '
', - 'A is a formatting element, which requires more complicated reconstruction.', - ), + $processor->next_tag( 'DIV' ); + $this->assertSame( + array( 'HTML', 'BODY', 'DIV' ), + $processor->get_breadcrumbs(), + 'Failed to construct breadcrumbs properly - the DIV should have closed the A element.' + ); + + // When the DIV re-opens, it reconstructs an unclosed A, then the A in the text is a second A. + $processor->next_tag( 'A' ); + $this->assertSame( + array( 'HTML', 'BODY', 'DIV', 'A' ), + 'Failed to create proper breadcrumbs for recreated A element.' + ); + + // This is the one that's second in the raw text. + $processor->next_tag( 'A' ); + $this->assertSame( + array( 'HTML', 'BODY', 'DIV', 'A' ), + 'Failed to create proper breadcrumbs for explicit A element - this A should have closed the reconstructed A.' ); } From bf356f0e1d43659162379c3063afc61b82babfa9 Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Tue, 2 Jul 2024 16:17:36 -0700 Subject: [PATCH 4/6] Remove addition of extra tags in this PR. --- .../html-api/class-wp-html-processor.php | 54 +++---------------- .../tests/html-api/wpHtmlProcessor.php | 7 +++ .../html-api/wpHtmlProcessorBreadcrumbs.php | 18 +++---- .../wpHtmlSupportRequiredOpenElements.php | 21 ++++++++ 4 files changed, 43 insertions(+), 57 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 a469ba6260195..2b870f24e8b58 100644 --- a/src/wp-includes/html-api/class-wp-html-processor.php +++ b/src/wp-includes/html-api/class-wp-html-processor.php @@ -1276,18 +1276,6 @@ private function step_in_body() { $this->run_adoption_agency_algorithm(); return true; - /* - * > A start tag whose tag name is one of: "applet", "marquee", "object" - */ - case '+APPLET': - case '+MARQUEE': - case '+OBJECT': - $this->reconstruct_active_formatting_elements(); - $this->insert_html_element( $this->state->current_token ); - $this->state->active_formatting_elements->insert_marker(); - $this->state->frameset_ok = false; - return true; - /* * > An end tag whose tag name is "br" * > Parse error. Drop the attributes from the token, and act as described in the next @@ -1348,41 +1336,6 @@ private function step_in_body() { case '+TRACK': $this->insert_html_element( $this->state->current_token ); return true; - - /* - * > A start tag whose tag name is "textarea" - */ - case '+TEXTAREA': - $this->insert_html_element( $this->state->current_token ); - $this->state->frameset_ok = false; - return true; - - /* - * > A start tag whose tag name is "xmp" - */ - case '+XMP': - if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) { - $this->close_a_p_element(); - } - $this->reconstruct_active_formatting_elements(); - $this->insert_html_element( $this->state->current_token ); - $this->state->frameset_ok = false; - return true; - - /* - * > A start tag whose tag name is "iframe" - */ - case '+IFRAME': - $this->insert_html_element( $this->state->current_token ); - $this->state->frameset_ok = false; - return true; - - /* - * > A start tag whose tag name is "noembed" - */ - case '+NOEMBED': - $this->insert_html_element( $this->state->current_token ); - return true; } /* @@ -1402,6 +1355,7 @@ private function step_in_body() { * @see https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inbody */ switch ( $token_name ) { + case 'APPLET': case 'BASE': case 'BASEFONT': case 'BGSOUND': @@ -1414,12 +1368,16 @@ private function step_in_body() { case 'FRAMESET': case 'HEAD': case 'HTML': + case 'IFRAME': case 'LINK': + case 'MARQUEE': case 'MATH': case 'META': case 'NOBR': + case 'NOEMBED': case 'NOFRAMES': case 'NOSCRIPT': + case 'OBJECT': case 'OPTGROUP': case 'OPTION': case 'PLAINTEXT': @@ -1436,11 +1394,13 @@ private function step_in_body() { case 'TBODY': case 'TD': case 'TEMPLATE': + case 'TEXTAREA': case 'TFOOT': case 'TH': case 'THEAD': case 'TITLE': case 'TR': + case 'XMP': $this->last_error = self::ERROR_UNSUPPORTED; throw new WP_HTML_Unsupported_Exception( "Cannot process {$token_name} element." ); } diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php index c230a03849575..2a5ddd2c1b418 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php @@ -388,6 +388,7 @@ public function test_step_in_body_fails_on_unsupported_tags( $tag_name ) { */ public static function data_unsupported_special_in_body_tags() { return array( + 'APPLET' => array( 'APPLET' ), 'BASE' => array( 'BASE' ), 'BASEFONT' => array( 'BASEFONT' ), 'BGSOUND' => array( 'BGSOUND' ), @@ -400,12 +401,16 @@ public static function data_unsupported_special_in_body_tags() { 'FRAMESET' => array( 'FRAMESET' ), 'HEAD' => array( 'HEAD' ), 'HTML' => array( 'HTML' ), + 'IFRAME' => array( 'IFRAME' ), 'LINK' => array( 'LINK' ), + 'MARQUEE' => array( 'MARQUEE' ), 'MATH' => array( 'MATH' ), 'META' => array( 'META' ), 'NOBR' => array( 'NOBR' ), + 'NOEMBED' => array( 'NOEMBED' ), 'NOFRAMES' => array( 'NOFRAMES' ), 'NOSCRIPT' => array( 'NOSCRIPT' ), + 'OBJECT' => array( 'OBJECT' ), 'OPTGROUP' => array( 'OPTGROUP' ), 'OPTION' => array( 'OPTION' ), 'PLAINTEXT' => array( 'PLAINTEXT' ), @@ -422,11 +427,13 @@ public static function data_unsupported_special_in_body_tags() { 'TBODY' => array( 'TBODY' ), 'TD' => array( 'TD' ), 'TEMPLATE' => array( 'TEMPLATE' ), + 'TEXTAREA' => array( 'TEXTAREA' ), 'TFOOT' => array( 'TFOOT' ), 'TH' => array( 'TH' ), 'THEAD' => array( 'THEAD' ), 'TITLE' => array( 'TITLE' ), 'TR' => array( 'TR' ), + 'XMP' => array( 'XMP' ), ); } diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php b/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php index 5bec52bf8051d..1e3e9272e3667 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php @@ -40,7 +40,6 @@ public static function data_single_tag_of_supported_elements() { 'ABBR', 'ACRONYM', // Neutralized. 'ADDRESS', - 'APPLET', // Deprecated. 'AREA', 'ARTICLE', 'ASIDE', @@ -86,28 +85,25 @@ public static function data_single_tag_of_supported_elements() { 'I', 'IMG', 'INS', + 'LI', 'ISINDEX', // Deprecated. 'KBD', 'KEYGEN', // Deprecated. 'LABEL', 'LEGEND', - 'LI', 'LISTING', // Deprecated. 'MAIN', 'MAP', 'MARK', - 'MARQUEE', // Deprecated. 'MENU', 'METER', 'MULTICOL', // Deprecated. 'NAV', 'NEXTID', // Deprecated. - 'OBJECT', 'OL', 'OUTPUT', 'P', 'PICTURE', - 'PRE', 'PROGRESS', 'Q', 'RUBY', @@ -129,7 +125,6 @@ public static function data_single_tag_of_supported_elements() { 'UL', 'VAR', 'VIDEO', - 'WBR', ); $data = array(); @@ -137,11 +132,7 @@ public static function data_single_tag_of_supported_elements() { $data[ $tag_name ] = array( "<{$tag_name}>", $tag_name ); } - $data['IFRAME'] = array( '', 'IFRAME' ); $data['IMAGE (treated as an IMG)'] = array( '', 'IMG' ); - $data['NOEMBED'] = array( '', 'NOEMBED' ); // Neutralized. - $data['TEXTAREA'] = array( '', 'TEXTAREA' ); - $data['XMP'] = array( '', 'XMP' ); // Deprecated, use PRE instead. return $data; } @@ -176,6 +167,7 @@ public function test_fails_when_encountering_unsupported_tag( $html ) { */ public static function data_unsupported_elements() { $unsupported_elements = array( + 'APPLET', // Deprecated. 'BASE', 'BGSOUND', // Deprecated; self-closing if self-closing flag provided, otherwise normal. 'BODY', @@ -187,12 +179,16 @@ public static function data_unsupported_elements() { 'FRAMESET', 'HEAD', 'HTML', + 'IFRAME', 'LINK', + 'MARQUEE', // Deprecated. 'MATH', 'META', 'NOBR', // Neutralized. + 'NOEMBED', // Neutralized. 'NOFRAMES', // Neutralized. 'NOSCRIPT', + 'OBJECT', 'OPTGROUP', 'OPTION', 'PLAINTEXT', // Neutralized. @@ -208,11 +204,13 @@ public static function data_unsupported_elements() { 'TBODY', 'TD', 'TEMPLATE', + 'TEXTAREA', 'TFOOT', 'TH', 'THEAD', 'TITLE', 'TR', + 'XMP', // Deprecated, use PRE instead. ); $data = array(); diff --git a/tests/phpunit/tests/html-api/wpHtmlSupportRequiredOpenElements.php b/tests/phpunit/tests/html-api/wpHtmlSupportRequiredOpenElements.php index d1a35906c9011..c2e8c697e8156 100644 --- a/tests/phpunit/tests/html-api/wpHtmlSupportRequiredOpenElements.php +++ b/tests/phpunit/tests/html-api/wpHtmlSupportRequiredOpenElements.php @@ -62,11 +62,14 @@ private function ensure_support_is_added_everywhere( $tag_name ) { */ public function test_has_element_in_scope_needs_support() { // These elements impact all scopes. + $this->ensure_support_is_added_everywhere( 'APPLET' ); $this->ensure_support_is_added_everywhere( 'CAPTION' ); $this->ensure_support_is_added_everywhere( 'HTML' ); $this->ensure_support_is_added_everywhere( 'TABLE' ); $this->ensure_support_is_added_everywhere( 'TD' ); $this->ensure_support_is_added_everywhere( 'TH' ); + $this->ensure_support_is_added_everywhere( 'MARQUEE' ); + $this->ensure_support_is_added_everywhere( 'OBJECT' ); $this->ensure_support_is_added_everywhere( 'TEMPLATE' ); // MathML Elements: MI, MO, MN, MS, MTEXT, ANNOTATION-XML. @@ -97,11 +100,14 @@ public function test_has_element_in_scope_needs_support() { */ public function test_has_element_in_list_item_scope_needs_support() { // These elements impact all scopes. + $this->ensure_support_is_added_everywhere( 'APPLET' ); $this->ensure_support_is_added_everywhere( 'CAPTION' ); $this->ensure_support_is_added_everywhere( 'HTML' ); $this->ensure_support_is_added_everywhere( 'TABLE' ); $this->ensure_support_is_added_everywhere( 'TD' ); $this->ensure_support_is_added_everywhere( 'TH' ); + $this->ensure_support_is_added_everywhere( 'MARQUEE' ); + $this->ensure_support_is_added_everywhere( 'OBJECT' ); $this->ensure_support_is_added_everywhere( 'TEMPLATE' ); // MathML Elements: MI, MO, MN, MS, MTEXT, ANNOTATION-XML. @@ -128,11 +134,14 @@ public function test_has_element_in_list_item_scope_needs_support() { */ public function test_has_element_in_button_scope_needs_support() { // These elements impact all scopes. + $this->ensure_support_is_added_everywhere( 'APPLET' ); $this->ensure_support_is_added_everywhere( 'CAPTION' ); $this->ensure_support_is_added_everywhere( 'HTML' ); $this->ensure_support_is_added_everywhere( 'TABLE' ); $this->ensure_support_is_added_everywhere( 'TD' ); $this->ensure_support_is_added_everywhere( 'TH' ); + $this->ensure_support_is_added_everywhere( 'MARQUEE' ); + $this->ensure_support_is_added_everywhere( 'OBJECT' ); $this->ensure_support_is_added_everywhere( 'TEMPLATE' ); // MathML Elements: MI, MO, MN, MS, MTEXT, ANNOTATION-XML. @@ -160,11 +169,14 @@ public function test_has_element_in_button_scope_needs_support() { */ public function test_after_element_pop_must_maintain_p_in_button_scope_flag() { // These elements impact all scopes. + $this->ensure_support_is_added_everywhere( 'APPLET' ); $this->ensure_support_is_added_everywhere( 'CAPTION' ); $this->ensure_support_is_added_everywhere( 'HTML' ); $this->ensure_support_is_added_everywhere( 'TABLE' ); $this->ensure_support_is_added_everywhere( 'TD' ); $this->ensure_support_is_added_everywhere( 'TH' ); + $this->ensure_support_is_added_everywhere( 'MARQUEE' ); + $this->ensure_support_is_added_everywhere( 'OBJECT' ); $this->ensure_support_is_added_everywhere( 'TEMPLATE' ); // MathML Elements: MI, MO, MN, MS, MTEXT, ANNOTATION-XML. @@ -192,11 +204,14 @@ public function test_after_element_pop_must_maintain_p_in_button_scope_flag() { */ public function test_after_element_push_must_maintain_p_in_button_scope_flag() { // These elements impact all scopes. + $this->ensure_support_is_added_everywhere( 'APPLET' ); $this->ensure_support_is_added_everywhere( 'CAPTION' ); $this->ensure_support_is_added_everywhere( 'HTML' ); $this->ensure_support_is_added_everywhere( 'TABLE' ); $this->ensure_support_is_added_everywhere( 'TD' ); $this->ensure_support_is_added_everywhere( 'TH' ); + $this->ensure_support_is_added_everywhere( 'MARQUEE' ); + $this->ensure_support_is_added_everywhere( 'OBJECT' ); $this->ensure_support_is_added_everywhere( 'TEMPLATE' ); // MathML Elements: MI, MO, MN, MS, MTEXT, ANNOTATION-XML. @@ -223,11 +238,14 @@ public function test_after_element_push_must_maintain_p_in_button_scope_flag() { */ public function test_has_element_in_table_scope_needs_support() { // These elements impact all scopes. + $this->ensure_support_is_added_everywhere( 'APPLET' ); $this->ensure_support_is_added_everywhere( 'CAPTION' ); $this->ensure_support_is_added_everywhere( 'HTML' ); $this->ensure_support_is_added_everywhere( 'TABLE' ); $this->ensure_support_is_added_everywhere( 'TD' ); $this->ensure_support_is_added_everywhere( 'TH' ); + $this->ensure_support_is_added_everywhere( 'MARQUEE' ); + $this->ensure_support_is_added_everywhere( 'OBJECT' ); $this->ensure_support_is_added_everywhere( 'TEMPLATE' ); // MathML Elements: MI, MO, MN, MS, MTEXT, ANNOTATION-XML. @@ -270,11 +288,14 @@ public function test_has_element_in_table_scope_needs_support() { */ public function test_has_element_in_select_scope_needs_support() { // These elements impact all scopes. + $this->ensure_support_is_added_everywhere( 'APPLET' ); $this->ensure_support_is_added_everywhere( 'CAPTION' ); $this->ensure_support_is_added_everywhere( 'HTML' ); $this->ensure_support_is_added_everywhere( 'TABLE' ); $this->ensure_support_is_added_everywhere( 'TD' ); $this->ensure_support_is_added_everywhere( 'TH' ); + $this->ensure_support_is_added_everywhere( 'MARQUEE' ); + $this->ensure_support_is_added_everywhere( 'OBJECT' ); $this->ensure_support_is_added_everywhere( 'TEMPLATE' ); // MathML Elements: MI, MO, MN, MS, MTEXT, ANNOTATION-XML. From 2746122326fa554c96f8c0a7abaf1301dfbf082e Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Sat, 6 Jul 2024 03:31:48 -0700 Subject: [PATCH 5/6] Undo added element support. --- .../html-api/class-wp-html-open-elements.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/wp-includes/html-api/class-wp-html-open-elements.php b/src/wp-includes/html-api/class-wp-html-open-elements.php index fda99df033d5b..d1585cdea5bf5 100644 --- a/src/wp-includes/html-api/class-wp-html-open-elements.php +++ b/src/wp-includes/html-api/class-wp-html-open-elements.php @@ -237,9 +237,14 @@ public function has_element_in_scope( $tag_name ) { return $this->has_element_in_specific_scope( $tag_name, array( - 'APPLET', - 'MARQUEE', - 'OBJECT', + + /* + * Because it's not currently possible to encounter + * one of the termination elements, they don't need + * to be listed here. If they were, they would be + * unreachable and only waste CPU cycles while + * scanning through HTML. + */ ) ); } @@ -534,10 +539,7 @@ public function after_element_push( $item ) { * cases where the precalculated value needs to change. */ switch ( $item->node_name ) { - case 'APPLET': case 'BUTTON': - case 'MARQUEE': - case 'OBJECT': $this->has_p_in_button_scope = false; break; From 921f5466d09ede5dfe77b03d12436b1a7b4e2888 Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Sat, 6 Jul 2024 03:36:15 -0700 Subject: [PATCH 6/6] Add ticket number --- tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php b/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php index e44b86b3fe296..5ec846df16fec 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php @@ -221,7 +221,7 @@ public static function data_unsupported_elements() { /** * Ensures that formats inside unclosed A elements are reconstructed. * - * @ticket {TICKET_NUMBER} + * @ticket 61576 */ public function test_reconstructs_formatting_from_unclosed_a_elements() { $processor = WP_HTML_Processor::create_fragment( 'Click Here' ); @@ -244,7 +244,7 @@ public function test_reconstructs_formatting_from_unclosed_a_elements() { /** * Ensures that unclosed A elements are reconstructed. * - * @ticket {TICKET_NUMBER} + * @ticket 61576 */ public function test_reconstructs_unclosed_a_elements() { $processor = WP_HTML_Processor::create_fragment( '
' );