When querying a combination of posts and other meta fields, is there a better solution than directly modifying the WHERE value?

This question is a follow up to a question I recently asked.

I’ve implemented what seemed to be the only solution, and it seems to work (YAY!). I just need to verify that:

Read More
  1. This is really the only way to modify the query to match with a match to the (post_title OR post_content OR any one of the other meta fields desired.
  2. That this won’t mess with other queries not related to searches. The regex used below, I think, would generally only be used for search, but what chance is there of it matching some other functionality in the core or a plugin. I realize with plugins anything could happen, but I’m especially concerned about conflicts in the WP Core.
  3. I considered doing all the work in the posts_where filter, but thought it was best to rely on modifying $query as much as possible and limit direct modification of WHERE. Is that a reasonable choice?

In any event, here is the function used to modify the WHERE:

function st_posts_where( $where ){
    if( !is_admin() ){
        global $wpdb;
        $ptn = "/(s*AND ((({$wpdb->prefix}posts.post_title LIKE '%.*%')s+ORs+(".
               "{$wpdb->prefix}posts.post_content LIKE '%.*%')))s+)AND(.*)/";
        $where = preg_replace( $ptn, "$1OR$2", $where );
    }
    return $where;
}
add_filter( 'posts_where' , 'st_posts_where' );

Additionally, here is the function that the original question was addressing, which is still being used alongside the above one.

function st_search_all( $query ) {
    if( !is_admin() && $query->is_search ) {
        $query->set( 'post_type', array( 'page', 'attachment' ) );
        $query->set( 'post_status', 'inherit' );
        $query->set( 'meta_query', array(
            'relation' => 'OR',
            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' );

All of this in combination results in the following query result which achieves the desired result:

AND (((dev_posts.post_title LIKE '%sbir%') 
  OR (dev_posts.post_content LIKE '%sbir%')))  
OR 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%'))

Related posts

Leave a Reply

1 comment