Extending the site search to include a single custom field

I have the followign code in my functions.php file

function __adapted_search_function($search, $query) {
  if(is_admin() || !$query->is_main_query() || !$query->is_search)
    return; //determine if we are modifying the right query

  global $wpdb;
  $search_term = $query->get('s');
  $search = ' AND (';

  //point 1
  $search .= "($wpdb->posts.post_title LIKE '%$search_term%')";

  //need to add an OR between search conditions
  $search .= " OR ";

  //point 2
  $search .= "($wpdb->posts.post_excerpt LIKE '%$search_term%')";

  //need to add an OR between search conditions
  $search .= " OR ";

  //point 3
  $search .= "($wpdb->postmeta.meta_key = 'mcb-product' AND $wpdb->postmeta.meta_value LIKE '%$search_term%')";

  //add the filter to join, sql will error out without joining the tables to the query
  add_filter('posts_join', '__custom_join_tables');   


  return $search . ') ';
}

function __custom_join_tables($joins) {
  global $wpdb;
  $joins = "JOIN $wpdb->postmeta ON ($wpdb->postmeta.post_ID = $wpdb->posts.ID)";
  return $joins;
}

Which I was hoping would search only the post title, excerpt and also a single custom field.

Read More

It works if I remove the join but really need to keep that included, can anyone see where I have gone wrong?

Related posts

2 comments

  1. I managed to resolve by extending the query

    function extend_search( $search, &$wp_query ) {
        global $wpdb;
    
        if ( empty( $search ))
            return $search;
    
        $terms = $wp_query->query_vars[ 's' ];
        $exploded = explode( ' ', $terms );
        if( $exploded === FALSE || count( $exploded ) == 0 )
            $exploded = array( 0 => $terms );
    
        $search = '';
        foreach( $exploded as $tag ) {
            $search .= " AND (
                ($wpdb->posts.post_title LIKE '%$tag%')
                OR ($wpdb->posts.post_excerpt LIKE '%$tag%')
                OR EXISTS
                (
                    SELECT * FROM $wpdb->postmeta
                    WHERE post_ID = pl_posts.ID
                        AND meta_key = '--KEY--'
                        AND meta_value LIKE '%$tag%'
                )
    
            )";
        }
    
        return $search;
    }
    
  2. pre_get_posts only takes one parameter but you seems to be using it as if it were posts_where. That isn’t really how pre_get_posts works. You have to modify the $query object passed into it, not construct and return a SQL clause.

    It isn’t possible for me to easily test this but I think the hook you want is either posts_where or the posts_search filter which logically makes the most sense.

    add_action('posts_where', '__adapted_search_function',1,2);
    

    or

    add_action('posts_search', '__adapted_search_function',1,2);
    

    You may need to modify the code but changing the hook you are using is key.

Comments are closed.