Advanced search in WordPress themes

For some time now, I’ve been meaning to build an advanced search in WordPress. So now that all the functionality is available in core functions like query_posts, it looks like it’s just a matter of piecing it all together. Easy, right? Previously, I had been using plugins like Multiple Category Selection Widget and Query Multiple Taxonomies, but I either found bugs with new 3.0 features or the widget-style operation too restricting for my purposes. I like widgets, but I wanted my advanced search to appear on its own page.

So here is a quick run through of how you can add an advanced search page to your WordPress theme. For simplicity sake this tutorial will demonstrate how to use multiple categories at once. Truly advanced search would also combine keywords, sorting, filtering and more advanced user input. We’ll save those options for a later day.

Create a page template file in your theme

I really like using page template files, it makes it easier to work in ‘the loop’ and you have more space to build interfaces. In your theme folder create a file called template-advanced-search.php. A WordPress template file only needs the following code to make itself available to pages in wp-admin.

<?php
/*
Template Name: Advanced Search
*/
?>

Create a new page and attach the template file

Now you just need to attach the page template to a new page in wp-admin. Create a new page called ‘Advanced search’. If you created the page correctly you’ll see a reference to it in the page options. Select your template and publish the page.

Page Template Animation

Page Template Animation

Build form with wp_dropdown_categories

wp_dropdown_categories is a very useful core function that we can quickly use to build our advanced search form. In this example, we’ll be using this function combined with parent and child category groups. Creating parent and child category groups is easy. Go play around in the admin section (wp-admin/edit-tags.php?taxonomy=category) and work it out. Essentially, you want to create the following structure:

  • Category 1
    • Child 1
    • Child 2
    • Child 3

Create 3 separate parent child groups.

Here is an example of the code should look now in template-advanced-search.php.

<?php
/*
Template Name: Advanced Search
*/
?>
<h2><a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>"><?php the_title(); ?></a></h2>
<form action="<?php bloginfo('url'); ?>" method="get">
<h3>Category 1</h3>
<div><?php wp_dropdown_categories('child_of=1&show_option_none=Not selected...&hide_empty=1&name=cat[one]'); ?></div>
<h3>Category 2</h3>
<div><?php wp_dropdown_categories('child_of=2&show_option_none=Not selected...&hide_empty=1&name=cat[two]'); ?></div>
<h3>Category 3</h3>
<div><?php wp_dropdown_categories('child_of=3&show_option_none=Not selected...&hide_empty=1&name=cat[three]'); ?></div>
<br />
<div><input class="button" type="submit" name="submit" value="Advanced Search" /></div>
</form>

Now to get the above example to work properly with your categories, you need to edit the code above so that each of the <code>child_of=X</code> references actually refer to real parent category IDs from your WordPress install. So, change the numbers 1, 2 and 3 to the parent category IDs you are using.

Control results with query_post in index.php

Now you just need some code to catch the get parameters from the URL and send that to the query_post function. query_posts will modify the loop to only show the posts that match you’re combination of categories. The following is very simplified code for index.php. If you’re testing this on an existing theme back-up your existing index.php before over-writing.

<?php
if ($_GET['submit'] == 'Advanced Search') {
	$pladvsearchcatids = Array ();
	$pladvsearchcatnames = Array ();
	foreach ($_GET['cat'] as &$pladvsearchcatvalue) {
		if ( $pladvsearchcatvalue != "-1" ) {
			array_push($pladvsearchcatids, $pladvsearchcatvalue);
		}
	}
}
global $wp_query;
query_posts( array_merge( $wp_query->query, array( 'category__and' => $pladvsearchcatids )));
if (have_posts()) :
   while (have_posts()) :
      the_post();
      the_content();
   endwhile;
endif;
?>

That’s it, now you should have the basics of advanced multi-category search working.

If you have any questions, please use the comments below…

17 Responses to “Advanced search in WordPress themes”

  1. Guest says:

    Hi,

    How does one get results to show up properly? i.e. regardless of item searched, it just displays the main blog page.

    Also is there a way to use category names instead of ID#s?

    Thank you.

    • admin says:

      Did you edit your index.php file to contain the code display in the last step above?

      The child_of variable in wp_dropdown_categories only accepts integers. So, no, I don’t see a way to use category names instead of IDs.

  2. agabu says:

    Thanks a lot for the tutorial. It was exactly the intro I needed to start understanding the main idea of custom search working.
    One little note, I added the categories and subcategories but didn’t assign any posts to them at first, so I initially got stuck but after then your tutorial turned out to be really helpful. Thank you.

  3. baalstorm says:

    HI! i was using this great tip and it worked like a charm, but now – don’t know why – i get this :
    Warning: urldecode() expects parameter 1 to be string, array given in /web/htdocs/www.archivioflaviobeninati.com/home/archivio/wp-includes/query.php on line 1702

    do you have any idea what’s going on? :/
    thanks a lot

    • baalstorm says:

      looks like the problem starts when i put those name=cat[one], name=cat[two], name=cat[three] in… i used to change them to the id’s of the categories i wanted to show in the dropdown list..

      • admin says:

        Weird. Did you manage to fix it?

      • daniele says:

        HI! I used this tutorial but i have an error like baalstrom, this :
        Warning: urldecode() expects parameter 1 to be string, array given in /web/htdocs/www.archivioflaviobeninati.com/home/archivio/wp-includes/query.php on line 1722

        Someone can help me?

  4. seba says:

    just wanted to thank you man, I’ve been looking for this tutorial for such a long time!!

    • admin says:

      You’re very welcome. I found it hard to find examples like this online when I was researching it.

  5. Jason says:

    Great tutorial! Question… is there a way to make this spit out just a single random result? For example, if the search generates, say, 10 matches, it will only display one at random. Any help would be greatly appreciated. Thanks!

    • admin says:

      I’m sure that’s possible, but why would you want to do that? The idea behind this advanced search was to increase accuracy of a user’s search.

  6. Stefano says:

    Hi guys,
    following this tutorial I made an advanced search page for a real estate site. It works like a charm but now, after upgrade wordpress to 3.2.1 I have a problem.
    When someone click on search button wordpress does the work but he give me that error:

    Warning: urldecode() expects parameter 1 to be string, array given in /home/hosting/p/provestefanino/www/wp-includes/query.php on line 1722

    I’m working hard to solve it but I’m not a programmer and I don’t know how I can fix it.

    it’s the first time I have a problem after an upgrade.
    Can someone show me how to solve it?

  7. Stefano says:

    ok..

    i’ve solved the problem downgrading to wordpress 3.0.4 ..

    now it works again but i’m still curious..