diff --git a/src/wp-includes/formatting.php b/src/wp-includes/formatting.php index 234d71a2a175a..fa60cf156b0b6 100644 --- a/src/wp-includes/formatting.php +++ b/src/wp-includes/formatting.php @@ -5510,7 +5510,20 @@ function normalize_whitespace( $str ) { * the `' )` * will return 'something'. wp_strip_all_tags() will return an empty string. * + * Because tags and comments are disappearing, which might have + * separated sequences that could combine into new character + * references when joined, it’s important to start by removing + * any raw breaks before decoding, then fully decode each chunk, + * and finally re-encode the entire string once done. This ensures + * that no previous boundaries will be merged on accident. + * + * Example: + * + * $html = '

<script

'; + * '&lt;script' === wp_strip_all_tags( $html ); + * * @since 2.9.0 + * @since {WP_VERSION} Reliably parses HTML via the HTML API. * * @param string $text String containing HTML tags * @param bool $remove_breaks Optional. Whether to remove left over line breaks and white space chars @@ -5544,14 +5557,45 @@ function wp_strip_all_tags( $text, $remove_breaks = false ) { return ''; } - $text = preg_replace( '@<(script|style)[^>]*?>.*?@si', '', $text ); - $text = strip_tags( $text ); + $text_extractor = new class( $text ) extends WP_HTML_Tag_Processor { + public function extract_raw_token() { + $this->set_bookmark( 'here' ); + $here = $this->bookmarks['here']; + + return substr( $this->html, $here->start, $here->length ); + } + }; + $plaintext = ''; if ( $remove_breaks ) { - $text = preg_replace( '/[\r\n\t ]+/', ' ', $text ); + while ( $text_extractor->next_token() ) { + if ( '#text' !== $text_extractor->get_token_name() ) { + continue; + } + + $chunk = $text_extractor->extract_raw_token(); + $chunk = preg_replace( '~[ \r\n\t\f]+~', ' ', $chunk ); + $plaintext .= WP_HTML_Decoder::decode_text_node( $chunk ); + } + } else { + while ( $text_extractor->next_token() ) { + if ( '#text' !== $text_extractor->get_token_name() ) { + continue; + } + + $plaintext .= WP_HTML_Decoder::decode_text_node( $text_extractor->extract_raw_token() ); + } } - return trim( $text ); + $html_syntax = array( + '&' => '&', + '<' => '<', + '>' => '>', + '"' => '"', + "'" => ''', + ); + + return trim( strtr( $plaintext, $html_syntax ) ); } /** diff --git a/tests/phpunit/tests/customize/nav-menu-item-setting.php b/tests/phpunit/tests/customize/nav-menu-item-setting.php index eb5aa46e89f51..21c5eec808e61 100644 --- a/tests/phpunit/tests/customize/nav-menu-item-setting.php +++ b/tests/phpunit/tests/customize/nav-menu-item-setting.php @@ -955,7 +955,7 @@ public function test_value_as_wp_post_nav_menu_item() { $this->assertObjectHasProperty( 'type_label', $nav_menu_item ); $expected = apply_filters( 'nav_menu_attr_title', wp_unslash( apply_filters( 'excerpt_save_pre', wp_slash( $post_value['attr_title'] ) ) ) ); $this->assertSame( $expected, $nav_menu_item->attr_title ); - $this->assertSame( 'Attempted \o/ o’o markup', $nav_menu_item->description ); + $this->assertEqualHTML( 'Attempted \o/ o’o markup', $nav_menu_item->description ); $this->assertSame( array( 'class-1', 'class-2' ), $nav_menu_item->classes ); } diff --git a/tests/phpunit/tests/formatting/wpHtmlExcerpt.php b/tests/phpunit/tests/formatting/wpHtmlExcerpt.php index 96cd58226d2dc..6e0af6ac02d65 100644 --- a/tests/phpunit/tests/formatting/wpHtmlExcerpt.php +++ b/tests/phpunit/tests/formatting/wpHtmlExcerpt.php @@ -13,9 +13,9 @@ public function test_html() { $this->assertSame( 'Baba', wp_html_excerpt( "Baba told me not to come", 4 ) ); } public function test_entities() { - $this->assertSame( 'Baba', wp_html_excerpt( 'Baba & Dyado', 8 ) ); - $this->assertSame( 'Baba', wp_html_excerpt( 'Baba & Dyado', 8 ) ); - $this->assertSame( 'Baba & D', wp_html_excerpt( 'Baba & Dyado', 12 ) ); - $this->assertSame( 'Baba & Dyado', wp_html_excerpt( 'Baba & Dyado', 100 ) ); + $this->assertEqualHTML( 'Baba', wp_html_excerpt( 'Baba & Dyado', 8 ) ); + $this->assertEqualHTML( 'Baba', wp_html_excerpt( 'Baba & Dyado', 8 ) ); + $this->assertEqualHTML( 'Baba & D', wp_html_excerpt( 'Baba & Dyado', 12 ) ); + $this->assertEqualHTML( 'Baba & Dyado', wp_html_excerpt( 'Baba & Dyado', 100 ) ); } } diff --git a/tests/phpunit/tests/widgets/wpWidgetMediaImage.php b/tests/phpunit/tests/widgets/wpWidgetMediaImage.php index 934adab6d50c9..be1cf7ed7225f 100644 --- a/tests/phpunit/tests/widgets/wpWidgetMediaImage.php +++ b/tests/phpunit/tests/widgets/wpWidgetMediaImage.php @@ -259,12 +259,8 @@ public function test_update() { ), $instance ); - $this->assertSame( - $result, - array( - 'alt' => '">', - ) - ); + $this->assertArrayHasKey( 'alt', $result ); + $this->assertEqualHTML( '">', $result['alt'] ); // Should return valid link type. $expected = array(