Spruce interactive

Noise

Two Category Dropdown Search Filter in WordPress

Posted: September 14th, 2012

Author: Ben Heller

Tags:

, , ,

 Details

When Josh Lurie asked Spruce to re-code his excellent blog FoodGPS, we jumped at the chance to take a bloated WordPress install and clean it up. As part of our ongoing efforts to improve the platform, we just implemented a two category search function. Previously, visitors had been able to select a type of cuisine or a particular location from a pulldown menu. They were then taken to an archive page for the selected category. Our task was to take these two dropdowns and combine them, so that users could select either a cuisine, or a location, or both a cuisine and a location. In the case a user selects an option from both categories, we don’t merely want a combined archive page (category 1 + category 2), but rather a filtered archive page, with only those posts that meet the criteria for both categories (e.g. Chinese Food in Los Angeles, not Chinese Food and Los Angeles). There are some examples of similar attempts out there, but we couldn’t find anyone who was doing quite what we wanted. So, as usual we figured it out ourselves. First we created an HTML form and displayed the dropdowns using the built-in WordPress function wp_dropdown_categories():

<form method="get" action="<?php bloginfo('template_url');?>/findfood.php" id="findfood">       
   <?php wp_dropdown_categories('show_option_none=Select a Cuisine&hide_empty=1&child_of=27&orderby=name&name=cuisine'); ?>
   <?php wp_dropdown_categories('show_option_none=Select a Location&hide_empty=1&child_of=26&orderby=name&name=location&hierarchical=1'); ?>
   <input type="submit" value="Search"/>
</form>

There are three things worth noting here:
1.) Set the method to “get”
2.) Set the action to a new .php file that we’re sticking in our theme directory
3.) Set the &name= property inside the wp_dropdown_categories() options to something unique–in this case we used “cuisine” and “location”

Next, create the custom PHP file that will be processing the form and move it to your theme directory (as good a place as any, right?). The top of this file looks like this:

<?php
require_once('../../../wp-blog-header.php');

if (($_GET['cuisine'] != -1) && ($_GET['location'] != -1)):
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
query_posts( 
   array( 
      'orderby' => 'date', 
      'order' => 'DESC',
      'paged' => $paged,
      'posts_per_page' => 6,
      'category__and' => array(
         $_GET['location'],
         $_GET['cuisine']
      ),   
   ) 
);
?>

There’s a lot to talk about here, so we’ll work from top to bottom. First, we’re requiring the wp-blog-header.php file. This allows us to use WordPress functions and lets WordPress know this strange new file is part of the gang. Next, we run some checks to see if the user set both the location and the cuisine. If neither of these values are -1, then we can go ahead and run a special query using both values. The form will return the ID for each category, so we’ll use this to create a custom results page. The important bit here is the ‘category__and’ parameter, which ensures that the resulting posts will be assigned to both categories and not just one or the other. We’ve decided to display the list in a paged view, so we’ve added ‘paged’ to our parameters as well. Below this we copied code from our archives.php page, and used something like get_cat_name($_GET['cuisine']) in get_cat_name($_GET['location']) to display “Showing Chinese Food in Los Angeles” as the page title. The PHP and HTML code here will vary based on your theme, but remember that you can pull information from the $_GET variable to show category names. The next interesting bit is our else statement, which directs users to the appropriate single category archive page if they’ve only searched for one or the other category:

<?php else:
   if ($_GET['cuisine'] != -1){
      header('Location:'.get_category_link($_GET['cuisine']));
   } elseif ($_GET['location'] != -1){
      header('Location:'.get_category_link($_GET['location']));
   } else{
      wp_redirect(home_url());
   }
endif;?>

