Send us your brain! Let us do the thinking for you.
 

Some friends of mine that have started offering custom WordPress designed sites and consulting hit me up a couple of weeks ago for some help. They had a site for a client that was utilizing custom fields to provide some additional CMS-like functionality to WordPress and had hit a snag. Their custom fields were not being searched.

Why custom fields in the first place? Using the custom fields allowed them to add deck, byline, bio, kicker text that their custom template was checking for and formatting appropriately. It really makes life easier when you are dealing with clients that come from the standard publishing background. Not to mention how much easier it is to apply a global formatting change to those elements since you don't have to manually edit each post body.

Here's where I came in. The client noticed that when they entered in a post authors' name(custom field, byline) no search results were being returned. So they called me up for help.

I did some quick digging online and found a few blog posts that had people writing custom queries to fetch the search information. Further digging revealed the WordPress filters that are responsible for building the SQL query for the search: posts_join, posts_groupby, posts_where, and posts_request. For those wanting to play around, the posts_request filter is likely the first place you will want to look. I tossed the following code into our plugin and was able to echo out the entire sql request that was being made for each page:

function custom_search_request($request) { echo($request); return($request); } add_filter('posts_request', 'custom_search_request');

Once that is done, a few page views will let you know what WordPress is doing internally to pull up the posts for each page. You can then update the above to work with the other filters to show you how everything is assembled.

From there, it was a matter of looking at the existing code in the get_posts funciton in wp-includes/query.php and figuring out what additional query information needs to be passed in the filters. Since that function is the densest code I've seen yet in WordPress, I won't go into all of the details. I'll leave that to folks who have good eyes and brave hearts.

When putting it all together, there are several things to note. Always check to make sure that you are currently in a search page and return the original query snippet if you are not. The example I have below adds the custom fields: bio, byline, kicker, and deck.

function custom_search_join($join) { if ( is_search() && isset($_GET['s'])) { global $wpdb; $join = " LEFT JOIN $wpdb->postmeta ON $wpdb->posts.ID = $wpdb->postmeta.post_id "; } return($join); } add_filter('posts_join', 'custom_search_join'); function custom_search_groupby($groupby) { if ( is_search() && isset($_GET['s'])) { global $wpdb; $groupby = " $wpdb->posts.ID "; } return($groupby); } add_filter('posts_groupby', 'custom_search_groupby'); function custom_search_where($where) { $old_where = $where; if (is_search() && isset($_GET['s'])) { global $wpdb; $customs = Array('bio', 'byline', 'kicker', 'deck'); $query = ''; $var_q = stripslashes($_GET['s']); if ($_GET['sentence']) { $search_terms = array($var_q); } else { preg_match_all('/".*?("|$)|((?<=[\\s",+])|^)[^\\s",+]+/', $var_q, $matches); $search_terms = array_map(create_function('$a', 'return trim($a, "\\"\'\\n\\r ");'), $matches[0]); } $n = ($_GET['exact']) ? '' : '%'; $searchand = ''; foreach((array)$search_terms as $term) { $term = addslashes_gpc($term); $query .= "{$searchand}("; $query .= "($wpdb->posts.post_title LIKE '{$n}{$term}{$n}')"; $query .= " OR ($wpdb->posts.post_content LIKE '{$n}{$term}{$n}')"; foreach($customs as $custom) { $query .= " OR ("; $query .= "($wpdb->postmeta.meta_key = '$custom')"; $query .= " AND ($wpdb->postmeta.meta_value LIKE '{$n}{$term}{$n}')"; $query .= ")"; } $query .= ")"; $searchand = ' AND '; } $term = $wpdb->escape($var_q); if (!$_GET['sentense'] && Count($search_terms) > 1 && $search_terms[0] != $var_q) { $search .= " OR ($wpdb->posts.post_title LIKE '{$n}{$term}{$n}')"; $search .= " OR ($wpdb->posts.post_content LIKE '{$n}{$term}{$n}')"; } if (!empty($query)) { $where = " AND ({$query}) AND ($wpdb->posts.post_status = 'publish') "; } } return($where); } add_filter('posts_where', 'custom_search_where');

With all of that done, I added the above code into their plugin and the new fields were being used in the search. It should be noted that the code is adding significant overhead to the post searching. In the above example, each keyword in a search generates 5 SQL LIKE statements instead of 1. In addition, these LIKEs are being performed across joined tables. Because this was for a small website, I do not know the full performance trade-off of the changes. For larger sites, I'll almost always advocate using an external search engine such as Google or Sphinx.

Tags: , ,
Attachments:
 
 
30 Comments…
stefanomavilio.com » Blog Archive » custom field search function Says: January 30th, 2009 at 6:25 pm

