I have built a theme for a car dealership. Each car is a custom post type ("vehicle"), and has about 12 custom fields with things such as Make, Model, Mileage, Fuel Type etc. etc.

So basically on the home page I want a search form which has drop down lists for Make & Model and contains any available Makes or Models.

I also want it to have 2 options for Year, so the end user can select "2006" and "2012" and the search results contain all vehicles with the year between those two numbers.

Is there a plugin out there that can do this??

Thankyou for any help.. this has been driving me crazy for hours!!!!

up vote 13 down vote accepted

______UPDATE_______
Though I'm getting more and more votes, and the solution works, but cybmeta's answer is actually the answer that is nice and WordPress' way. You should definitely try that.

Step 1

Start by making an Advanced Search Form with which you want your user will interact with the website, and save it with a name (i.e. I saved it as advanced-searchform.php — but don't save it with searchform.php then it'll replace the WordPress' default search form):

<form method="get" id="advanced-searchform" role="search" action="<?php echo esc_url( home_url( '/' ) ); ?>">

    <h3><?php _e( 'Advanced Search', 'textdomain' ); ?></h3>

    <!-- PASSING THIS TO TRIGGER THE ADVANCED SEARCH RESULT PAGE FROM functions.php -->
    <input type="hidden" name="search" value="advanced">

    <label for="name" class=""><?php _e( 'Name: ', 'textdomain' ); ?></label><br>
    <input type="text" value="" placeholder="<?php _e( 'Type the Car Name', 'textdomain' ); ?>" name="name" id="name" />

    <label for="model" class=""><?php _e( 'Select a Model: ', 'textdomain' ); ?></label><br>
    <select name="model" id="model">
        <option value=""><?php _e( 'Select one...', 'textdomain' ); ?></option>
        <option value="model1"><?php _e( 'Model 1', 'textdomain' ); ?></option>
        <option value="model2"><?php _e( 'Model 1', 'textdomain' ); ?></option>
    </select>

    <input type="submit" id="searchsubmit" value="Search" />

</form>

Then call the form into your template like the following:

<?php get_template_part( 'advanced', 'searchform' ); ?>

Now your search form is ready, and you can now use the search form and can take user input into the URL.

Step 2

What you just need is: query the database and query the post type and its custom fields as per the search query. Remember your search query is now the URL you got after submission of the form. Now ask WordPress to load your custom search result page when the form is submitted. Place the following function into your functions.php so that it'll enable your custom search template instead of the default search.php:

<?php
function wpse_load_custom_search_template(){
    if( isset($_REQUEST['search']) == 'advanced' ) {
        require('advanced-search-result.php');
        die();
    }
}
add_action('init','wpse_load_custom_search_template');
?>

I brought the code somewhere from WPSE (I forgot the root), but there's controversy using the code above. But it actually works (lame excuse of course).

Check another way @G.M. suggested.

Step 3

Make a new file and save it with advanced-search-result.php (because we used this name in functions.php) and now you are free - obviously. Concept is:

  • Grab the data from the URL,
  • Use a simple WP_Query() (if your query is complex then use $wpdb query),
  • Pass the commands within the query, fetch data from db, and
  • Show the result[s]

A sample can be:

<?php
// Get data from URL into variables
$_name = $_GET['name'] != '' ? $_GET['name'] : '';
$_model = $_GET['model'] != '' ? $_GET['model'] : '';

// Start the Query
$v_args = array(
        'post_type'     =>  'vehicle', // your CPT
        's'             =>  $_name, // looks into everything with the keyword from your 'name field'
        'meta_query'    =>  array(
                                array(
                                    'key'     => 'car_model', // assumed your meta_key is 'car_model'
                                    'value'   => $_model,
                                    'compare' => 'LIKE', // finds models that matches 'model' from the select field
                                ),
                            )
    );
$vehicleSearchQuery = new WP_Query( $v_args );

// Open this line to Debug what's query WP has just run
// var_dump($vehicleSearchQuery->request);

// Show the results
if( $vehicleSearchQuery->have_posts() ) :
    while( $vehicleSearchQuery->have_posts() ) : $vehicleSearchQuery->the_post();
        the_title(); // Assumed your cars' names are stored as a CPT post title
    endwhile;
else :
    _e( 'Sorry, nothing matched your search criteria', 'textdomain' );
endif;
wp_reset_postdata();
?>

So, here is your final thing. But still there are many challenges:

  • Alternative Values - an advanced search can be performed with ALL of the fields or ANY of the field, so you have to make sure the Query is taking all the results as per the search and data. You can use $wpdb custom SQL query for complex search result and that will be pure MySQL - WordPress has nothing there.
  • Sanitization & Validation - the texts field and textarea are so vulnerable that can cause mal practice to your site. So passing raw data would be unsafe, you will need to Sanitize and Validate them before passing into the db query. (Data Sanitization and Validation with WordPress - TutsPlus)
  • Designing - you can choose the page.php (or search.php) template and make this page on the basis of that.

So, you got the idea, now it's your turn to explore and discover the way. Remember, everybody's way is different. Make yours, so that I can follow you. :)

  • Thankyou for taking the time, very kind of you. Do you know how I can have it so the drop down menu for "Makes" will automatically show any makes that have been entered in one of the vehicle posts? – absdigital Oct 15 '14 at 16:00
  • Will glad if it works for you. :) – Mayeenul Islam Oct 15 '14 at 16:01
  • Do you know how I can have it so the drop down menu for "Makes" will automatically show any makes that have been entered in one of the vehicle posts? – absdigital Oct 15 '14 at 16:06
  • use a WP_Query() using custom field parameters and loop the result to show the <option>s. – Mayeenul Islam Oct 15 '14 at 16:06
  • I would like to see this "advanced search" done using pre_get_posts hook and not a secondary loop. – cybmeta Feb 2 '15 at 9:44

