I have a search field for the blog posts, but I need an other for a custom post type. How can I create this custom search form with a different search result layout?
8 Answers
Here is what I've tried and got a solution with 3 steps. Let's say your custom post type is "products"
1 . Add Function Code here you can specify the archive-search.php
function template_chooser($template)
{
global $wp_query;
$post_type = get_query_var('post_type');
if( $wp_query->is_search && $post_type == 'products' )
{
return locate_template('archive-search.php'); // redirect to archive-search.php
}
return $template;
}
add_filter('template_include', 'template_chooser');
2 . Create search result template for custom post type ( archive-search.php )
<?php
/* Template Name: Custom Search */
get_header(); ?>
<div class="contentarea">
<div id="content" class="content_right">
<h3>Search Result for : <?php echo htmlentities($s, ENT_QUOTES, 'UTF-8'); ?> </h3>
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<div id="post-<?php the_ID(); ?>" class="posts">
<article>
<h4><a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>"><?php the_title(); ?></a></h4>
<p><?php the_excerpt(); ?></p>
<p align="right"><a href="<?php the_permalink(); ?>">Read More</a></p>
<span class="post-meta"> Post By <?php the_author(); ?>
| Date : <?php echo date('j F Y'); ?></span>
</article><!-- #post -->
</div>
<?php endwhile; ?>
<?php endif; ?>
</div><!-- content -->
</div><!-- contentarea -->
<?php get_sidebar(); ?>
<?php get_footer(); ?>
Build Search Form
In this Search Form, the value "products" is hidden and it will search only product posts.<div> <h3>Search Products</h3> <form role="search" action="<?php echo site_url('/'); ?>" method="get" id="searchform"> <input type="text" name="s" placeholder="Search Products"/> <input type="hidden" name="post_type" value="products" /> <!-- // hidden 'products' value --> <input type="submit" alt="Search" value="Search" /> </form> </div>
for more, I would like to link you to here
http://www.wpbeginner.com/wp-tutorials/how-to-create-advanced-search-form-in-wordpress-for-custom-post-types/
-
Tip: when registering the post type, the publicly_queryable argument must be set to true. If not, the get_query_var('post_type') will never return the post_type value given in the url argument. codex.wordpress.org/Function_Reference/… Commented May 21, 2015 at 17:46
-
Another tip/suggested edit:
get_query_var('post_type')
returned an array (rather than a string) so couldn't be compared directly. Since I'm only searching one post type at a time, I simply changed my$post_type
var to$post_type[0]
.– indextwoCommented Apr 8, 2016 at 15:51 -
is there a way to rewrite the url from
http://localhost:3000/?s=cloud%27&post_type=product
tohttp://localhost:3000/search/cloud/product
– YarGnawhCommented Nov 6, 2017 at 16:33 -
@YarGnawh Sorry for late response, check this out wordpress.stackexchange.com/questions/15418/…. There is a plugin called rewrite too wordpress.org/plugins/rewrite– RonaldCommented Nov 13, 2017 at 11:20
-
3For an answer being written 9 years ago, I can confirm in 2022 that it still works and with great accuracy! Excellent work @Ronald you are amazing! Commented Mar 5, 2022 at 10:24
Here is what works for me. Not as clean but I couldn't get any of these other answers to work.
Search form for Custom Post Type:
<form role="search" method="get" class="search-form" action="<?php echo home_url( '/' ); ?>">
<label>
<span class="screen-reader-text"><?php echo _x( 'Search for:', 'label' ) ?></span>
<input type="search" class="search-field" placeholder="<?php echo esc_attr_x( 'Search …', 'placeholder' ) ?>" value="<?php echo get_search_query() ?>" name="s" title="<?php echo esc_attr_x( 'Search for:', 'label' ) ?>" />
<input type="hidden" name="post_type" value="book" />
</label>
<input type="submit" class="search-submit" value="<?php echo esc_attr_x( 'Search', 'submit button' ) ?>" />
</form>
In functions.php:
function searchfilter($query) {
if ($query->is_search && !is_admin() ) {
if(isset($_GET['post_type'])) {
$type = $_GET['post_type'];
if($type == 'book') {
$query->set('post_type',array('book'));
}
}
}
return $query;
}
add_filter('pre_get_posts','searchfilter');
In search.php:
<?php if (have_posts()) : ?>
<?php while (have_posts()) : the_post(); ?>
<?php if(isset($_GET['post_type'])) {
$type = $_GET['post_type'];
if($type == 'book') {?>
/* Format for "book" custom post type */
<?php } else { ?>
/* Format for custom post types that are not "book,"
or you can use elseif to specify a second post type the
same way as above. Copy the default format here if you
only have one custom post type. */
<?php } ?>
<?php } else { ?>
/* Format to display when the post_type parameter
is not set (i.e. default format) */
<?php } ?>
<?php endwhile; else: ?>
/* What to display if there are no results. */
<?php endif; ?>
Naturally in all three places you'll need to replace "book" with your custom post type.
Hope this helps someone!
A short code more actualized
function template_chooser($template)
{
global $wp_query;
$post_type = $wp_query->query_vars["pagename"];
if( isset($_GET['s']) && $post_type == 'products' )
{
return locate_template('archive-search.php'); // redirect to archive-search.php
}
return $template;
}
add_filter('template_include', 'template_chooser');
I was looking to use two different forms for my normal searches and my searches on a custom post type.
My custom post type uses a different header than normal pages, on my normal page, the call to my search form is:
<?php get_search_form(true); ?>
And the call to my search form in the custom post type header is:
<?php get_template_part('search','library'); ?>
Which has an additional field:
<input type="hidden" name="post_type" value="library" /> //Where "library" is my custom post type.
In the functions file I have the following code that you have provided.
/** Custom Search for Library */
function search_library($template)
{
global $wp_query;
$post_type = get_query_var('post_type');
if( $wp_query->is_search && $post_type == 'library' )
{
return locate_template('search-library.php'); // redirect to archive-search.php
}
return $template;
}
add_filter('template_include', 'search_library');
Which detects if the search form is doing a search within custom fields, thus showing the search in a custom template, otherwise use the normal template.
Edit: fixed the get_search_form() function call which would have returned true no matter what.
-
2Worth noting, but
get_search_form('true')
should beget_search_form(true)
.get_search_form
is looking for a boolean input, so eithertrue
orfalse
. By wrapping it in quotes you are feeding it a string, not a boolean parameter. The way that function is set up, both'true'
and'false'
would return the same result, because they are both non-empty strings (which causes the function to return true in both cases).– MikeCommented Feb 22, 2018 at 1:29
To fix the empty input search issue you can substitute the function code with this:
function template_chooser($template)
{
global $wp_query;
$post_type = get_query_var('post_type');
if( isset($_GET['s']) && $post_type == 'products' )
{
return locate_template('archive-search.php'); // redirect to archive-search.php
}
return $template;
}
add_filter('template_include', 'template_chooser');
-
3Would be great if you explain how your code works, an reveal your source of the code Commented Sep 16, 2014 at 11:00
I know this is an old thread, but I use custom shortcodes in my functions.php file to enable searches tied to specific post types and in my case custom taxonomies. I use Pods for a video lecture archive by year, and wanted searches to be within that year only. This is currently working (in my functions.php):
/*Custom search for Video Archives Year 2020 - adds shortcode [2020search] for the search*/
function video2020searchform( $form ) {
$form = '<form role="search" method="get" id="searchform" action="' . home_url( '/' ) . '" >
<div class="my-custom-search"><label class="screen-reader-text" for="s">' . __('Search for:') . '</label>
<input type="hidden" name="video_year" value="video-archive-2020" />
<input type="text" value="' . get_search_query() . '" name="s" id="s" placeholder="Search 2020 archives by speaker or keyword..." />
<input type="submit" id="searchsubmit" value="'. esc_attr__('Search') .'" />
</div>
</form>';
return $form;
}
add_shortcode('2020search', 'video2020searchform');
// end of 2020 search form.
I then have a page with the highlight videos from 2020, with the search form shortcode above it so users can search the rest of 2020. name="video_year"
is the custom taxonomy created by Pods, the post type is also created by Pods and is called "videos", and value="video-archive-2020"
is the slug from the Pods video year I need. If you had a custom post type of "books", a taxonomy of "book-genre" and you are trying to restrict the search to "adventure", "book-genre" would be the 'name' entry and "adventure" would be the 'value'. Hope this helps someone, and thank you to all the above answers!
I have 10 CPTs each with it's own search result page (different layouts each) and using this was not working for me.
After more digging, I found this this approach where you condition the search.php template to load another template if there is a CPT in the URL.
basically in search.php you insert this:
<?php
// check to see if there is a post type in the URL + nonce for security
if ( isset( $_GET['post_type'], $_GET['custom_search_nonce_field'] ) && wp_verify_nonce( $_GET['custom_search_nonce_field'], 'custom_search_nonce_action' ) ) {
// save it for later
$post_type = $_GET['post_type'];
// check to see if a search template exists
if ( locate_template( 'search-' . $post_type . '.php' ) ) {
// load it and exit
get_template_part( 'search', $post_type );
exit;
}
}
?>
and the search form would be something like this:
<form class="search" action="<?php echo home_url( '/' ); ?>">
<input type="search" name="s" placeholder="Search…">
<input type="submit" value="Search">
<input type="hidden" name="post_type" value="kb_article">
<?php wp_nonce_field( 'custom_search_nonce_action', 'custom_search_nonce_field' ); ?>
</form>
-
-
1yes, especially on a public form, but it depends a lot on the setup; I added in this example hoping it will make people more conscious.– RwkYCommented Feb 23 at 17:32
In my case, the search was working perfectly. I just needed to filter out the query to search only for Learndash Courses post type. Here's what I did:
// Filters the search query to only include 'sfwd-courses' post type
function fn_search_courses_only($query) {
if( $query->is_search && ! is_admin() ) {
$query->set( 'post_type', 'sfwd-courses' );
}
}
add_action( 'pre_get_posts', 'fn_search_courses_only' );