[...] http://www.braindonor.net/coding/wordpress-custom-field-search-plugin/102/ [...]

 

maxaud Says: January 30th, 2009 at 11:09 pm

Good work.

I’m planning on building out a site that will use custom fields extensively for each post and I need a good way to search each custom field used.

Example:
Real Estate Listing website that uses custom fields for State/Bedrooms/Bathrooms/etc.

How would one make a search to filter through each one of those custom fields to find a match that matches each custom field variable specified?

Let me know if I haven’t made myself clear as to what I’m trying to accomplish.

Thanks.
Dustin

 

John Hoff Says: January 30th, 2009 at 11:44 pm

You would be able to accomplish it by adding the search filters to a plugin and updating the custom_search_where function to include your custom fields like so:

$customs = Array('State', 'Bedrooms', 'Bathrooms');

The custom_search_where function I wrote iterates over this array and adds the needed logical conditions to the SQL query of searches.

I highly recommend that you put the filters into a plugin by themselves so that you can easily enable/disable the functionality without having to modify your theme.

Hope that helps.

 

Loco Says: March 12th, 2009 at 2:50 am

HI, nice post.

How can I change the search just for custom fields or categories?

Thanks

 

John Hoff Says: March 12th, 2009 at 8:55 am

How can I change the search just for custom fields or categories?

If you mean searching only the custom fields and not the post_title or post_content, you would drop the inclusion of the OR clauses that add the post_title and post_content to the SQL query.

If you mean searching the category names, then you would have to include the necessary joins on the category table.

Just remember that the search is still built around displaying posts, so it may be confusing to the end user if you avoid searching for matches in the post content.

 

Loco Says: March 12th, 2009 at 9:34 am

Ok, thanks. Both are the solution for what I’m looking for. It wont be confused for the user, the design is clear at that point. Sorry for my bad English ;)

 

Michael Montgomery Says: May 5th, 2009 at 8:33 pm

Hi John,

I’ve tried a couple of advanced search plugins to no avail. Your solution was simple to implement, even though I’m not a coding guru. It works like a charm.

Thank You

 

Andres Carvajal Says: May 12th, 2009 at 4:38 am

Hi, I’m running Sphinx search engine in my site. How can I use it to search custom fields?

 

Andres Carvajal Says: May 12th, 2009 at 4:39 am

I’m also using WordPress.
Thanks.

 

John Hoff Says: May 12th, 2009 at 5:49 am

Are you using a WordPress plugin to integrate Sphinx? Or are you having the sphinx indexer do raw SQL calls to fetch your posts?

 

Andres Carvajal Says: May 12th, 2009 at 4:04 pm

John, I’m using a WordPress plugin that replaces WordPress search with Sphinx. I found it here: http://wordpress.org/extend/plugins/wordpress-sphinx-plugin/

 

The Braindonor Network » Custom Field Searching Wordpress Using Sphinx Says: May 20th, 2009 at 7:16 pm

[...] Blog Custom Field Searching WordPress Using Sphinx posted May 20th, 2009 | by John Hoff In my previous post on implementing a custom field search in WordPress, I showed how to modify the internal SQL LIKE [...]

 

John Hoff Says: May 20th, 2009 at 7:17 pm

Sorry for the delay in answering, family has kept me very busy this week!

I added a new post to deal with this issue because a comment just wasn’t going to cut it: http://www.braindonor.net/coding-blog/custom-field-searching-wordpress-using-sphinx/199/

 

Jonah Says: June 22nd, 2009 at 9:20 pm

I need to have this functionality, but for practicalities sake, with the site I am working on, I need it to search multiple custom fields through drop down menus in the search form. Seems easy enough to intergrate, until you realize that all the custom field plugins/write ups I have found only search POSTS. I need them to search PAGES.

Any ideas?

 

John Hoff Says: June 22nd, 2009 at 9:31 pm

The default search implemented by WordPress returns both pages and posts. Both pages and posts are stored in the same database table–with a different wp_posts.post_type value. You can see this demonstrated quite easily on this site. If you search for ‘donate’, the only search result that you will get is the ‘donate a brain’ page. Any functionality you implement that searches the posts also applies to pages.

 

The Braindonor Network » Apache Optimization and NGINX Says: July 29th, 2009 at 6:50 pm

[...] WordPress friends had to hit me up for some help. These are the same friends that I helped with a Custom Field Search Plugin. They have been maintaining a community site, SuccessNet Online™, and an email mailing list [...]

 

Michelle Says: October 20th, 2009 at 2:31 pm

This is an awesome post, thankyou so much!

