Query post_title OR meta_query

I’m searching for a solution for my WordPress custom query problem.
I have a search-form where the user can input some text, this text can be a word from the post_title or an meta_value (Company ID).

I need to search the string in post_title OR the meta_key-Field “id-number”,
but I also have some other additional search params.
These are my Args for the WP_Query:

Read More
Array(
    [post_type] => company
    [pagination] => 1
    [posts_per_page] => 10
    [paged] => 1
    [meta_query] => Array
        (
            [relation] => AND
            [0] => Array
                (
                    [0] => Array
                        (
                            [key] => id-number
                            [value] => FOOBAR
                        )

                    [1] => Array
                        (
                            [key] => post_title
                            [value] => FOOBAR
                            [compare] => LIKE
                        )

                    [relation] => OR
                )

            [1] => Array
                (
                    [relation] => AND
                    [0] => Array
                        (
                            [0] => Array
                                (
                                    [key] => country
                                    [value] => USA
                                )
                            [relation] => OR
                        )
                )
        )
)

Array[meta_query][0][1] (post_title) is only a placeholder – i know that can’t work, but how can i search for
(id-number OR post_title) AND (all other vars...)

Related posts

Leave a Reply

2 comments

  1. Doing this with WP_Query isn’t directly possible. The query is constructed from the arguments in the monstrous (over 1000 lines long) WP_Query::get_posts method (see wp-includes/query.php) as mostly a long series of concatenations of AND statements to a $where variable.1

    Now, you can hook into a number of filters to customize how that variable (which holds the SQL for the query) is constructed. In your case, one of the following might be appropriate:

    • posts_search: Lets you change how search queries are interpreted (coming from WordPress built-in/standard search form). Then you’d manually construct your where query as needed from the search query.
    • posts_where: Lets you change the entire where query — for every query, though.

    Using filter, you’d not really send arguments to WP_Query and construct it in “the normal way” but override how the SQL WHERE query is constructed. You might be better off just running your own SQL query entirely. The codex has an article Displaying Posts using a Custom Select Query that details how this can be done.


    1. WP_Query is not at all a complete ORM but a dedicated class for taking query string variables and filtering posts based on those rules.

  2. There’s a ready-to-use copy & paste solution by Adam Balee – and by short I mean 50 lines including comments.

    It uses just three simple hooks:

    • posts_join to JOIN-add meta_value fields to the query
    • posts_where to alter WHERE query part and add meta_value LIKE % just after the post_title LIKE statement
    • posts_distinct hook to remove duplicates created by previously added JOIN statement

    To make happy the stackoverflow purists I will paste Adams’s solutions here but feel free to visit Adam’s blog for detailed explanation.

    <?php
    /**
     * Extend WordPress search to include custom fields
     *
     * https://adambalee.com
     */
    
    /**
     * Join posts and postmeta tables
     *
     * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_join
     */
    function cf_search_join( $join ) {
        global $wpdb;
    
        if ( is_search() ) {    
            $join .=' LEFT JOIN '.$wpdb->postmeta. ' ON '. $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
        }
    
        return $join;
    }
    add_filter('posts_join', 'cf_search_join' );
    
    /**
     * Modify the search query with posts_where
     *
     * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_where
     */
    function cf_search_where( $where ) {
        global $pagenow, $wpdb;
    
        if ( is_search() ) {
            $where = preg_replace(
                "/(s*".$wpdb->posts.".post_titles+LIKEs*('[^']+')s*)/",
                "(".$wpdb->posts.".post_title LIKE $1) OR (".$wpdb->postmeta.".meta_value LIKE $1)", $where );
        }
    
        return $where;
    }
    add_filter( 'posts_where', 'cf_search_where' );
    
    /**
     * Prevent duplicates
     *
     * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_distinct
     */
    function cf_search_distinct( $where ) {
        global $wpdb;
    
        if ( is_search() ) {
            return "DISTINCT";
        }
    
        return $where;
    }
    add_filter( 'posts_distinct', 'cf_search_distinct' );