And that’s it folks! As always, feel free to get in touch if you have any questions about this process or trouble implementing it on your own sites. In the meantime, you can see it in action at foodgps.com!

  • Farhad

    Hi,
    i get an error “Parse error: syntax error, unexpected T_STRING in xxxxx/findfood.php on line 2″
    while i used your code..
    Pls Help! ))))

    • spruceit

      Hi Farhad, this looks like a PHP error. We’d be happy to help debug–drop us a line via our contact form with a link to your sourcecode and we’ll see what we can do!

  • Anup

    Hi

    I cant tell you how thankful I am to you for this solution. I was scratching my head for this multiple category search feature. Thanks a ton!

    • spruceit

      Cool, glad we could help!

  • Anup

    Hi

    How do I alter it for searching across 4 (or more…) different dropdown menus? Can you help?

    • spruceit

      Hi Anup–we haven’t tested this, but it *should* be possible. You’d want to do the following:

      1.) Add additional wp_dropdown_categories() as needed in the HTML form, so wp_dropdown_categories(‘show_option_none=Select a Your Field&hide_empty=1&child_of=yourparentID&orderby=name&name=yourfield’);

      2.) Add these new fields to the IF statement in the form processor, so: if (($_GET[cuisine] != -1) && ($_GET[location] != -1) && ($_GET[yourfield] != -1))

      3.) Add these new fields to the query_posts() array, under ‘category_and’ => array($_GET[location], $_GET[cuisine], $_GET[yourfield])

      4.) Add an additional ELSEIF statement to the redirect: ELSEIF ($_GET['yourfield'] != -1){ header(‘Location:’.get_category_link($_GET['yourfield'])); }

      And that should be it!

      • Antonio

        Hi there,

        let’s simplify the logic applied here:

        if (ALL selectable categories ARE SELECTED) // all are selected
        then “run query”/”apply filter” for ALL selectable categories

        elseif (ONE selectable category IS SELECTED) // one is selected
        then “run query”/”apply filter” for the ONE SELECTED category

        else [if (ALL selctable categories ARE NOT SELECTED)] // none is selected
        do something else (for example go to the homepage).

        Unfortunately this logic stops working when you want to have yet another option:

        if (MANY selectable categories ARE SELECTED) // more than one, but not all

        Using the logic applied in this tutorial with more than two categories to choose from, it’s all or nothing, because if you skip only one of the categories, it’s not ALL and it’s not NONE. But which ever was selected first is shown as one single category page.

        Any ideas onhow to restructure the conditional chaining to make it work for n[2+x] categories?

        • Antonio

          Maybe it’s possible to “collect” MANY SELECTED categories in one array and explode that array into the search filter URL. This would cover 1-n categories and NONE would be covered as well (if array is empty).
          My php coding knowledge is too limited to code that myself, but it sounds reasonably easy. ;)

          • spruceit

            Hmm, this sounds plausible! We’ll have our devs look into this, and we’ll see if we can rig up an example as a follow-up to this post. Thanks for the suggestion!

  • Cleopatra Wallace

    I am using a wordpress them that I purchased and want to turn the nearby search into a drop down that sorts by Island, can this be used to do so (www.mybahamasdining.com)

    • spruceit

      It looks like this would be a great use for our tutorial. It depends somewhat on how you have your categories set up, but the “Search for X in Y” principle is exactly the same. Feel free to get in touch if you need any help implementing this on your site!

  • Ali

    Hi there! I’ve been searching for this all over the place and your’s looks like it comes the closest. Hooray! However there’s something wrong with my findfood.php file I think as it seems to stop after the first line of code. Have copied the two blocks of code you mention to create the findfood.php and changed the categories to those I want to search in but the search results come back with just a blank page. Any ideas why this may be? Thanks!

    • spruceit

      Heya, glad we could help! My guess is that the “require” for wp-blog-header.php isn’t finding the right file. You can try hardcoding the path, or checking the number of ../../ relative to your theme directory. This can often happen if your WordPress install lives in its own folder (e.g. /html/wordpress). The best way to unravel this mystery is to turn on the debug.log that lives in /wp-content and then check that sucker. Good instructions can be found here: http://codex.wordpress.org/Editing_wp-config.php#Debug

      • Ali

        Hmmm I did try that but still no joy. Also tried to use a fresh copy of the 2012 theme on the latest WP version incase it was my theme as I’ve created my own. Before I fiddle around a bit more with it; thought I’d check it’s compatible with the latest versions?

        • spruceit

          It should be! We’ve tested it up to 3.4.2, and none of the functions or methods used in this tutorial were deprecated in 3.5, so I doubt it’s a version issue. From your description above, it really does sound like Apache isn’t finding the wp-blog-header.php file. It’s tough to debug via Disqus, but if you want to drop us a line with FTP/WP credentials we can take a look at it.

          • Ali

            Will keep trying to find the solution but thanks for the offer; will be in touch if I can’t sort it! Grrrrr; probably something really simple!

          • Ali

            Hi again. I contacted my hosts incase it was something I needed to do differently; they gave me a different path to try but it didn’t work so suggested contacting you with the following question:

            “My host does not allow loopback connections. What settings do I need to use to have the scripts run files directly without making a http connection back to the site?”

            Can you help with that?

          • spruceit

            Yikes, I’m afraid that’s our of our wheelhouse! The above code shouldn’t be causing a loopback connection, as it’s using the file path and not an absolute URL to require the file. But, we’re admittedly taking shots in the dark at this point, since we can’t see the code in the actual environment. If you’d like us to take a look we’d be happy to, but I think this is about as much as we can help without actually having the files in front of us. Sorry!

          • Ali

            no probs. will send over the details in a contact form ; if you could take a look when you get a mo that would be ace :o )

          • ali

            Hi guys; just wanted to say a BIG thank you for taking the time out to solve my problem. For those reading this thread; I hadn’t replaced ALL of my categories with those in the initial code and I needed to copy my category.php template into the findfood.php so that something displayed on the results page. Simple really ;o) THANK YOU!

  • ali

    Hi again team Spruce! Just wondering … on the results page is it possible to show the user what categories they’ve just searched on? i.e. something along the lines of ‘Here are the search results for Category A in/and Category B’?

    • spruceit

      Ali,

      Yep, that’s actually what’s being stored in the $_GET variable–it’s the same process we mention above in the tutorial as to how we determine the page title.

      “Below this we copied code from our archives.php page, and used something like get_cat_name($_GET['cuisine']) in get_cat_name($_GET['location']) to display “Showing Chinese Food in Los Angeles” as the page title. The PHP and HTML code here will vary based on your theme, but remember that you can pull information from the $_GET variable to show category names.”

      So basically you want “Here are the search results for echo get_cat_name($_GET['cuisine']) in echo get_cat_name($_GET['location'])”, but of course using real PHP syntax.

  • Matt Harris

    Sorry the ‘else’ statement, the ‘if’ statement is working correctly

  • Antonio

    Hello folks,

    I’m trying to make this work with a couple of different categories, but first reduced the amount of selections to two (like in the example), to see how it goes.

    First there was an error message about the require_once(‘../../../wp-blog-header.php’);

    I got that sorted out, by changing the path.

    Not I get a blank page when doing the selection. So I turned on debugging and it displayed the following error messages:

    Notice: Use of undefined constant cuisine – assumed ‘cuisine’ in /home/vhosts/***/***/***/htdocs/wp-content/themes/suffusion-child/find-staffel.php on line 4
    Notice: Use of undefined constant location – assumed ‘location’ in /home/***/***/***/htdocs/wp-content/themes/suffusion-child/find-staffel.php on line 4
    Notice: Use of undefined constant location – assumed ‘location’ in /home/vhosts/***/***/***/htdocs/wp-content/themes/suffusion-child/find-staffel.php on line 12
    Notice: Use of undefined constant cuisine – assumed ‘cuisine’ in /home/vhosts/***/***/***/htdocs/wp-content/themes/suffusion-child/find-staffel.php on line 13

    I used the code for the form with my category IDs, but changed nothing else and also used the findfood.php (here find-staffel.php) without changing anything.

    So, a) What could be the problem here?

    and b) Once this works, I’d like to throw some checkboxes into the mix, to not only choose one from many, but also be able to select single categories on their own. What do I have to add in the form and what do I have to add in the find-staffel.php?

    Also: Someone over here
    http://wordpress.stackexchange.com/questions/8224/is-there-any-multiple-filter-criteria-plugin-for-wordpress
    claims that ” ‘category_and’ should be ‘category_in’ if you want to check multiple categories “.

    I’m working on a website for my diploma project, please help me out. Thanks!

    • spruceit

      Heya!

      So you’re doing everything correctly, but guessing from the blank page, you skipped this step: “Below this we copied code from our archives.php page”. You actually need to echo the results inside findfood.php, within the IF statement. The logic is, “IF someone’s made a search in both categories, show the results in the following template {copy archive.php code, or whatever you want to use}, ELSE redirect to the proper single category page”.

      The undefined constant errors you’re getting just have to do with whether you’ve used single quotes around ‘location’ and ‘cuisine’ in the $_GET variables (we had omitted them in our example, but I’ve now updated this).

      We’ve also edited the ELSE case in which neither dropdown is selected so users are redirected to the WP home page via wp_redirect(home_url());

      • Antonio

        Thanks! I totally forgot about this part. It’s working now. That brings me to my next question:

        “b) Once this works, I’d like to throw some checkboxes into the mix, to
        not only choose one from many, but also be able to select single
        categories on their own. What do I have to add in the form and what do I
        have to add in the find-staffel.php?”

        • spruceit

          Hi there, this gets into extending the functionality we’ve provided in the tutorial. If we ever need to do this for a client we’ll add it as a follow-up post, but for the time being the ball’s in your court to make modifications of this nature. If you do end up adding this functionality, let us know and we’ll add it to the post with all due credit. Thanks!

      • yves

        Hi,

        I also get a blank page. Indeed I skipped the step ‘Below this we copied code from our archives.php page’.

        My theme has no archives.php. Is there a general code that can be used?

        Where exactly do I have to insert the code from archives.php? What do you mean with ‘within the IF statement’?

        Can you please explain this step-by-step ;-)

        Thank you for your help!

        • spruceit

          Hi Yves! We’d be happy to explain:

          1.) You’ll be displaying the page data between the 2nd and 3rd code excerpts in this tutorial, satisfying the condition “if (($_GET['cuisine'] != -1) && ($_GET['location'] != -1))”, and before the ELSE statement.

          2.) We copied our archive.php template here, as it was the closest template to how we wished to display this kind of data (it’s what we use as our category page template on this site). Any WordPress Loop would do here: http://codex.wordpress.org/The_Loop. You can experiment by doing something as simple as http://codex.wordpress.org/The_Loop#Using_The_Loop. Remember to include your header.php and footer.php files.

          3.) You can then utilize any of the $_GET variables to display category information on this page.

          If you’re not yet familiar with IF statements in PHP, you might want to consider taking some general PHP tutorials before launching into the techniques mentioned above–they’re not super advanced, but they do require a working knowledge of PHP and WordPress.

          Thanks!

  • dreamer

    Great tutorial! With that said, is there an easy way to change the second category drop-down to instead be a drop-down of tags? So the first element would choose a category, and then the second filter could then filter within that category by tag? I haven’t been able to find a simple way to create a dropdown of tags that will function like the cat dropdown does. Wonder if you knew offhand!

    • spruceit

      Heya,

      So there’s a built-in WP function for creating a dropdown of categories, but we’re not aware of a corresponding one for tags. It would be pretty simple to iterate through tags to build the dropdown menu, but creating the filter would require some trickier parameters for the query_posts that generates the results page. Sounds pretty doable, but I’m afraid we don’t have a quick solution. We will, however, add this to our queue of ideas for follow-up posts, and will try to get to it soon. Stay tuned!

  • dmitcha

    Thanks – this is what I have been looking for after trying many plugins (including trying to modify the Query Multiple Taxonomies plugin to search AND rather than OR). One question – how would you modify this to get all categories/taxonomies rather than hard-coding select ones? We have a lot, and the list expands regularly. Even if there is a link to direct me to this answer, it would be greatly appreciated!

  • Ali

    Hi Team Spruce
    Just playing around with the code and my php skills aren’t quite what I’d like them to be. How would I change that final bit of code to show some text in the page along the lines of ‘Sorry there are no items in these categories’ when someone selects two things where they don’t have an entry e.g. shoe shops in brighton? I’m hoping to have entries for all but at the moment it just comes up with a blank page so would be good to add a line in there. Hope that makes sense?!

    • spruceit

      Hi Ali–you’d want to add something within the ELSE statement in the final block of code that redirects to an existing page containing the text “Sorry there are no items in these categories”. Alternately, you can paste your entire page.php template here (so, include your header.php, footer.php, and body tags) and type this code in manually. Either method should work, though redirecting to a static page is probably the cleanest and therefore preferred method.

      • ali

        thanks team spruce!

  • Ali West

    hi team spruce

    just wondering, i’ve just this great search facility for my site but i’m also looking to do a similar thing with only one category to choose BUT the item has to be in two categories. i.e. a list of events in certain cities. i’ve set up a custom post type ‘events’ and those events are based in a number of cities. the cities categories are also used for other entries e.g. ‘web designers in london’. is it possible to do this by tweaking the code .. if so and it’s fairly simple could you give me some guidance. if it’s not possible i’ll look elsewhere, just thought i’d ask first before i start trying as i’m no expert at php!

    • spruceit

      Hi Ali,

      For something like this, I’d consider a frontend JS solution to actually stop users from submitting the dropdown until they’ve selected both an Event and a City. Then, you can add additional logic in the PHP that redirects to an error page if for some reason the JS doesn’t do its job. It would definitely be possible to modify this code for the situation you’ve described, but it would also involve a good bit of original programming. We’d be happy to lend a hand if you want to get in touch about hiring some dev time!

      • Ali

        Hi there
        I may just need to do that, will contact you separately with the info …
        Thanks!

  • paleka

    Hi

    Thank you! Great post. pushed me in the right direction for making filter for mutiple (as many as you want) categories. Three changes: GET to POST, generating string that I use in category__and array, redirecting only if nothing chosen.

    foreach($_POST AS $key => $value) {

    if($value ‘date’,

    ‘order’ => ‘DESC’,

    ‘category__and’ => array($strSearch),

    )

    );

    • spruceit

      Nice work! Would you be cool if we integrated this into the main article and gave you all due credit for the improvement?

      • paleka

        Of course! maybe it’ll help somebody else.

    • dave

      Hi paleka

      just trying to integrate the code you’ve created. can you explain where it would go?

      My code is shown below; which bits are removed? thanks!:

      ‘date’,

      ‘order’ => ‘DESC’,

      ‘paged’ => $paged,

      ‘posts_per_page’ => 6,

      ‘category__and’ => array(

      $_GET['city'],

      $_GET['category']

      ),

      )

      );

      ?>

  • Tonyzg

    Wow awesome work! Thank you guys! I would suggest to change this:

    action=”/findfood.php”

    to something like this:

    action=” /filter/”

    Just to keep URL consistent and shorter.

  • Nicholas Chen

    This is exactly what i’ve been searching for! unfortunately i can’t seem to get it to work. it just takes to me a page that says “nothing found”. where did i go wrong? here is my site: http://sbxdev1.com/applefitness/

    • butreallytho

      How did you get yours to work? This is exactly what I’m looking for!

  • Rezwan Mohsin

    Hi, I thanks for a great tutorial..

    I am relatively new in wordpress and having a problem querying a custom post type.. actually I am a bit confused..

    I want to have a filter search for books which are needed for a certain exam.. in my search drop down list, the first one will have the list of the universities, when a certain uni is selected, the next dropdown will have the list of available courses in that university. and the final dropdown will have the semesters names of that course..

    when all of these selected the result will show the list of books that are needed in that course exam..

    the example is in this link..
    http://www.academicbooks.dk/en/readinglist

    i am very much confused on how to relate them..

    I have taken a custom post types named “books” and taxonomies named “uni”, “course”, ”semester” and ”exam”.. but stuck on relating them..

    if possible please help..

    • Jig

      How did you get yours to work? This is exactly what I’m looking for!

  • dave

    hi there
    apologies if this is repeat; i posted something up earlier but not sure if it’s made its way to the comments section ok.
    i’ve used the code perfectly for a search for say category and city. i’ve then copied and pasted the code from the two relevant files and renamed and changed the bits i need to category1 and town for a separate search. however the page returns no results even though there is something in the two categories. been trying to figure out for a fair few hours changing bits and pieces; wanted to double check that it is possible to do this first off or is something conflicting maybe?
    hope that gives you enough info about the problem. any help much appreciated!

  • Ross

    Hey there, I made a plugin that does just this – you can create complex search forms with categories/tags/taxonomies & more – I hope its useful to someone :)http://wordpress.org/plugins/search-filter/

    • butreallytho

      I tried your plugin and it doesn’t work with custom fields.

      • Ross

        Yup you’re right it doesn’t do meta data but it does do categories and taxonomies like this article describes – if you’re stuck feel free to leave us a question in support.

        • butreallytho

          It seems yours just does All Categories in one drop down though. I need multiple categories as drop downs.

  • Mike

    Hi When I create my custom php file, dreamweaver tells me the last ?> is a syntax error?

  • Mike

    Also does the last bit of code slot in with the dropdown code? Or where?

  • Mike

    If I paste it into my custom php page, the syntax error goes but when I search I get the ‘broken’ white screen?

  • butreallytho

    I wish this worked. It’s exactly what I need. I can’t get the results to display. Using the action=”/findfood.php” creates an error. Changing to action=”/findfood/” generates no results.

  • Zahid Hasan

    Great artricle… I have multiple categories that I set up in workpress. I would like to have multiple dropdown for each category. How can I achieve it? I asked my question here at SO: http://stackoverflow.com/questions/23479680/how-to-edit-themes-for-each-dropdown-select

  • Shaun Bakic

    I also have a completely blank screen. I have changed everything to accommodate my setup that I can see but it is just not returning anything. Could some one please help me out with this.

