Gladly I’ve written two plugins for that yesterday:
Filter/Core
That’s what a search query part looks like inside the posts_search
filter:
' AND (((wp_XX_posts.post_title LIKE '%test%') OR (wp_XX_posts.post_content LIKE '%test%'))) '
where wp_XX_
is just the $wpdb->prefix
for my WPSE test site inside my local MU installation.
Plugin #1 – drop searching post types that we don’t need.
Here’s a plugin modifying the searched post types, as this is needed often.
<?php
/** Plugin Name: (#66815) »kaiser« Limit search query post types */
/**
* Alter the searched post types
*
* @param object $query
* @return object $query
*/
add_action( 'pre_get_posts', 'wpse66815_pre_get_posts' );
function wpse66815_pre_get_posts( $query )
{
if ( $query->is_main_query() )
{
$query->set( 'post_type', 'YOUR_POST_TYPE' );
}
return $query;
}
Plugin #2 – modify the search string
Now, that we know how the default search string for the post title and content looks, we just have to rebuild it the way we need it:
<?php
/** Plugin Name: (#66815) »kaiser« Modify search query string */
function wpse66815_search_query_string( $search_string )
{
global $wpdb;
$searched_for = preg_match_all(
// Match a prefix (%), but exclude it from the capture
// Any character, any number of repetitions
// Match a suffix (%), but exclude it from the capture
"/(?<=\%)(.*)(?=\%)/",
$search_string,
$search_string_matches
);
// We only need one element
$searched_for = array_shift( $search_string_matches );
// Now we need to search for [LETTERS (min 1)][NUMBER (zero or more)][CHARACTER (zero or more)]
preg_match_all(
"/([^a-zA-Z][\d+]*[-_ ]*)/",
$searched_for,
$string_part_matches
);
// Here we now got matches - if not, we can simply abort and leave the default
$searched_for = array_shift( $string_part_matches );
if ( empty( $searched_for ) )
return $search_string;
// Finally we need to split the string by all parts that are allowed
// YOU NEED TO EDIT MY ANSWER HERE AND FILL IN WHAT WORKS FOR YOU
$keywords = preg_split(
"/([\s]*[\d+]*[-_ ]*)/",
$searched_for,
-1, // 0 & -1 are NO limit
PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE
);
// Now loop and build an array for further processing
// Our first search string is - of course - the default string
$string_parts = array( $search_string );
foreach ( $keywords as $keyword )
{
$new_string_parts[] = $GLOBALS['wpdb']->prepare(
" AND ((%s.post_title LIKE '%s') OR (%s.post_content LIKE '%s')) ",
$wpdb->posts,
$wpdb->esc_like( $keyword ),
$wpdb->posts,
$wpdb->esc_like( $keyword )
);
}
// Now lets glue them together, return and see what we get...
return implode( " ", $new_string_parts );
}
This 2nd plugin is untested, as my needs are different and I guess some of the regexes are not completely what you need – you’ll have to fix that and update this answer (this is your part in “giving the community back” in this Q/A). A nice tool to build regex, that I just found, is Expresso. It’s damn ugly (as the web presence), but extremely helpful.