Search only for custom post types (in 2 different forms)

Hi there,

I’d like the WP search form to search for one specific custom post type (CPT). Normally I’d put this peace of code inside the form: <input type="hidden" name="post_type" value="events"/>

But it seems the Roots search rewrite overwrites this hidden input, is that so? And if so; how can I disable it? I have two CPT’s: events and artists and I’d like to create two search forms which each search through one CPT.

Would be great if that was possible while maintaining the search rewrite (because it looks nice!). So when searching for ACDC, maybe the query could (still) look like domain.com/search/acdc.

If that’s not possible, it could be something like domain.com/search/acdc&t=artists (or &type=artists).

Cheers,
Joost

The nice search functionality does not have a good solution for CPTs. Your most reliable option is to disable nice search in /lib/config.php by commenting out the add_theme_support('nice-search'); line.

If you want to try something more complex, you can replace the roots_nice_search_redirect function in /lib/cleanup.php with something like this (not tested well):

 function roots_nice_search_redirect() {
  global $wp_rewrite;
  if (!isset($wp_rewrite) || !is_object($wp_rewrite) || !$wp_rewrite->using_permalinks()) {
    return;
  }

  $search_base = $wp_rewrite->search_base;
  if (is_search() && !is_admin() && strpos($_SERVER['REQUEST_URI'], "/{$search_base}/") === false) {
    $post_type = '';
    if(get_query_var('post_type') != 'any') { $post_type = "?post_type=".urlencode(get_query_var('post_type')); };

    wp_redirect(home_url("/{$search_base}/" . urlencode(get_query_var('s')).$post_type));
    exit();
  }
}

If you want to change the query var from post_type to t, replace both these functions in /lib/cleanup.php:

function roots_nice_search_redirect() {
  global $wp_rewrite;
  if (!isset($wp_rewrite) || !is_object($wp_rewrite) || !$wp_rewrite->using_permalinks()) {
    return;
  }

  $search_base = $wp_rewrite->search_base;
  if (is_search() && !is_admin() && strpos($_SERVER['REQUEST_URI'], "/{$search_base}/") === false) {
    $post_type = '';
    if(get_query_var('post_type') != 'any') { $post_type = "?t=".urlencode(get_query_var('post_type')); };

    wp_redirect(home_url("/{$search_base}/" . urlencode(get_query_var('s')).$post_type));
    exit();
  }
}

AND

function roots_request_filter($query_vars) {
  if (isset($_GET['s']) && empty($_GET['s'])) {
    $query_vars['s'] = ' ';
  }
  if (isset($_GET['t']) && !empty($_GET['t'])) {
    $query_vars['post_type'] = get_query_var('post_type');
  }
  return $query_vars;
}

Disable nice-search doesn’t sound nice :-). I’m not that good at programming so I’ll give your code a shot and if it doesn’t work out than I’ll go for disabling the nice-search. But thanks anyway!

Didn’t read your second post because we were posting at the same time. I’ll try your code, thanks again!

Doesn’t seem to work. It still searches through all custom post types and pages.

My search form now looks like this:

<form action="<?php echo home_url('/'); ?>" method="get">
<input type="hidden" name="t" value="events" />
<input id="s" name="s" type="text" class="span4" />
<input type="submit" value="Search" />
</form>

Wasn’t sure if I should use 't' or 'post_type' for name, but both don’t work.

Use your original additional hidden field in the form:

<input type="hidden" name="post_type" value="events"/>

and you can use the rest of the form markup from /templates/searchform.php

I think I’m missing something. I’ve put the original hidden field in the form from templates/searchform.php but when I search for an event of which I know it exists it doesn’t return any results. The search URL does become /search/eventname?t=events…

Is your CPT publicly searchable? To see if it is something wrong with the search functionality or your CPT, put post in the post_type hidden input and then test against searching just posts (vs. pages, posts and events results).

Show me your full form again, and maybe a gist of your /lib/cleanup.php contents as well.

And make sure your CPT name is correct, event vs. events?

