Custom search form and SRP in WordPress

In this tutorial I will create custom search form that can filter search results by post type and display them on custom search page.

1. Get all post types

First of all I will create function to retrieve all post types and filter unwanted. By unwanted I mean post types ‘attachment’, ‘nav_menu’ and ‘revision’, we don’t want them to appear in selection menu.

function all_post_types() {
  // Get all post types
  $post_types = get_post_types();

  // Post types to exclude
  $exclude = array( 'attachment', 'revision', 'nav_menu_item', 'acf' );

  // Filter out all unwanted post types
  foreach ( $post_types as $key => $value ) {

    if ( in_array( $key, $exclude ) ) {
      unset( $post_types[$key] );
    }
  }

  if( is_array($post_types)): ?>

    <select name="post_type-filter" id="post_type-filter" class="form-control">

    <?php
    // Return post types as options for select menu
    foreach ( $post_types as $key => $value ): ?>
      <option value="<?php echo $key; ?>"><?php echo $value; ?></option>
    <?php endforeach; ?>

    </select>

  <?php endif;
}

2. Create search form

Second thing is to create search form, you can use default WordPress search form snippet and save it in new file. That way you can include it on any page you like this search to appear.
My search form html would then look like this:

<form role="search" method="get" class="search-form form-inline" action="<?php echo home_url('/'); ?>">
  <div class="input-group">
    <input type="search" value="<?php if (is_search()) { echo get_search_query(); } ?>" name="s" class="search-field form-control" placeholder="Search <?php bloginfo('name'); ?>">

    <label class="hide">Search for:</label>
    <span class="input-group-btn">
      <button type="submit" class="search-submit btn btn-default">Search</button>
    </span>
  </div>

  <div class="input-group">
    <label for="post_type-filter">Select post type:</label>
      <?php all_post_types(); ?>
  </div>
</form>

3. Create new search page

Next, I will create new search results page (SRP) and using template_include filter load our new template.
Basically what you do is duplicate search.php and rename it to something new like: custom-search.php
To load this new search template add this to your functions.php

function search_template_chooser($template) {
  global $wp_query;

  // Check if we are on search page && if post_type-filter is selected
  if( $wp_query->is_search && isset( $_GET['post_type-filter'] ) ) {
    return locate_template('custom-search.php');  //  redirect to custom-search.php
  }
  return $template;
}
add_filter('template_include', 'search_template_chooser');

Info: If you are using URL Rewrite for search page, this might not work and you would need to turn off rewrite for search.

4. Filter search results

Only one thing left to do is to filter out search results and display only results from selected post type.
To do this I will use pre_get_posts action. Add this to your functions.php:

function search_filter($query) {

  // Get post type value
  if ( isset( $_GET['post_type-filter'] ) ):
    $filter_by = $_GET['post_type-filter'];

    if ( !is_admin() && $query->is_main_query() ) {
      if ($query->is_search) {
        $query->set('post_type', $filter_by );
      }
    }

  endif;
}

add_action('pre_get_posts','search_filter');

Query multiple post type

To query multiple post types, we would need to make a little modification to our search form. Instead of select menu I will use checkbox

function all_post_types() {
  // Get all post types
  $post_types = get_post_types();

  // Post types to exclude
  $exclude = array( 'attachment', 'revision', 'nav_menu_item', 'acf' );

  // Filter out all unwanted post types
  foreach ( $post_types as $key => $value ) {

    if ( in_array( $key, $exclude ) ) {
      unset( $post_types[$key] );
    }
  }

  if( is_array( $post_types ) ):

    // Return post types as options for select menu
    foreach ( $post_types as $key => $value ): ?>
      <input type="checkbox" checked="checked" value="<?php echo $key; ?>" name="post_type-filter[]"> <label> <?php echo $value; ?></label><br />
    <?php
    endforeach;
  endif;
}

This will print out form with checkbox for each post type, then users will be able to select multiple. Everything else stays as is.

Hope this helps.

Leave a Reply

Your email address will not be published. Required fields are marked *