Multiple custom search forms in WordPress

There are occasions when you want to fine-tune where, when, and how WordPress outputs search forms. For example you will likely want to change the default HTML used for the form, and you may want to display more than one search form on some pages.

In this post I’ll show several ways of customising the HTML of search forms, how to conditionally display a search form, and how to display more than one search form on the same page without breaking validation.

There are many ways of doing this (more than I had thought of when I started writing this), and there may well be even more than those I describe here. I’m not sure which way – if any – is considered WordPress best practice. As far as I can tell they all do work though.

Customising the HTML of the WordPress search form

Changing the markup used for the global search form (which is normally displayed in the header or at the top of the sidebar) is pretty straightforward, but there are at least five ways of doing it:

  • Hard coding the form into your template file
  • Putting the form in a separate file and using PHP’s include() function to pull it in
  • Using get_template_part() to include the file
  • Creating a template file called searchform.php to hold the form
  • Creating a custom function that returns the markup you want

The last two options are described well on the Function Reference/get search form page in the WordPress Codex.

Hard coding the HTML for the form

Though it’s how it’s done in the default theme for WordPress 3, you don’t have to use the get_search_form function to output your search forms. Hard coding the HTML in whatever template file you need it in works fine. Just remember that for the search to work, the form needs to use the get method and the text field’s name attribute has to have the value s. Other than that it’s up to you.

Using include() to load a file with the form

If you want to be able to put the search form in different template files, you can avoid repeating the same code over and over by simply moving the form HTML to a new file in your theme directory and loading it with PHP’s include() function like this:

<?php include( TEMPLATEPATH . '/searchform.php' ); ?>

TEMPLATEPATH is a constant that points to the physical location of your template directory.

Using get_template_part() to include the file

We’re not out of options just yet. You can also use the WordPress function get_template_part() to include your file. To load a file called searchform.php from your theme directory you can also use this:

<?php get_template_part( 'searchform' ); ?>

Using a searchform.php template file

You can also load the include file, as long as it’s called searchform.php, by placing <?php get_search_form(); ?> where you want your form to appear. WordPress will load the file just as if you had used include().

The drawback to this method is that – at least as far as I’ve been able to figure out – doing so prevents you from using a custom function (described next) to modify the form. If searchform.php exists it seems to override anything you do with add_filter().

Using a custom function

Yet another option is to create a custom function in your functions.php file:

function custom_search_form( $form ) {
    $form = '<form method="get" id="quick-search" action="/" >';
    $form .= '<div><label for="s">Search this site for:</label>';
    $form .= '<input type="text" value="' . get_search_query() . '" name="s" id="s" />';
    $form .= '<input type="submit" value="Search" />';
    $form .= '</div>';
    $form .= '</form>';
    return $form;
}
add_filter( 'get_search_form', 'custom_search_form' );

Like creating a searchform.php file, this will let you control the output of the get_search_form function.

Are there even more ways? Probably.

Hiding the global search form on search results pages

On search results pages you may want to hide the global search form and display a larger search form above the search results. I’m not taking a stand here whether doing this is good or bad for usability, but just noting that this is a fairly common design pattern.

The default behaviour in WordPress 3 is to display the global search form on all pages that have a sidebar. This includes the search results page. When a search returns no results, an additional, identical, search form is displayed below the “nothing found” message. If you want valid code this is not good since the id values of the two forms and their controls will be identical, which is not allowed.

You can get around this by only ever displaying one search form on the same page. As usual there are several ways to do that:

  • Replace the global search form with a local search form on search pages
  • Replace the global search form only when nothing is found
  • Always show the global search form and never show the local search form

Always remove the global search form on search pages

In the file that contains your global search form (typically header.php or sidebar.php), replace <?php get_search_form(); ?> (or whichever of the other methods described above you have used to output the form) with this:

<?php
if ( !is_search() ) {
    get_search_form();
}
?>

This does what it says – do not display the global search form on search result pages.

Since you still want people to be able to search you’ll need to add a search form elsewhere by inserting <?php get_search_form(); ?> (or – again – with one of the other options) in a suitable position in your search.php file. One common place is to insert it above the search results.

Remove the global search form when nothing is found

To only remove the global search form when nothing is found, replace <?php get_search_form(); ?> with this:

<?php
global $query_string;
$posts = query_posts($query_string);
if (have_posts()) {
    get_search_form();
}
?>

This snippet will check if the search returned any results and only display the global search if there are search results. If you’re using the logic from the default WordPress 3 theme, a search form will be displayed in the content area of the search page instead.

Displaying multiple search forms without causing validation errors

The default theme in WordPress 3 outputs the search form HTML as it is defined in the WordPress core. This may be okay as long as there is only one instance of the search form. But if you search for something that returns no results, the search page gets another search form with exactly the same HTML, which causes validation errors due to there being multiple elements with the same id.

To get around this you need to create multiple forms where no id values clash. You can use the same markup and keep the name values for the controls since their scope is limited to the form they belong to. That’s good since we need to use name="s" for the text field containing the search phrase.

One way of doing this is to create a custom function for each form you need. If you want two forms, you can put this in your functions.php file:

function custom_search_form( $form ) {
    $form = '<form method="get" id="quick-search" action="/" >';
    $form .= '<div><label for="s">Search this site for:</label>';
    $form .= '<input type="text" value="' . get_search_query() . '" name="s" id="s" />';
    $form .= '<input type="submit" value="Search" />';
    $form .= '</div>';
    $form .= '</form>';
    return $form;
}
add_filter( 'get_search_form', 'custom_search_form' );

function custom_search_form_2( $form ) {
    $form = '<form method="get" id="main-search" action="/" >';
    $form .= '<div><label for="s2">Search this site for:</label>';
    $form .= '<input type="text" value="' . get_search_query() . '" name="s" id="s2" />';
    $form .= '<input type="submit" value="Search" />';
    $form .= '</div>';
    $form .= '</form>';
    return $form;
}

The absence of a second add_filter call is intentional. The custom_search_form_2 function will only be invoked when we need to display a second search form. Still using the search results page as an example, here is how to display an additional search form by editing the search.php template file and replacing <?php get_search_form(); ?> with this:

<?php
/* Temporarily use custom_search_form_2 to output the search form. */
add_filter( 'get_search_form', 'custom_search_form_2' );
get_search_form();
remove_filter( 'get_search_form', 'custom_search_form_2' );
?>

This will add a filter just before we call get_search_form, modifying the HTML it outputs, and remove the filter when we’re done to make sure any subsequent calls will output the default search form HTML.

(Almost too) many options

This was meant to be a really short tip post, but once I started writing it turned out there are more ways than I thought to customise search forms in WordPress. I hope I got things right and that there aren’t too many mistakes here. Please do let me know if you spot something.

The good thing about all these options is that there is no reason to be limited to the default HTML WordPress gives you unless you want to.

Posted on February 15, 2011 in WordPress

Comments are disabled for this post (read why), but if you have spotted an error or have additional info that you think should be in this post, feel free to contact me.