Extend the default Wordpress Search

Hi,

Just a short snippet I have written for one of my WordPress-based web site.
By default, the WordPress search only checks post titles and post contents. What I wanted to do was to also search post tags and post comments.

I first tried to use an existing plugin, like Search Everything. But it was searching for sentences. As an example, if I searched for “Eclipse Menu”, it was searching the exact expression. And not all the posts that contain both key words “Eclipse” and “Menu”.

I spent a lot of time to search an existing solution.
I finally created my own one. You can add the following code in the functions.php file of your theme.

function my_smart_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 (
			(wp_posts.post_title LIKE '%$tag%')
			OR (wp_posts.post_content LIKE '%$tag%')
			OR EXISTS
			(
				SELECT * FROM wp_comments
				WHERE comment_post_ID = wp_posts.ID
					AND comment_content LIKE '%$tag%'
			)
			OR EXISTS
			(
				SELECT * FROM wp_terms
				INNER JOIN wp_term_taxonomy
					ON wp_term_taxonomy.term_id = wp_terms.term_id
				INNER JOIN wp_term_relationships
					ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
				WHERE taxonomy = 'post_tag'
					AND object_id = wp_posts.ID
					AND wp_terms.name LIKE '%$tag%'
			)
		)";
	}

    return $search;
}

add_filter( 'posts_search', 'my_smart_search', 500, 2 );

With this function, you customize the search.
When there are several key words, you search for posts which contain both of them, no matter if they are in the post title, content, tags or comments.

25 thoughts on “Extend the default Wordpress Search

  1. Hey there,

    Many thanks for sharing this!!
    After hours of research, your snippet enabled me to tweak my search query as I whished.

    As I no longer use “content / main wordpress editor” but rather split content into fields, I no longer got results -exept for titles- in search queries.
    Hence I needed to encompass custom fields (I use ACF : http://www.advancedcustomfields.com/).

    Here is the gist in case anyone could ever need it (any feedback on this is more than welcome) : https://gist.github.com/kartonnade/5924863

    Cheers from Paris!

  2. Thanks for sharing this code, I’ve made best use of it in my own theme.

    To get the search prefix-independent, I would propose to write

    $search .= ” AND (
    ($wpdb->posts.post_title LIKE ‘%$tag%’)
    OR ($wpdb->posts.post_content LIKE ‘%$tag%’)
    OR EXISTS
    (
    SELECT * FROM $wpdb->comments
    WHERE comment_post_ID = $wpdb->posts.ID
    AND ( comment_content LIKE ‘%$tag%’
    OR comment_author LIKE ‘%$tag%’ )
    )
    OR EXISTS
    (
    SELECT * FROM $wpdb->terms
    INNER JOIN $wpdb->term_taxonomy
    ON $wpdb->term_taxonomy.term_id = $wpdb->terms.term_id
    INNER JOIN $wpdb->term_relationships
    ON $wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id
    WHERE taxonomy = ‘post_tag’
    AND object_id = $wpdb->posts.ID
    AND $wpdb->terms.name LIKE ‘%$tag%’
    )
    )”;

    The $wpdb-> gets you to the right tables, even in a multisite environment. Oh, and I’ve included the search for comment author names, too.

  3. Looks like the exact code I need!
    I haven’t done this before, so I wonder where I write the search keywords?
    How do I use this. I have this in functions.php, but now, what do I do?

    Thanks

    1. Once you have copied it in your functions.php file, then every time a user will perform a search on your blog, this function will be called. It customizes where and what to search when a user uses the search bar of your blog.

      1. Okey! but I am writing my own code for this. And I have only used wp_query to setup queries, but I don’t think that is the way to do it.
        How do I write a query in code, to work with this?

      2. Sorry, I am not sure to understand what you want to do. Basically, you want to inject new keywords in the search query? If so, I would just print the current search query (the $search variable) and see what changes should be done.

        Or do you mean perform a search independently of a user action?

  4. No problem, I am happy you trying to help me with this =)

    What I mean is that I do not use any widget or something to show some search field.
    I have with html code, created a input search field, which I get with post in PHP code.

    But now I don’t know how to make search query with that fields, data. I have your code in my functions.php

    1. I’m not sure to understand the question.
      Basically, if you want to customize the WordPress search, you have to copy the sample code in your plugin’s main file (and modify it acording to your needs).

    1. I have not checked WordPress’ database schema for a long time.
      Somehow, the answer seems in your question. Or maybe you only have an issue with SQL syntax.

    2. If I understand what you’re asking, I just added the following to the query:

      OR EXISTS
      (
      SELECT * FROM wp_postmeta
      WHERE post_id = wp_posts.ID
      AND wp_postmeta.meta_value LIKE ‘%$tag%’
      )

  5. I just tried out your script and it worked great. Good job and thank you! I just modified it a little for my specific need. One question though… If I perform a search with multiple terms and one of them doesn’t exist, no results are shown, even if all other terms do exist. How can I go about ignoring any that don’t exist so it will still show results?

    1. When you say “term”, do you mean a word in the search query, or a term as in WordPress’ taxonomy?
      If it is the first case, then the default search should work (you might want to customize where to search, but not what). Because you do not want to find all the words (AND expression) but only some of them (OR). In fact, a OR expression is much more simple. You can reduce the length of the SQL query. That will improve the performances of your search.

      1. Yes, I was referring to the search query. I thought about that after I posted it and figured it would be a little confusing.

        I stripped down the query a bit and I tried switching the AND to an OR among other things and either get no results, or literally everything. Even auto saved versions of posts. Not sure what I’m doing wrong.

      2. Just so that I understand. Starting from the casual search, what do you want in addition?
        Given a set of words, you want to find any post that contains any term in the set of words. Is that right? And you want to search for one of these terms in the title, content, comment and tags?

  6. I’ve added custom data to the `wp_postmeta` table. All I want to search is the post title and `meta_value` within the `wp_postmeta` table. Something like this:

    $search .= ” AND (
    (wp_posts.post_title LIKE ‘%$tag%’)
    OR EXISTS
    (
    SELECT * FROM wp_postmeta
    WHERE post_id = wp_posts.ID
    AND meta_value LIKE ‘%$tag%’
    )
    )”;

    If I change the first `AND` to `OR` I get 4 pages of results when I should only get one result. It works using the code above, but if there is a search term that doesn’t exist, no results are returned, even if there are other search terms that do exist. I hope that makes sense.

  7. Hi.
    I just found your blog, and I need a code exactly like this to extend searching on wordpress. Unfortunately it’s not really working for me. I have a unique attribute that I would like to include in the search. The name is “gyariszam”, and one of the values is “415.00-6200-007A”. The attribute is in the wp_terms table, I can see that the “name” value is that number, but when I search for it, nothing. I see it in the code that it’s also searching in that table. What can be the problem?
    Thanks

  8. Thanks! This is such a life-saver. It should the default behavior. With all the talk about not use categories for less frequent topics, only tagging them… going around. It is all useless unless you can search for those tags. Which is right here. Thanks a ton!

  9. WordPress filters out “stop words” like “a”, “the”, “of”, etc. and stores the real search terms in the search_terms query_var. This gives us an opportunity to simplify this code a bit.

    Instead of exploding the ‘s’ query_var, you can get the search_terms directly from query_vars. So you can actually completely remove lines 7-10. Then the foreach loop becomes:

    “`
    foreach ($wp_query->query_vars[‘search_terms’] as $tag) { /* … */ }
    “`

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s