How to Expand Search to Custom Fields in WordPress

Posted on

The default WordPress search facility does a reasonable job of going through your post titles and content for your search terms. Personally, I find it rather insufficient since it doesn’t take into consideration spread out terms, misspellings, and other contextual information. But it’s good enough for basic search functionality. However, it doesn’t extend its base to include custom fields. Of course, only WordPress back end users would require this kind of functionality. But its lack can be a major block if you really need it.

There are plenty of plugins that either extend the regular WordPress search, or create their own search tool to allow you to filter your results by custom fields. However in this article, I’m going to provide a solution that allows you to do this without a plugin. By default, the code I give you below will search both custom field values as well as custom keys. But you can modify it so that it only searches one or the other.

Extending Search to Custom Fields

Let’s take an example where I have a post with the phrase “og_image” in the content of the post itself. In addition, I have another post with a custom field value of “og_image” as shown here:

custom field with text

The way search currently works, when I type “og_image” into the box, I only get results for the first type of post, and not the other. You can see this result below:

just one result og_image

The second post called “Hide Text from Google Snippets” isn’t included in the results because we haven’t yet told WordPress to search the custom fields. To do that, open up your functions.php file and type in the following code before the closing ?> PHP tag:

function custom_search_where($pieces) {
	if (is_search()) {
		global $wpdb;
		$keywords = get_query_var('s');
		$query = "";
		$query .= " (custom_table.meta_value  LIKE '%{$keywords}%') OR ";
		$query .= " (custom_table.meta_key  LIKE '%{$keywords}%') OR ";

		if (!empty($query)) {
			$pieces['where'] = str_replace("(((wp_posts.post_title LIKE '%", "( {$query} ((wp_posts.post_title LIKE '%", $pieces['where']);
			$pieces['join'] = $pieces['join'] . " INNER JOIN {$wpdb->postmeta} AS custom_table ON ({$wpdb->posts}.ID = custom_table.post_id)";
			$pieces['groupby'] = "{$wpdb->posts}.ID";
	return ($pieces);
add_filter('posts_clauses', 'custom_search_where', 20, 1);

If you don’t yet know how to add custom code to WordPress like this, don’t worry! You can read my earlier tutorial on how to do the same.

The snippet above includes both the custom field’s name (key), as well as the value. You can see in the screenshot below how the same search query as before now also includes the second post which included the “og_image” in the custom field name.

second result visible

If you want to limit your search only to custom field values (or names/keys), simply delete the appropriate line marked in bold in the code above. The first line includes the search for the custom field value, and the second one includes it for the key.

We achieve this using the “post_clauses” filter which allows us to hook into the “where” and “join” clauses of the basic SQL query in order to make the requisite modifications.

You can even restrict this to admins only by inserting a “is_admin” clause right at the very beginning of the function like this:

if ( ! is_admin() )
    return $pieces;

This method of searching custom field values and keys allows you to do without another plugin that will simply slow down your site. In fact, you can build on the code given here by specifying new ORDER BY clauses if you know what you’re doing. Also keep in mind that this snippet doesn’t “explode” the search terms, so you have to type in the exact string that you want without mistakes. Other than that, it’s a great way to extend your search functionality!

Leave a Reply

Your email address will not be published. Required fields are marked *