Make WordPress Core

Changeset 55248


Ignore:
Timestamp:
02/07/2023 08:53:01 AM (22 months ago)
Author:
audrasjb
Message:

Query: Add a search_columns argument to control which fields are searched in a search query.

Previously, the s argument of the WP_Query::parse_query() method searched the post_title, post_excerpt, and post_content fields, with no way of controlling this apart from using the posts_search filter and adjusting the SQL manually. This changeset adds the ability to specify which fields are searched when performing a query, using the search_columns argument.

Props johnbillion, birgire, petitphp, audrasjb, costdev, mukesh27.
Fixes #43867.

Location:
trunk
Files:
1 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-query.php

    r55035 r55248  
    611611            'author__in',
    612612            'author__not_in',
     613            'search_columns',
    613614        );
    614615
     
    638639     * @since 5.3.0 Introduced the `$meta_type_key` parameter.
    639640     * @since 6.1.0 Introduced the `$update_menu_item_cache` parameter.
     641     * @since 6.2.0 Introduced the `$search_columns` parameter.
    640642     *
    641643     * @param string|array $query {
     
    751753     *                                                    character used for exclusion can be modified using the
    752754     *                                                    the 'wp_query_search_exclusion_prefix' filter.
     755     *     @type array           $search_columns          Array of column names to be searched. Accepts 'post_title',
     756     *                                                    'post_excerpt' and 'post_content'. Default empty array.
    753757     *     @type int             $second                  Second of the minute. Default empty. Accepts numbers 0-59.
    754758     *     @type bool            $sentence                Whether to search by phrase. Default false.
     
    14111415        $q['search_orderby_title'] = array();
    14121416
     1417        $default_search_columns = array( 'post_title', 'post_excerpt', 'post_content' );
     1418        $search_columns         = ! empty( $q['search_columns'] ) ? $q['search_columns'] : $default_search_columns;
     1419        if ( ! is_array( $search_columns ) ) {
     1420            $search_columns = array( $search_columns );
     1421        }
     1422
     1423        /**
     1424         * Filters the columns to search in a WP_Query search.
     1425         *
     1426         * The supported columns are `post_title`, `post_excerpt` and `post_content`.
     1427         * They are all included by default.
     1428         *
     1429         * @since 6.2.0
     1430         *
     1431         * @param string[] $search_columns Array of column names to be searched.
     1432         * @param string   $search         Text being searched.
     1433         * @param WP_Query $query          The current WP_Query instance.
     1434         */
     1435        $search_columns = (array) apply_filters( 'post_search_columns', $search_columns, $q['s'], $this );
     1436
     1437        // Use only supported search columns.
     1438        $search_columns = array_intersect( $search_columns, $default_search_columns );
     1439        if ( empty( $search_columns ) ) {
     1440            $search_columns = $default_search_columns;
     1441        }
     1442
    14131443        /**
    14141444         * Filters the prefix that indicates that a search term should be excluded from results.
     
    14401470            $like = $n . $wpdb->esc_like( $term ) . $n;
    14411471
     1472            $search_columns_parts = array();
     1473            foreach ( $search_columns as $search_column ) {
     1474                $search_columns_parts[ $search_column ] = $wpdb->prepare( "({$wpdb->posts}.$search_column $like_op %s)", $like );
     1475            }
     1476
    14421477            if ( ! empty( $this->allow_query_attachment_by_filename ) ) {
    1443                 $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) $andor_op (sq1.meta_value $like_op %s))", $like, $like, $like, $like );
    1444             } else {
    1445                 $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 );
    1446             }
     1478                $search_columns_parts['attachment'] = $wpdb->prepare( "(sq1.meta_value $like_op %s)", $like );
     1479            }
     1480
     1481            $search .= "$searchand(" . implode( " $andor_op ", $search_columns_parts ) . ')';
     1482
    14471483            $searchand = ' AND ';
    14481484        }
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php

    r54870 r55248  
    250250            'parent_exclude' => 'post_parent__not_in',
    251251            'search'         => 's',
     252            'search_columns' => 'search_columns',
    252253            'slug'           => 'post_name__in',
    253254            'status'         => 'post_status',
     
    28922893        }
    28932894
     2895        $query_params['search_columns'] = array(
     2896            'default'     => array(),
     2897            'description' => __( 'Array of column names to be searched.' ),
     2898            'type'        => 'array',
     2899            'items'       => array(
     2900                'enum' => array( 'post_title', 'post_content', 'post_excerpt' ),
     2901                'type' => 'string',
     2902            ),
     2903        );
     2904
    28942905        $query_params['slug'] = array(
    28952906            'description' => __( 'Limit result set to posts with one or more specific slugs.' ),
  • trunk/tests/phpunit/tests/rest-api/rest-attachments-controller.php

    r55104 r55248  
    231231                'per_page',
    232232                'search',
     233                'search_columns',
    233234                'slug',
    234235                'status',
  • trunk/tests/phpunit/tests/rest-api/rest-pages-controller.php

    r54090 r55248  
    8787                'per_page',
    8888                'search',
     89                'search_columns',
    8990                'slug',
    9091                'status',
  • trunk/tests/phpunit/tests/rest-api/rest-posts-controller.php

    r55104 r55248  
    205205                'per_page',
    206206                'search',
     207                'search_columns',
    207208                'slug',
    208209                'status',
     
    15261527
    15271528        $this->assertPostsWhere( " AND {posts}.ID NOT IN ($id3) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" );
     1529    }
     1530
     1531    /**
     1532     * Tests that Rest Post controller supports search columns.
     1533     *
     1534     * @ticket 43867
     1535     * @covers WP_REST_Posts_Controller::get_items
     1536     */
     1537    public function test_get_items_with_custom_search_columns() {
     1538        $id1 = self::factory()->post->create(
     1539            array(
     1540                'post_title'   => 'Title contain foo and bar',
     1541                'post_content' => 'Content contain bar',
     1542                'post_excerpt' => 'Excerpt contain baz',
     1543            )
     1544        );
     1545        $id2 = self::factory()->post->create(
     1546            array(
     1547                'post_title'   => 'Title contain baz',
     1548                'post_content' => 'Content contain foo and bar',
     1549                'post_excerpt' => 'Excerpt contain foo, bar and baz',
     1550            )
     1551        );
     1552
     1553        $request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
     1554        $request->set_param( 'search', 'foo bar' );
     1555        $request->set_param( 'search_columns', array( 'post_title' ) );
     1556        $response = rest_get_server()->dispatch( $request );
     1557        $this->assertSame( 200, $response->get_status(), 'Response should have a status code 200.' );
     1558        $data = $response->get_data();
     1559        $this->assertCount( 1, $data, 'Response should contain one result.' );
     1560        $this->assertSame( $id1, $data[0]['id'], 'Result should match expected value.' );
    15281561    }
    15291562
  • trunk/tests/phpunit/tests/rest-api/wpRestMenuItemsController.php

    r55210 r55248  
    148148        $this->assertArrayHasKey( 'per_page', $properties );
    149149        $this->assertArrayHasKey( 'search', $properties );
     150        $this->assertArrayHasKey( 'search_columns', $properties );
    150151        $this->assertArrayHasKey( 'slug', $properties );
    151152        $this->assertArrayHasKey( 'status', $properties );
  • trunk/tests/qunit/fixtures/wp-api-generated.js

    r55132 r55248  
    396396                            "required": false
    397397                        },
     398                        "search_columns": {
     399                            "default": [],
     400                            "description": "Array of column names to be searched.",
     401                            "type": "array",
     402                            "items": {
     403                                "enum": [
     404                                    "post_title",
     405                                    "post_content",
     406                                    "post_excerpt"
     407                                ],
     408                                "type": "string"
     409                            },
     410                            "required": false
     411                        },
    398412                        "slug": {
    399413                            "description": "Limit result set to posts with one or more specific slugs.",
     
    17531767                            "required": false
    17541768                        },
     1769                        "search_columns": {
     1770                            "default": [],
     1771                            "description": "Array of column names to be searched.",
     1772                            "type": "array",
     1773                            "items": {
     1774                                "enum": [
     1775                                    "post_title",
     1776                                    "post_content",
     1777                                    "post_excerpt"
     1778                                ],
     1779                                "type": "string"
     1780                            },
     1781                            "required": false
     1782                        },
    17551783                        "slug": {
    17561784                            "description": "Limit result set to posts with one or more specific slugs.",
     
    28322860                            },
    28332861                            "default": [],
     2862                            "required": false
     2863                        },
     2864                        "search_columns": {
     2865                            "default": [],
     2866                            "description": "Array of column names to be searched.",
     2867                            "type": "array",
     2868                            "items": {
     2869                                "enum": [
     2870                                    "post_title",
     2871                                    "post_content",
     2872                                    "post_excerpt"
     2873                                ],
     2874                                "type": "string"
     2875                            },
    28342876                            "required": false
    28352877                        },
     
    35443586                            "required": false
    35453587                        },
     3588                        "search_columns": {
     3589                            "default": [],
     3590                            "description": "Array of column names to be searched.",
     3591                            "type": "array",
     3592                            "items": {
     3593                                "enum": [
     3594                                    "post_title",
     3595                                    "post_content",
     3596                                    "post_excerpt"
     3597                                ],
     3598                                "type": "string"
     3599                            },
     3600                            "required": false
     3601                        },
    35463602                        "slug": {
    35473603                            "description": "Limit result set to posts with one or more specific slugs.",
     
    43404396                            "required": false
    43414397                        },
     4398                        "search_columns": {
     4399                            "default": [],
     4400                            "description": "Array of column names to be searched.",
     4401                            "type": "array",
     4402                            "items": {
     4403                                "enum": [
     4404                                    "post_title",
     4405                                    "post_content",
     4406                                    "post_excerpt"
     4407                                ],
     4408                                "type": "string"
     4409                            },
     4410                            "required": false
     4411                        },
    43424412                        "slug": {
    43434413                            "description": "Limit result set to posts with one or more specific slugs.",
     
    64896559                                "title"
    64906560                            ],
     6561                            "required": false
     6562                        },
     6563                        "search_columns": {
     6564                            "default": [],
     6565                            "description": "Array of column names to be searched.",
     6566                            "type": "array",
     6567                            "items": {
     6568                                "enum": [
     6569                                    "post_title",
     6570                                    "post_content",
     6571                                    "post_excerpt"
     6572                                ],
     6573                                "type": "string"
     6574                            },
    64916575                            "required": false
    64926576                        },
Note: See TracChangeset for help on using the changeset viewer.