The full form now looks like this:

<form role="search" method="get" id="searchform" class="form-search" action="<?php echo home_url('/'); ?>">
<input type="hidden" name="post_type" value="events" />
<label class="hide" for="s"><?php _e('Search for:', 'roots'); ?></label>
<input type="text" value="<?php if (is_search()) { echo get_search_query(); } ?>" name="s" id="s" class="search-query" placeholder="<?php _e('Search', 'roots'); ?> <?php bloginfo('name'); ?>">
<input type="submit" id="searchsubmit" value="<?php _e('Search', 'roots'); ?>" class="btn">
</form>

The form that I eventually would like to use looks like this (and I think this should work just as the roots form):

<form action="<?php echo home_url('/'); ?>" method="get">
<input type="hidden" name="post_type" value="events" />
<input id="s" name="s" type="text" class="yt-search-input span4" />
<input type="submit" value="Zoek" />
</form>

CPT is publicly searchable, tried event vs events, gist can be found here: https://gist.github.com/joostvanhoof/fd2837b0a683c8469485

It still searches for everything, but the results are kind of weird. When I search for an event which I know it exists it doesn’t return results. When I search for a generic term it returns pages, posts, and results from events and also artists.

Disable nice search, reset the roots_request_filter function and then test the form/CPT setup to make sure your search of the CPT works.

If I do, everything works as expected (with the roots form code from my previous post). So then it must be somewhere in the code you’ve posted? Weird because it looks pretty straightforward…

If I disable nice search and reset the roots_request_filter everything works as expected. When I enable nice search and set the roots_request_filter like you’ve suggested search doesn’t work anymore.

My custom post type is named ‘events’. Say I type the search query ‘rock’ and there are 3 events with ‘rock’ in the eventname (custom post title). What happens is that somewhere it tries to forward to a custom post type page from events. The URL I get when I search for ‘rock’ is domain.com/events/event-with-rock-name/?t=events and it returns the 404 page. So it looks like the rewrite fails somewhere and / or roots tries to forward to an existing page (I noticed that when typing domain.com/events/event-with-r for instance, it forwards to domain.com/events/event-with-rock-name. Or is this default WP behavior?)

Any ideas?

In addition to my previous answer, if I change roots_nice_search_redirect to the code below (added $query) than the URL rewrite seems to work (becomes domain.com/search/?t=events&s=query), but it also returns a 404 so search is not working.

function roots_nice_search_redirect() {
  global $wp_rewrite;
  if (!isset($wp_rewrite) || !is_object($wp_rewrite) || !$wp_rewrite->using_permalinks()) {
    return;
  }

  $search_base = $wp_rewrite->search_base;
  if (is_search() && !is_admin() && strpos($_SERVER['REQUEST_URI'], "/{$search_base}/") === false) {
    
    $post_type = '';

    if(get_query_var('post_type') != 'any') { $post_type = "?t=".urlencode(get_query_var('post_type')); };

    $query = "&s=".urlencode(get_query_var('s'));

    wp_redirect(home_url("/{$search_base}/".$post_type.$query));
    exit();
  }
}

and roots_request_filter is:

function roots_request_filter($query_vars) {
  if (isset($_GET['s']) && empty($_GET['s'])) {
    $query_vars['s'] = ' ';
  }
  if (isset($_GET['t']) && !empty($_GET['t'])) {
    $query_vars['post_type'] = get_query_var('post_type');
  }
  return $query_vars;
}

I’m still struggling with this problem. I’ve also put a post on stackoverflow but still no luck. Any ideas?

Most of us just disable “nice-search” for anything other than the default base search functionality – does everything work as intended if you do that? Unfortunately I don’t have time to write and test this for you.

Yes then it works. Thanks for the help, I’ll let you know when it’s working!

It’s the default behaviour for WordPress and in the codex under redirect_canonical. You can turn it off with:

remove_filter('template_redirect','redirect_canonical');

As for the search issue I would follow Chris’ advice or hire a dev to fix it for you.