Extend search with predefined search query strings

Almost every WordPress developer had some annoyance with the basic search functionality of WordPress. Today I customised the search functionality for one of my projects so I am able to add a list of comma separated search query strings to a post where I want it to be found on. So for example a product like “bicycle” needs to be found on “bike”.

To achieve this I first hooked into the SQL query of a search request trough the posts_join and posts_where functions.

Post meta table join

To use post meta data in combination with a post I had to make a connection between the two tables using a left join.

/**
 * Modifies search query join clause
 *
 * Adds a left join for post meta
 */
function search_posts_join( $join ) {

   global $wp_query, $wpdb;

   // Searching and not in admin
   if ( ! is_admin() && $wp_query->is_search && isset( $wp_query->query_vars['s'] ) ) {
      $join .= "LEFT JOIN $wpdb->postmeta ON $wpdb->posts.ID = $wpdb->postmeta.post_id";
   }
   return $join;

}
add_action( 'posts_join', 'search_posts_join' );

Changing the where clause

Now the connection with the post meta table is made I am able to compare the value of the post meta field “search_queries” to the search query string. The where clause searches for similarities with the post title as well, so you have the chance on a match from both sides.

/**
 * Modifies search query where clause
 *
 * Changes the where clause so that it checks a pre defined search queries
 * stored in a meta value.
 */
function search_posts_where( $where ) {

   global $wp_query, $wpdb;

   // Searching and not in admin
   if ( ! is_admin() && $wp_query->is_search && isset( $wp_query->query_vars['s'] ) ) {

      // Store search query
      $s = $wp_query->query_vars['s'];

      // Write the where clause from scratch
      // Check post title or comma seperated meta value with key 'search_queries'
      $where  = " AND (($wpdb->posts.post_title LIKE '%$s%') OR ($wpdb->postmeta.meta_key = 'search_queries' AND $wpdb->postmeta.meta_value LIKE '%$s%'))";

      // Only posts from 'products' post type
      $where .= " AND wp_posts.post_type = 'products'";

      // Published posts only
      $where .= " AND wp_posts.post_status = 'publish'";

      // Because of the join, otherwise multiple same results
      $where .= " GROUP BY $wpdb->posts.ID";
   }

   return $where;
}
add_action( 'posts_where', 'search_posts_where' );

Add post meta field

I created a meta box with a large field to store the comma separated search query strings. In my case a added this metabox and field to my “products” custom post type.

// Adds search settings metabox
function add_search_metabox() {
   add_meta_box( 'search_settings_metabox', __( 'Search settings', 'theme' ), 'search_settings_metabox', 'theme' );
}
add_action( 'add_meta_boxes', 'add_search_metabox' );

// Adds search settings metabox fields
function search_settings_metabox( $post ) {

   $search_queries = ( get_post_meta( $post->ID, 'search_queries', true ) ) ? get_post_meta( $post->ID, 'search_queries', true ) : '';

   $html = '<table class="form-table">';
      $html .= '<tbody>';
         $html .= '<tr>';

            $html .= '<th scope="row">';
               $html .= '<label for="search_queries_field">' . __( 'Search queries', 'gtp_translate' ) . ':</label>';
            $html .= '</th>';

            $html .= '<td>';
               $html .= '<input type="text" name="search_queries" id="search_queries_field" class="large-text" value="' . $search_queries . '">';
               $html .= '<p class="description">' . __( 'Comma seperated strings to extend the matching search queries', 'gtp_translate' ) . '</p>';
            $html .= '</td>';

         $html .= '</tr>';
      $html .= '</tbody>';
   $html .= '</table>';

   echo $html;
}

Store search query strings

Last I needed to make the functionality to store the comma separated search query strings. I added little checkings on this save function. You can make this more extensive if you want.

// Saves search settings metabox fields
function save_search_settings_metabox( $post_id ) {

   if ( ! empty( $_POST['search_queries'] ) ) {
      update_post_meta( $post_id, 'search_queries', $_POST['search_queries'] );
   }

}
add_action( 'save_post_products', 'save_search_settings_metabox' )