Wordpress - Creating a search form for custom fields

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 field (<input type="text" ...> used for search to "s", so it will be used directly for as search field. Save this code in advanced-searchform.php under your theme folder. Then, use get_template_part( 'advanced', 'searchform' ); to load it where you want it to appear in your theme:

<?php /**`advanced-searchform.php`*/ ?>
<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;
}

______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>
  • Learn more about WordPress default searchform template

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();
?>
  • Your best friend while using WP_Query — Codex and the Custom Field Parameters

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. :)