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' );
Hi Robbert,
Nice post. I tried to copy/paste the “posts_where” hook. It works fine ! thanks
Now, I would like to order the search ascending, so I add
$where .= “ORDER BY $wpdb->posts.post_title ASC”;
No idea why, but with this new order, no posts are found
Any help ?
Thanks
Olivier