I’m trying to expand the scope of the default WP search algorithm. What am I doing wrong?

I’m aware that there is a plugin that will do this, but it is too broad for what I would like to add.

Below is my first attempt at expanding the search to query custom fields, but it’s returning nothing. I’ve written code in the past to create queries, but this is my first time trying to modify a pre-existing one and I’m clearly missing something.

function st_search_all( $query ) {
    if ( $query->is_search ) {

        $query->set( 'post_type', array( 'page', 'attachment', 'post' ) );
        $query->set( 'post_status', 'inherit' );
        $query->set( 'meta_query', array(
                array( 
                    'key'       => '_st_plaintext',
                    'value'     => "%{$query->get('s')}%",
                    'compare'   => 'LIKE'
                ),
                array(
                    'key'       => 'Training Classes',
                    'value'     => "%{$query->get('s')}%",
                    'compare'   => 'LIKE'
                ),
                array(
                    'key'       => 'External Content',
                    'value'     => "%{$query->get('s')}%",
                    'compare'   => 'LIKE'
                )
            )
        );
    }
    return $query;
}
add_filter( 'pre_get_posts', 'st_search_all' );

The other thing is, I will need to include a search of the main content of pages/posts also, which this code doesn’t attempt. What would that meta key be if I wanted to include it within the meta_query?

EDIT: Dumping the resulting query string after making @s_ha_dum’s suggested changes (removing %s, adding the OR relationship, and removing the post type from the post_type) is returning the following (indention added). I’m not extremely familiar with SQL, but it appears that the query generated is requiring the title or content to match the query before it will even check any of the added fields. Am I misreading something? If not, how can I modify that through the WP API?

string(494) " 
  AND ((
        (dev_posts.post_title LIKE '%SBIR%') OR 
        (dev_posts.post_content LIKE '%SBIR%')
  )) AND 
    (dev_posts.post_password = '') AND 
    dev_posts.post_type IN 
    ('page', 'attachment') AND 
    (dev_posts.post_status="inherit") AND 
    ((dev_postmeta.meta_key = '_st_plaintext' AND 
      CAST(dev_postmeta.meta_value AS CHAR) LIKE '%SBIR%') OR 
      (mt1.meta_key = 'Training Classes' AND 
        CAST(mt1.meta_value AS CHAR) LIKE '%SBIR%') OR 
      (mt2.meta_key = 'External Content' AND 
        CAST(mt2.meta_value AS CHAR) LIKE '%SBIR%') )
"

1 Answer
1

Add this temporarily to your functions.php. It will break things but you can see the WHERE clause. Be sure to remove it because things won’t work right if you leave it there.

function dump_where($w){
 var_dump($w);
}
add_filter('posts_where','dump_where');

The first thing you should notice is that the % signs get escaped. Remove those and WordPress will add them back unescaped. If you only wanted one of those at the beginning or the end, but not both, this might be trickier. Luckily you don’t.

Second, the default relationship appears to be AND so unless you want to enforce a match on every one of those meta_keys you should add a relationship to your meta query.

 $query->set( 'meta_query', array(
            'relation' => 'OR',
            array( 
                'key'       => '_st_plaintext',
                /* and the rest of your query */

Third, post content is already searched.You shouldn’t have to do anything to make that happen. Take a look at the WHERE clause my temporary code dumps and you should be able to see where that happens.

http://codex.wordpress.org/Class_Reference/WP_Query

Leave a Comment