I do have one problem, if anyone knows how to fix it it would really save me a lot of worry. On my search results page currently I have a couple of recent posts widgets in the sidebar. This custom search code is working perfectly, but my custom query is then being used for the recent posts widgets which are just displaying the same posts as the search results.

Is there some way to “reset” the query before the sidebar gets involved?

Really excellent post though, thanks again!

 

John Hoff Says: October 20th, 2009 at 2:42 pm

What recent post plugins are you using? There should be a way to turn it off except for the full search results. I can take a look at the plugins you are using and see how it can be done.

 

Michelle Says: October 20th, 2009 at 2:52 pm

This is the plugin I’m using http://wordpress.org/extend/plugins/enhanced-recent-posts/, I have two seperate widgets showing posts from different categories.

Any help will be very helpful :D

Thanks

 

John Hoff Says: October 20th, 2009 at 3:15 pm

In the function filters I am looking to see if we are on a search results page, and including the SQL updates if we are:
if (is_search() && isset($_GET['s'])) {

What you need to do is update the filters so that they also look at the $wp_query to see if it is currently executing a search:
global $wp_query
if (is_search() && isset($_GET['s']) && isset($wp_query->query_vars['s'])) {

Once that change has been made, the custom SQL query will only be used inside of the search functionality. I tested this on a couple of pages I manage that have custom WP_QUERY calls on the search results pages, and it behaved correctly.

 

Michelle Says: October 20th, 2009 at 3:41 pm

Hmm, no change for me. I’ll just take the sidebar off the search page for now til I get it figured out, much appreciated anyway :)

 

John Hoff Says: October 20th, 2009 at 3:57 pm

I’m sorry, I misread your post. I thought you meant that the SQL was being updated for the queries inside the widgets–which was the case in the pages I tested.

Is the search page the only page you are having this issue? If so, are you also making a custom WP_QUERY() to fetch and display the search results? The plugin code I put together was to enhance the existing search pages. If you are making any WP_QUERY calls, you may be stepping on the WP_QUERY calls inside your widgets. It’s a common mistake that people make when developing in WordPress–I had to learn from it myself.

If you aren’t making a custom WP_QUERY call on your search results page, you may be having an issue with your template. If it is a stock template provided by someone else, I wouldn’t mind taking a look at it to see if I can identify the issue. I just need more information to further help you.

 

Michelle Says: October 20th, 2009 at 4:49 pm

You don’t like to leave things un-figured out do you? :D

The template thing made me think, so I tried it with the default template(s) too and still had the same problem. The one I’m using is from Woothemes and doesn’t have this problem with the regular search.

It’s also definitely not a problem with the recent posts plugin, since the default one comes up against the same problem when I search.

I did try wp_reset_query after my search results listing and before the sidebar in my template file, that sounded like it might do the trick but alas. Since it only happens with this custom search plugin installed I suspect I’ve done something idiotic, and am now poring over the code a line at a time to figure out exactly what.

Even if this never gets resolved, searching custom fields is more important than having to put a different sidebar on one page, so I’m happy.

 

horla Says: October 27th, 2009 at 4:31 am

hello thank’s you for this interresting post.
i’am trying change in wordpress the search just for tag or categories?… i make a function but it doesn’t work… i don’t know why :

function myTagFilter($query) {
if ($query->is_search) {
$query->set(‘tag’, ‘cat’);
}
return $query;
}
add_filter(‘pre_get_posts’,'myTagFilter’);

thank’s a lot

 

Baga Says: November 9th, 2009 at 5:41 pm

Hello do you have any idea on how to implement a custom field search with selectable checkboxes for each custom field value?

 

Han Says: November 17th, 2009 at 10:18 am

Perfect! I just put your peace of code in the functions.php, added my 2 customs fields in the array and it worked as a treat.
Thanks a lot for that little piece of your brain John.

 

oragoradway Says: November 25th, 2009 at 2:22 pm

I’m frequently searching for recent blogposts in the net about this matter. Thanks.

 

Wayne Smallman Says: February 18th, 2010 at 3:20 pm

John, thanks for the code, man. This has been a huge help.

 

Add multiple searchable content areas in WordPress with custom fields (video tutorial) | Web Design, Internet Marketing and Business Advice » Octane Says: March 2nd, 2010 at 10:46 am

[...] there’s a fix for this, all thanks to John Hoff, who’s written a script that extends the scope of the WordPress search engine to gra…, [...]

 

Tom Lany Says: May 28th, 2010 at 6:06 am

Thanks for sharing this! I have been needing some way to search through authors (that I store in custom fields) for along time, and this works wonderfully!

Thanks!

 
 
 
Leave a Reply

(required)

Mail (will not be published) (required)

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>