diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index 2c9502035705c..31d1769405c1b 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -1440,6 +1440,26 @@ protected function parse_search( &$query_vars ) { if ( empty( $_GET['s'] ) && $this->is_main_query() ) { $query_vars['s'] = urldecode( $query_vars['s'] ); } + // Admin post titles are texturized before display, so copied smart quotes should still match stored titles. + $query_vars['s'] = strtr( + $query_vars['s'], + array( + "\u{00A0}" => ' ', + "\u{202F}" => ' ', + "\u{00AB}" => '"', + "\u{00BB}" => '"', + "\u{2018}" => "'", + "\u{2019}" => "'", + "\u{201A}" => "'", + "\u{201B}" => "'", + "\u{201C}" => '"', + "\u{201D}" => '"', + "\u{201E}" => '"', + "\u{201F}" => '"', + "\u{2039}" => "'", + "\u{203A}" => "'", + ) + ); // There are no line breaks in fields. $query_vars['s'] = str_replace( array( "\r", "\n" ), '', $query_vars['s'] ); $query_vars['search_terms_count'] = 1; diff --git a/tests/phpunit/tests/query/search.php b/tests/phpunit/tests/query/search.php index 7bfbdec31c87d..c909d9292cc9e 100644 --- a/tests/phpunit/tests/query/search.php +++ b/tests/phpunit/tests/query/search.php @@ -32,6 +32,10 @@ private function get_search_results( $terms ) { return $this->q->query( $args ); } + private function get_texturized_search_term( $title ) { + return html_entity_decode( wptexturize( $title ), ENT_QUOTES, 'UTF-8' ); + } + public function test_search_order_title_relevance() { foreach ( range( 1, 7 ) as $i ) { self::factory()->post->create( @@ -52,6 +56,38 @@ public function test_search_order_title_relevance() { $this->assertSame( $post_id, reset( $posts )->ID ); } + /** + * @ticket 63209 + */ + public function test_search_should_match_texturized_double_quotes() { + $post_id = self::factory()->post->create( + array( + 'post_title' => '"New" a good post', + 'post_type' => $this->post_type, + ) + ); + + $posts = $this->get_search_results( $this->get_texturized_search_term( '"New" a good post' ) ); + + $this->assertSame( array( $post_id ), wp_list_pluck( $posts, 'ID' ) ); + } + + /** + * @ticket 63209 + */ + public function test_search_should_match_texturized_apostrophes() { + $post_id = self::factory()->post->create( + array( + 'post_title' => "Today's post", + 'post_type' => $this->post_type, + ) + ); + + $posts = $this->get_search_results( $this->get_texturized_search_term( "Today's post" ) ); + + $this->assertSame( array( $post_id ), wp_list_pluck( $posts, 'ID' ) ); + } + public function test_search_terms_query_var() { $terms = 'This is a search term'; $query = new WP_Query( array( 's' => 'This is a search term' ) );