Talk to Us

Wise men have said, "All good things must come to an end", and so it was with Spruce. We began our first project in 2006, and completed our last in Fall 2013. It's been a wonderful experience, but now it's time to begin the next adventure.

Though...we wouldn't want to leave you hanging, now would we? Here are our top recommendations for world-class branding, design, and web development:

  • Kristina (KJ) Parish and Beam Collective:
    KJ provided the artistic vision that allowed Spruce to succeed, and we still think she's the greatest designer in the entire world. She's started a new collective with some talented developers, and is covering much the same territory as Spruce--design and development all under one roof, with a caliber of service and professionalism seldom seen in this business or any other. If you like what you see on the Spruce site, then definitely get in touch with KJ at kj@beamcollective.com
  • Permanent Art & Design
    Permanent is a nationally recognized design & branding firm out of Minneapolis, MN. They've been a long term collaborator and strategic partner over the past couple years, and we'd recommend them for medium to large sized businesses/organizations who are serious about putting their best foot forward. In addition to design, Permanent offers strategy and marketing services, plus in-house and networked developers. For more information contact Joseph Belk joseph@permanentadg.com
  • Nate Thompson
    A freelancer, Nate reminds us of ourselves back in the day. Smart, communicative, and skilled, Nate is our recommendation for small to medium sized businesses/organizations who have sites built on Wordpress or other open source content management solutions. With a background in both design and development, he's a one-stop shop for most web-related tasks. You can get in touch at nate.a.thompson@gmail.com
  • Kevin DeBernardi
    Designer turned developer, Kevin is embarking on a freelance web career after working as the in-house designer at the Museum of the City of New York. He's adept at translating his design ideas into custom PHP code, and is constantly expanding his technical palette. Kevin's a good choice for projects that don't quite fit into the Wordpress mold, and that would benefit from a consistency of presence and vision from design through execution. Kevin can be reached at kevin@analoglifestyle.com