Although @MayeenulIslam's answer could work, I think the correct way to do an advanced search is using the pre_get_posts action hook.

Step 1: search form

This step equal to step 1 in the other answer, just changed the id of the "name" filed used for search to "s", so it will be used directly for as search field. Save this code in searchform-advanced.php under your theme folder. Then, use get_template_part( 'advanced', 'searchform' ); to load it where you want it to appear in your theme:

<form method="get" id="advanced-searchform" role="search" action="<?php echo esc_url( home_url( '/' ) ); ?>">

    <h3><?php _e( 'Advanced Search', 'textdomain' ); ?></h3>

    <!-- PASSING THIS TO TRIGGER THE ADVANCED SEARCH RESULT PAGE FROM functions.php -->
    <input type="hidden" name="search" value="advanced">

    <label for="s" class=""><?php _e( 'Name: ', 'textdomain' ); ?></label><br>
    <input type="text" value="" placeholder="<?php _e( 'Type the Car Name', 'textdomain' ); ?>" name="s" id="name" />

    <label for="model" class=""><?php _e( 'Select a Model: ', 'textdomain' ); ?></label><br>
    <select name="model" id="model">
        <option value=""><?php _e( 'Select one...', 'textdomain' ); ?></option>
        <option value="model1"><?php _e( 'Model 1', 'textdomain' ); ?></option>
        <option value="model2"><?php _e( 'Model 2', 'textdomain' ); ?></option>
    </select>

    <input type="submit" id="searchsubmit" value="Search" />

</form>

Step 2: add filters to search query

add_action( 'pre_get_posts', 'advanced_search_query' );
function advanced_search_query( $query ) {

    if ( isset( $_REQUEST['search'] ) && $_REQUEST['search'] == 'advanced' && ! is_admin() && $query->is_search && $query->is_main_query() ) {

        $query->set( 'post_type', 'vehicle' );

        $_model = $_GET['model'] != '' ? $_GET['model'] : '';

        $meta_query = array(
                            array(
                                'key'     => 'car_model', // assumed your meta_key is 'car_model'
                                'value'   => $_model,
                                'compare' => 'LIKE', // finds models that matches 'model' from the select field
                            )
                        )
        );
        $query->set( 'meta_query', $meta_query );

    }
}

Step 3: Templating (optional)

With this method, the default search template of WordPress will be used filtering the results without the need of a secondary query. If you want to use a different template for advanced search, you can use the template_include filter. For example, if you want to use advanced-search-template.php file as template for results from the advanced search form:

add_action('template_include', 'advanced_search_template');
function advanced_search_template( $template ) {
  if ( isset( $_REQUEST['search'] ) && $_REQUEST['search'] == 'advanced' && is_search() ) {
     $t = locate_template('advanced-search-template.php');
     if ( ! empty($t) ) {
         $template = $t;
     }
  }
  return $template;
}
  • 3
    Thank you very much for the WordPress' way. Just worked with this one and it's awesome. :) – Mayeenul Islam Apr 30 '15 at 17:39

protected by fuxia Nov 13 '15 at 12:37

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.