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.