wordpress-category-search
WordPress Search By Multiple Categories

This is actually quite a surprisingly popular problem, how to modify the WordPress search to search by multiple categories defined by the user (see image at base of article for how it looks).

To search by a single category is very simple, you just add this to your search form:

<input id="cat" type="hidden" name="cat" value="12" />

However to really extend this it would be nice for your users to be able to select a number of categories to filter/search.

You can use the system I will show you to filter anything from custom posts type, dates, authors, ..anything you can specify in wp_query.

The code:


<form role="search" method="post" id="searchform" action="<?php bloginfo('home'); ?>">

    <label class="screen-reader-text" for="s">Search for:</label>
    <input type="text" name="s" id="s" <?php if(is_search()) { ?>value="<?php the_search_query(); } ?>"  />     
	<h5>Select categories to search</h5>
	<div class="scroll_checkboxes">
				<?php 
		
		//print_r($_POST['filter_cat']);

		$categories=  get_categories('include=89,114,117,122,129,130'); 
  		foreach ($categories as $category) {
  			$checkboxes = '<label><input type="checkbox" name="filter_cat[]" value="'.$category->cat_ID.'"';
  			if (in_array($category->cat_ID, $_REQUEST['filter_cat'])) { $checkboxes .= 'checked="checked"';}
  			$checkboxes .= ' />';
			$checkboxes .= $category->cat_name;
			$checkboxes .= '</label>';
			echo $checkboxes;
  		}
		//if you want subsections just copy the chunk again
		echo "<h5>Sub Title</h5>";
  		$categories=  get_categories('child_of=7'); 
  		foreach ($categories as $category) {
  			$checkboxes = '<label><input type="checkbox" name="filter_cat[]" value="'.$category->cat_ID.'"';
  			if (in_array($category->cat_ID, $_REQUEST['filter_cat'])) { $checkboxes .= 'checked="checked"';}
  			$checkboxes .= ' />';
			$checkboxes .= $category->cat_name;
			$checkboxes .= '</label>';
			echo $checkboxes;
  		}  		
		?>
	</div>
    <input  class="btn" type="submit" id="searchsubmit" value="Search" />

</form>

Explanation

this code can be placed in search.php, searchform.php or on a unique page, …I placed it in the main content of search.php and left my default searchform.php alone as the client wanted to maintain a simple sidebar search also.

Line 1: This is your default WordPress search form, but I have changed the method to ‘post’ from ‘get’ as I do not want a messy url with the variables I create, but you can leave this as get if you wish.
Also, it should read ‘bloginfo(‘home’)’ but my syntax highlighter is playing up.

Line 2-5: As normal, with an extra title I inserted to precede the search filter box.

Line 6: After a number of different tests with radio buttons, multiple select menus, normal select menus, the multiple check box in a scrolling pane seemed to be the best and most useable solution, but you can change this as you wish using the same concept. This is why it is surround in this div, and has the following CSS in the style.css file:

.scroll_checkboxes {
height: 260px;
padding: 5px;
overflow: auto;
border: 1px solid #CCC;
}

Line 9: This is a debug check so you can see the category ID’s being passed should you need to.

Line 11-19: This is where the magic happens. Using the get_categories() function I query the WP cats with whatever parameters I wish,in this case a list of specific cats, but as you can see on Line 22, I later repeat this for child categories.

I then loop through these results creating a label encapsulated checkbox input with the name filter_cat[] which ensures checked box values are all placed in the same filter_cat array.

There is also a check in there using REQUEST (so will work if your form is get or post) to see if this box has been selected in the previous query, to ensure that it stays checked.

Line 21-30: As you see from the image at the bottom, I split my list with sub-headers, which gave me maximum control at my clients wish, so I have repeated the section with different parameters for get_categories, but nothing else has changed.

Line 32-35: Close the div and close the search form as normal.

Next, add this into your search.php file, just above the loop as this will extract your array of category ID’s and add tem to the search query:

global $wp_query;
foreach($_POST['filter_cat'] as $fcat){$fcat_list .= $fcat . ",";}

query_posts(
	array_merge(
		array( 'cat' => $fcat_list ),
		$wp_query->query
	)
);

Line 2: I cycle though the $_POST['filter_cat'] array and add the ID’s to a comma separated list.

Line 4-9: I add the list of cats to the $args of the query. This is the point at which you could in theory add further modification if you had created checkboxes to filter by another paramaters.

Finally

That’s it, …Wordpress search the way it should be witha few usability extras. To see what it looks like check the image out below. Alas I cannot show you how it works in person as it is on a closed client site.

Good Luck

Leave a comment...

15 comments

  1. I like this. All apart from:

    “Line 1: This is your default WordPress search form, but I have changed the method to ‘post’ from ‘get’ as I do not want a messy url with the variables I create”

    This breaks C.R.U.D (http://en.wikipedia.org/wiki/Create,_read,_update_and_delete) principles:
    ‘Create POST’
    ‘Read (Retrieve) GET’

    You’re switching a ‘read’ mechanism to a ‘write’ mechanism, and breaking the back button functionality (in as much as having done a search, clicking ‘back’ will report a ‘you submitted a form, please click to reconfirm submission’, which sucks from a UI perspective.)

    If you’re concerned about the prettiness of the URLs, write a decent rewrite ruleset, don’t use creation/updating methods for data retrieval…

  2. mog says:

    I was waiting for you to reply :P …this is true what you say however, it was trying to pass an array in the url which given the number of article id’s each with encoded []’s was making for a very very long url in some cases, which is not very usable to pass around, ..as as the point of the search in this particluar instance leads the user to a page where they can print, email or save those result, the usability is there. …but you are right, ..on a smaller public level, perhaps switch back to GET to maintain url usability, …and Jonathan’s happiness ;)

  3. Andrew says:

    Thanks for posting this, very helpful. Any guidance on how to modify what’s above to result in an inclusive search of categories checked? (Probably using category__and, I would imagine. Or otherwise.)

    Thanks!

  4. mog says:

    Sorry, I am not actually sure, ..you would need to hack the search query before it is run, …which 5 minutes of googling did not give me an answer on how to do, …but I know the Search Everything plugin will do this, …but guessing you are here because you wanted to avoid the plugins.
    Sorry I can’t spend more time looking, got a lot to do today.

  5. Andrew says:

    After much fussing, this seems to do the trick:

    $args = array(
    ‘category__and’ => $_GET['filter_cat'],
    );

    query_posts(
    array_merge(
    array( ‘cat’ => $fcat_list ),
    $args,
    $wp_query->query
    )
    );

  6. mog says:

    Thanks for coming back and posting it dude, ..much appreciated.

  7. Ruby says:

    Is it possible to have this filter in my nav menu? If so, where do i paste this code? Thanks!

  8. mog says:

    You can indeed, ..this is part of the search form, so if your search form is included in your header/nav then you may have this wherever you wish.

  9. Aaron says:

    I’m having difficulties implementing this one. I’ve done tonnes of research into multiple checkbox category searches and your article is the closest I’ve found.

    Specifically I am using this approach on a recipes website – each recipe is tagged with multiple categories of course, skill level, dietary requirement and season.

    As far as I can tell I’ve applied the correct code where required. I have my child categories displaying as expected but when I perform a search I get two main issues:

    - My search query ends with ?s=egg+recipes+&filter_cat[]=263 – I was reading for wordpress categories that the search string should simply read ‘&cat=263, 264′ – is this true or any reason why its different?

    - My search results page then returns 0 results (showing my fallback no results found content), however the title of the page shows ’24 egg recipes found’. Ontop of this if I remove the checkbox from the search it still returns 24 results – so its seemingly isnt filtering correctly.

    I found also if I remove the query posts snippet from search.php, I start getting correct results but categories still won’t work.

    So yeah totally stuck. I figured the above code would work out of the box but alas no. Anyone got any ideas?

  10. mog says:

    First things first, ..change your search form method to POST, …else it is going to get ugly when we try and pass an array in the url, which I am not sure is even possible.

    ..and ..erm, ..from what I can see, .that is it ;)

    I may be missing something bit here, …(I forgot to put sugar in my coffee so anything is possible) ….but I am sure you will let me know.

    Be aware that doing it like this as my geeky friend in the first comment pointed out does break some usability guidelines (in temrms of using the back button), …and it should be possible to adapt it to GET but you will nee to pass the categories as a string which will mean changing the name of the checkbox field to make sure it is without the [] square brackets, ..then checking what it outputs the other side, …I am a little pushed for time this morning to start testing, …but my client wanted the query hidden as they were super secret and corporate and did not want people messing with the query manually.

  11. I have made this search form but the main issue I am having is that the resulting categories all list side by side rather than neat and tidy in a list like yours.
    I would also like to have the results go to a blog results page (same as if you were to select a single blog category) rather than home page results. Any help there?
    Thanks for your efforts so far though!

  12. mog says:

    Hi Kate, ….the results page is your search.php file in your template folder (see ‘WordPress Template Hierachy’ to better understand which template file WP chooses), so you can organise and manipulate these results in that template as you wish with CSS and your template file.

    Let me know by email if you have any more questions.

  13. manil says:

    Hi, I was looking for this exact search capability. I am a complete newbie to php. I wanted to know where to place the code you have provided. I understad that it should be in search.php under content. I have done the same but unable to get this kinda search on the front end. Could you please help me place this code correctly in search.php?

  14. David says:

    Hi, I am having a few troubles here. If I set the method as post when searching I just see the homepage, running on get gives me the querystring /?s=&filter_cat[]=23 but returns no results.

    I have created a tpl-searchform.php template and assigned a page to this template. this shows my search form

    [code]

    <form role="search" method="get" id="searchform" action="">

    Search for:
    <input type="text" name="s" id="s" value=" " />
    Places

    <?php

    //print_r($_POST['filter_cat']);

    $categories= get_categories('include=22,23');
    foreach ($categories as $category) {
    $checkboxes = 'cat_ID.'"';
    //if (in_array($category->cat_ID, $_REQUEST['filter_cat'])) { $checkboxes .= 'checked="checked"';}
    $checkboxes .= ' />';
    $checkboxes .= $category->cat_name;
    $checkboxes .= '';
    echo $checkboxes;
    }
    //if you want subsections just copy the chunk again
    echo "Type";
    $categories= get_categories('include=17,19');
    foreach ($categories as $category) {
    $checkboxes = 'cat_ID.'"';
    //if (in_array($category->cat_ID, $_REQUEST['filter_cat'])) { $checkboxes .= 'checked="checked"';}
    $checkboxes .= ' />';
    $checkboxes .= $category->cat_name;
    $checkboxes .= '';
    echo $checkboxes;
    }
    ?>

    [/code]

    thn copied the search.php from the twentyforteen theme and pasted into my own and just changed the outout to show the titles.

    Have I missed something?

    Thanks

  15. Ross says:

    Hey there, I built a plugin that does just this + more ;)

    http://wordpress.org/plugins/search-filter/

    Its used to build complex search forms with filters for categories, tags, taxonomies, post types, and post dates – you can use all different kinds of inputs for them too such as dropdowns, checkboxes, multi selects etc :)

This site is not up to date. I really should take it down and make a new one as I have been busy with a lot of cool projects and clients recently, but currently do not have the time to rebuild it.

So, it stays here, but please note it has not been updated in a while and if you need to get in contact with me please just email me directly at mog@mogmachine.com or phone me on +44 (0)7960 214407.

Thanks,

Marcus (mog)