WordPress.org

Make WordPress Core

Ticket #43867: 43867.diff

File 43867.diff, 15.2 KB (added by birgire, 3 years ago)
  • src/wp-includes/class-wp-query.php

    diff --git src/wp-includes/class-wp-query.php src/wp-includes/class-wp-query.php
    index f8ead26..5964685 100644
    class WP_Query { 
    581581                        'post_parent__not_in',
    582582                        'author__in',
    583583                        'author__not_in',
     584                        'search_columns',
    584585                );
    585586
    586587                foreach ( $array_keys as $key ) {
    class WP_Query { 
    605606         * @since 4.6.0 Added 'post_name__in' support for `$orderby`. Introduced the `$lazy_load_term_meta` argument.
    606607         * @since 4.9.0 Introduced the `$comment_count` parameter.
    607608         * @since 5.0.0 Introduced the `$meta_compare_key` parameter.
     609         * @since 5.0.0 Introduced the `$search_columns` parameter.
    608610         *
    609611         * @param string|array $query {
    610612         *     Optional. Array or string of Query parameters.
    class WP_Query { 
    697699         *                                                 the 'wp_query_search_exclusion_prefix' filter.
    698700         *     @type int          $second                  Second of the minute. Default empty. Accepts numbers 0-60.
    699701         *     @type bool         $sentence                Whether to search by phrase. Default false.
     702         *     @type array        $search_columns          Array of column names to be searched. Accepts 'post_title',
     703         *                                                 'post_excerpt' and 'post_content'. Default empty array.
    700704         *     @type bool         $suppress_filters        Whether to suppress filters. Default false.
    701705         *     @type string       $tag                     Tag slug. Comma-separated (either), Plus-separated (all).
    702706         *     @type array        $tag__and                An array of tag ids (AND in).
    class WP_Query { 
    13001304                global $wpdb;
    13011305
    13021306                $search = '';
    1303 
     1307               
    13041308                // added slashes screw with quote grouping when done early, so done later
    13051309                $q['s'] = stripslashes( $q['s'] );
    13061310                if ( empty( $_GET['s'] ) && $this->is_main_query() ) {
    class WP_Query { 
    13281332                $searchand                 = '';
    13291333                $q['search_orderby_title'] = array();
    13301334
     1335                $search_columns           = $q['search_columns'];
     1336                $default_search_columns   = array( 'post_title', 'post_excerpt', 'post_content' );
     1337                $supported_search_columns = $default_search_columns;
     1338
     1339                if ( ! $search_columns ) {
     1340                        $search_columns = $default_search_columns;
     1341                }
     1342
     1343                /**
     1344                * Filters the columns to search in a WP_Query search.
     1345                *
     1346                * The supported columns are `post_title`, `post_excerpt` and `post_content`.
     1347                * They are all included by default.
     1348                *
     1349                * @since 5.0.0
     1350                *
     1351                * @param string[] $search_columns Array of column names to be searched.
     1352                * @param string   $search         Text being searched.
     1353                * @param WP_Query $this           The current WP_Query instance.
     1354                */
     1355                $search_columns = (array) apply_filters( 'post_search_columns', $search_columns, $q['s'], $this );
     1356
     1357                // Use only supported search columns.
     1358                $search_columns = array_intersect( $search_columns, $supported_search_columns );
     1359
     1360                if ( ! $search_columns ) {
     1361                        $search_columns = $default_search_columns;
     1362                }
     1363
    13311364                /**
    13321365                 * Filters the prefix that indicates that a search term should be excluded from results.
    13331366                 *
    class WP_Query { 
    13551388                                $q['search_orderby_title'][] = $wpdb->prepare( "{$wpdb->posts}.post_title LIKE %s", $like );
    13561389                        }
    13571390
    1358                         $like      = $n . $wpdb->esc_like( $term ) . $n;
    1359                         $search   .= $wpdb->prepare( "{$searchand}(({$wpdb->posts}.post_title $like_op %s) $andor_op ({$wpdb->posts}.post_excerpt $like_op %s) $andor_op ({$wpdb->posts}.post_content $like_op %s))", $like, $like, $like );
     1391                        $like = $n . $wpdb->esc_like( $term ) . $n;
     1392
     1393                        $searches = array();
     1394                        foreach ( (array) $search_columns as $search_column ) {
     1395                                $searches[] = $wpdb->prepare( "({$wpdb->posts}.{$search_column} $like_op %s)", $like );
     1396                        }
     1397
     1398                        if ( $searches ) {
     1399                                $search .= "{$searchand}(" . join( " $andor_op", $searches ) . ')';
     1400                        }
     1401
    13601402                        $searchand = ' AND ';
    13611403                }
    13621404
  • new file tests/phpunit/tests/query/searchColumns.php

    diff --git tests/phpunit/tests/query/searchColumns.php tests/phpunit/tests/query/searchColumns.php
    new file mode 100644
    index 0000000..1671619
    - +  
     1<?php
     2/**
     3 * Testing the search columns support in `WP_Query`.
     4 *
     5 * @package WordPress\UnitTests
     6 * @since 5.0.0
     7 */
     8
     9/**
     10 * Test cases for the search columns feature.
     11 *
     12 * @group query
     13 * @group search
     14 *
     15 * @since 5.0.0
     16 */
     17class Tests_Query_SearchColumns extends WP_UnitTestCase {
     18        /**
     19         * The post ID of the first fixture post.
     20         *
     21         * @since 5.0.0
     22         * @var int $pid1
     23         */
     24        protected static $pid1;
     25
     26        /**
     27         * The post ID of the second fixture post.
     28         *
     29         * @since 5.0.0
     30         * @var int $pid2
     31         */
     32        protected static $pid2;
     33
     34        /**
     35         * The post ID of the third fixture post.
     36         *
     37         * @since 5.0.0
     38         * @var int $pid3
     39         */
     40        protected static $pid3;
     41
     42        /**
     43         * Create posts fixtures.
     44         *
     45         * @param WP_UnitTest_Factory $factory The factory instance.
     46         */
     47        public static function wpSetUpBeforeClass( $factory ) {
     48                self::$pid1 = self::factory()->post->create(
     49                        array(
     50                                'post_status'  => 'publish',
     51                                'post_title'   => 'foo title',
     52                                'post_excerpt' => 'foo excerpt',
     53                                'post_content' => 'foo content',
     54                        )
     55                );
     56                self::$pid2 = self::factory()->post->create(
     57                        array(
     58                                'post_status'  => 'publish',
     59                                'post_title'   => 'bar title',
     60                                'post_excerpt' => 'foo bar excerpt',
     61                                'post_content' => 'foo bar content',
     62                        )
     63                );
     64
     65                self::$pid3 = self::factory()->post->create(
     66                        array(
     67                                'post_status'  => 'publish',
     68                                'post_title'   => 'baz title',
     69                                'post_excerpt' => 'baz bar excerpt',
     70                                'post_content' => 'baz bar foo content',
     71                        )
     72                );
     73        }
     74
     75        /**
     76         * The search should use default search columns when search columns are empty.
     77         */
     78        public function test_s_should_use_default_search_columns_when_empty_search_columns() {
     79                $q = new WP_Query(
     80                        array(
     81                                's'              => 'foo',
     82                                'search_columns' => array(),
     83                                'fields'         => 'ids',
     84                        )
     85                );
     86
     87                $this->assertContains( 'post_title', $q->request );
     88                $this->assertContains( 'post_excerpt', $q->request );
     89                $this->assertContains( 'post_content', $q->request );
     90                $this->assertEqualSets( array( self::$pid1, self::$pid2, self::$pid3 ), $q->posts );
     91        }
     92
     93        /**
     94         * The search should support the post_title search column.
     95         */
     96        public function test_s_should_support_post_title_search_column() {
     97                $q = new WP_Query(
     98                        array(
     99                                's'              => 'foo',
     100                                'search_columns' => array( 'post_title' ),
     101                                'fields'         => 'ids',
     102                        )
     103                );
     104
     105                $this->assertEqualSets( array( self::$pid1 ), $q->posts );
     106        }
     107
     108        /**
     109         * The search should support the `post_excerpt` search column.
     110         */
     111        public function test_s_should_support_post_excerpt_search_column() {
     112                $q = new WP_Query(
     113                        array(
     114                                's'              => 'foo',
     115                                'search_columns' => array( 'post_excerpt' ),
     116                                'fields'         => 'ids',
     117                        )
     118                );
     119
     120                $this->assertEqualSets( array( self::$pid1, self::$pid2 ), $q->posts );
     121        }
     122
     123        /**
     124         * The search should support the `post_content` search column.
     125         */
     126        public function test_s_should_support_post_content_search_column() {
     127                $q = new WP_Query(
     128                        array(
     129                                's'              => 'foo',
     130                                'search_columns' => array( 'post_content' ),
     131                                'fields'         => 'ids',
     132                        )
     133                );
     134                $this->assertEqualSets( array( self::$pid1, self::$pid2, self::$pid3 ), $q->posts );
     135        }
     136
     137        /**
     138         * The search should support the `post_title` and `post_excerpt` search columns together.
     139         */
     140        public function test_s_should_support_post_title_and_post_excerpt_search_columns() {
     141                $q = new WP_Query(
     142                        array(
     143                                's'              => 'foo',
     144                                'search_columns' => array( 'post_title', 'post_excerpt' ),
     145                                'fields'         => 'ids',
     146                        )
     147                );
     148
     149                $this->assertEqualSets( array( self::$pid1, self::$pid2 ), $q->posts );
     150        }
     151
     152        /**
     153         * The search should support the `post_title` and `post_content` search columns together.
     154         */
     155        public function test_s_should_support_post_title_and_post_content_search_columns() {
     156                $q = new WP_Query(
     157                        array(
     158                                's'              => 'foo',
     159                                'search_columns' => array( 'post_title', 'post_content' ),
     160                                'fields'         => 'ids',
     161                        )
     162                );
     163
     164                $this->assertEqualSets( array( self::$pid1, self::$pid2, self::$pid3 ), $q->posts );
     165        }
     166
     167        /**
     168         * The search should support the `post_excerpt` and `post_content` search columns together.
     169         */
     170        public function test_s_should_support_post_excerpt_and_post_content_search_columns() {
     171                $q = new WP_Query(
     172                        array(
     173                                's'              => 'foo',
     174                                'search_columns' => array( 'post_excerpt', 'post_content' ),
     175                                'fields'         => 'ids',
     176                        )
     177                );
     178
     179                $this->assertEqualSets( array( self::$pid1, self::$pid2, self::$pid3 ), $q->posts );
     180        }
     181
     182        /**
     183         * The search should support the `post_title`, `post_excerpt` and `post_content` search columns together.
     184         */
     185        public function test_s_should_support_post_title_and_post_excerpt_and_post_content_search_columns() {
     186                $q = new WP_Query(
     187                        array(
     188                                's'              => 'foo',
     189                                'search_columns' => array( 'post_title', 'post_excerpt', 'post_content' ),
     190                                'fields'         => 'ids',
     191                        )
     192                );
     193
     194                $this->assertEqualSets( array( self::$pid1, self::$pid2, self::$pid3 ), $q->posts );
     195        }
     196
     197        /**
     198         * The search should use default support columns when using a non existing search column.
     199         */
     200        public function test_s_should_use_default_search_columns_when_using_non_existing_search_column() {
     201                $q = new WP_Query(
     202                        array(
     203                                's'              => 'foo',
     204                                'search_columns' => array( 'post_non_existing_column' ),
     205                                'fields'         => 'ids',
     206                        )
     207                );
     208
     209                $this->assertContains( 'post_title', $q->request );
     210                $this->assertContains( 'post_excerpt', $q->request );
     211                $this->assertContains( 'post_content', $q->request );
     212                $this->assertEqualSets( array( self::$pid1, self::$pid2, self::$pid3 ), $q->posts );
     213        }
     214
     215        /**
     216         * The search should support ignore a non existing search column when used together with a supported one.
     217         */
     218        public function test_s_should_ignore_non_existing_search_column_when_used_with_supported_one() {
     219                $q = new WP_Query(
     220                        array(
     221                                's'              => 'foo',
     222                                'search_columns' => array( 'post_title', 'post_non_existing_column' ),
     223                                'fields'         => 'ids',
     224                        )
     225                );
     226
     227                $this->assertEqualSets( array( self::$pid1 ), $q->posts );
     228        }
     229
     230        /**
     231         * The search should support search columns when searching multiple terms.
     232         */
     233        public function test_s_should_support_search_columns_when_searching_multiple_terms() {
     234                $q = new WP_Query(
     235                        array(
     236                                's'              => 'foo bar',
     237                                'search_columns' => array( 'post_content' ),
     238                                'fields'         => 'ids',
     239                        )
     240                );
     241
     242                $this->assertEqualSets( array( self::$pid2, self::$pid3 ), $q->posts );
     243        }
     244
     245        /**
     246         * The search should support search columns when searching for a sentence.
     247         */
     248        public function test_s_should_support_search_columns_when_sentence_true() {
     249                $q = new WP_Query(
     250                        array(
     251                                's'              => 'bar foo',
     252                                'search_columns' => array( 'post_content' ),
     253                                'sentence'       => true,
     254                                'fields'         => 'ids',
     255                        )
     256                );
     257
     258                $this->assertEqualSets( array( self::$pid3 ), $q->posts );
     259        }
     260
     261        /**
     262         * The search should support search columns when searching for a sentence.
     263         */
     264        public function test_s_should_support_search_columns_when_sentence_false() {
     265                $q = new WP_Query(
     266                        array(
     267                                's'              => 'bar foo',
     268                                'search_columns' => array( 'post_content' ),
     269                                'sentence'       => false,
     270                                'fields'         => 'ids',
     271                        )
     272                );
     273
     274                $this->assertEqualSets( array( self::$pid2, self::$pid3 ), $q->posts );
     275        }
     276
     277        /**
     278         * The search should support search columns when searched with a term exclusion.
     279         */
     280        public function test_s_should_support_search_columns_when_searched_with_term_exclusion() {
     281                $q = new WP_Query(
     282                        array(
     283                                's'              => 'bar -baz',
     284                                'search_columns' => array( 'post_excerpt', 'post_content' ),
     285                                'fields'         => 'ids',
     286                        )
     287                );
     288
     289                $this->assertEqualSets( array( self::$pid2 ), $q->posts );
     290        }
     291
     292        /**
     293         * The search columns should be filterable with the `post_search_columns` filter.
     294         */
     295        public function test_search_columns_should_be_filterable() {
     296                add_filter( 'post_search_columns', array( $this, 'post_supported_search_column' ), 10, 3 );
     297                $q = new WP_Query(
     298                        array(
     299                                's'      => 'foo',
     300                                'fields' => 'ids',
     301                        )
     302                );
     303                remove_filter( 'post_search_columns', array( $this, 'post_supported_search_column' ) );
     304
     305                $this->assertEqualSets( array( self::$pid1 ), $q->posts );
     306        }
     307
     308        /**
     309         * Filter callback that sets a supported search column.
     310         *
     311         * @param  string[] $search_columns Array of column names to be searched.
     312         * @param  string   $search         Text being searched.
     313         * @param  WP_Query $wp_query       The current WP_Query instance.
     314         * @return string[] $search_columns Array of column names to be searched.
     315         */
     316        public function post_supported_search_column( $search_columns, $search, $wp_query ) {
     317                $search_columns = array( 'post_title' );
     318                return $search_columns;
     319        }
     320
     321        /**
     322         * The search columns should not be filterable when using non supported search columns.
     323         */
     324        public function test_search_columns_should_not_filterable_when_non_supported_search_columns() {
     325                add_filter( 'post_search_columns', array( $this, 'post_non_supported_search_column' ), 10, 3 );
     326                $q = new WP_Query(
     327                        array(
     328                                's'      => 'foo',
     329                                'fields' => 'ids',
     330                        )
     331                );
     332                remove_filter( 'post_search_columns', array( $this, 'post_non_supported_search_column' ) );
     333
     334                $this->assertNotContains( 'post_name', $q->request );
     335                $this->assertEqualSets( array( self::$pid1, self::$pid2, self::$pid3 ), $q->posts );
     336        }
     337
     338        /**
     339         * Filter callback that sets an existing but non supported search column.
     340         *
     341         * @param  string[] $search_columns Array of column names to be searched.
     342         * @param  string   $search         Text being searched.
     343         * @param  WP_Query $wp_query       The current WP_Query instance.
     344         * @return string[] $search_columns Array of column names to be searched.
     345         */
     346        public function post_non_supported_search_column( $search_columns, $search, $wp_query ) {
     347                $search_columns = array( 'post_name' );
     348                return $search_columns;
     349        }
     350
     351        /**
     352         * The search columns should not be filterable with non existing search columns.
     353         */
     354        public function xtest_search_columns_should_not_filterable_non_existing_search_column() {
     355                add_filter( 'post_search_columns', array( $this, 'post_non_existing_search_column' ), 10, 3 );
     356                $q = new WP_Query(
     357                        array(
     358                                's'      => 'foo',
     359                                'fields' => 'ids',
     360                        )
     361                );
     362                remove_filter( 'post_search_columns', array( $this, 'post_non_existing_search_column' ) );
     363
     364                $this->assertNotContains( 'post_non_existing_column', $q->request );
     365                $this->assertEqualSets( array( self::$pid1, self::$pid2, self::$pid3 ), $q->posts );
     366        }
     367
     368        /**
     369         * Filter callback that sets a non existing search column.
     370         *
     371         * @param  string[] $search_columns Array of column names to be searched.
     372         * @param  string   $search         Text being searched.
     373         * @param  WP_Query $wp_query       The current WP_Query instance.
     374         * @return string[] $search_columns Array of column names to be searched.
     375         */
     376        public function post_non_existing_search_column( $search_columns, $search, $wp_query ) {
     377                $search_columns = array( 'post_non_existing_column' );
     378                return $search_columns;
     379        }
     380
     381}