How to Create a Custom Search Form with Filters in WordPress

October 10, 2025
How to Create a Custom Search Form with Filters in WordPress

How to Create a Custom Search Form with Filters in WordPress

The default WordPress search only checks post titles and content. To give users a better experience, you can build a custom search form that includes filters — such as categories, tags, and custom fields. In this guide, you’ll learn how to create a custom search form, handle the logic in PHP, and display results with filters applied.

Step 1: Create the Search Form

First, create a custom search form that allows users to filter results by category and keyword. You can place this form in your theme (for example, in searchform.php or inside a widget area).

<form role="search" method="get" class="search-form" action="<?php echo esc_url( home_url( '/' ) ); ?>">
  <label>
    <span class="screen-reader-text">Search for:</span>
    <input type="search" class="search-field" placeholder="Search..." value="<?php echo get_search_query(); ?>" name="s">
  </label>

  <!-- Category Filter -->
  <select name="category" class="search-category">
    <option value="">All Categories</option>
    <?php
    $categories = get_categories( array( 'hide_empty' => false ) );
    foreach ( $categories as $cat ) :
      $selected = ( isset( $_GET['category'] ) && $_GET['category'] == $cat->term_id ) ? 'selected' : '';
      echo '<option value="' . esc_attr( $cat->term_id ) . '" ' . $selected . '>' . esc_html( $cat->name ) . '</option>';
    endforeach;
    ?>
  </select>

  <!-- Submit Button -->
  <button type="submit" class="search-submit">Search</button>
</form>

This form submits to your site’s default search URL (e.g., ?s=keyword&category=3), which you’ll process next.

Step 2: Modify the Query with pre_get_posts

Now, use the pre_get_posts action to modify the main query and filter results based on user input. Add this to your functions.php file.

<?php
// Customize search query with category filter
add_action( 'pre_get_posts', function ( $query ) {
    if ( $query->is_search() && $query->is_main_query() && ! is_admin() ) {

        // Category filter
        if ( ! empty( $_GET['category'] ) ) {
            $category_id = (int) $_GET['category'];
            $query->set( 'cat', $category_id );
        }

        // Optional: limit to specific post type
        $query->set( 'post_type', 'post' );

        // Optional: order results
        $query->set( 'orderby', 'date' );
        $query->set( 'order', 'DESC' );
    }
});

This ensures the search results only show posts in the selected category (if one is chosen).

Step 3: Add a Custom Field Filter (Optional)

If your site uses custom fields (meta data), you can filter by those too. Let’s add a dropdown for a custom field called difficulty with values “Beginner,” “Intermediate,” and “Advanced.”

Update the Search Form

<select name="difficulty" class="search-difficulty">
  <option value="">All Levels</option>
  <option value="beginner" <?php selected( $_GET['difficulty'] ?? '', 'beginner' ); ?>>Beginner</option>
  <option value="intermediate" <?php selected( $_GET['difficulty'] ?? '', 'intermediate' ); ?>>Intermediate</option>
  <option value="advanced" <?php selected( $_GET['difficulty'] ?? '', 'advanced' ); ?>>Advanced</option>
</select>

Update the Query Logic

<?php
add_action( 'pre_get_posts', function ( $query ) {
    if ( $query->is_search() && $query->is_main_query() && ! is_admin() ) {

        // Filter by category
        if ( ! empty( $_GET['category'] ) ) {
            $query->set( 'cat', (int) $_GET['category'] );
        }

        // Filter by custom field 'difficulty'
        if ( ! empty( $_GET['difficulty'] ) ) {
            $meta_query = array(
                array(
                    'key'     => 'difficulty',
                    'value'   => sanitize_text_field( $_GET['difficulty'] ),
                    'compare' => '=',
                ),
            );
            $query->set( 'meta_query', $meta_query );
        }
    }
});

Step 4: Customize the Search Results Page

Edit your search.php or archive-search.php template to display selected filters and the corresponding results.

<?php get_header(); ?>

<h1>Search Results</h1>

<?php if ( have_posts() ) : ?>
  <?php while ( have_posts() ) : the_post(); ?>
    <article>
      <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
      <p><?php the_excerpt(); ?></p>
    </article>
  <?php endwhile; ?>

  <?php the_posts_pagination(); ?>
<?php else : ?>
  <p>No results found. Try adjusting your filters.</p>
<?php endif; ?>

<?php get_footer(); ?>

Step 5: Display Active Filters

To make it clear which filters are active, you can display the current selections above the results:

<div class="search-summary">
  <strong>Keyword:</strong> <?php echo esc_html( get_search_query() ?: 'None' ); ?><br>
  <strong>Category:</strong> <?php
    if ( ! empty( $_GET['category'] ) ) {
      $cat = get_category( (int) $_GET['category'] );
      echo esc_html( $cat->name );
    } else {
      echo 'All';
    }
  ?><br>
  <strong>Difficulty:</strong> <?php echo esc_html( $_GET['difficulty'] ?? 'All' ); ?>
</div>

Step 6: Style Your Search Form and Results

Add CSS to your theme’s style.css for better presentation:

.search-form {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 16px;
}

.search-field,
.search-category,
.search-difficulty {
  padding: 6px 10px;
  font-size: 16px;
}

.search-submit {
  background: #0073aa;
  color: #fff;
  border: none;
  padding: 8px 14px;
  cursor: pointer;
}

.search-submit:hover {
  background: #005b8c;
}

Optional Enhancements

  • AJAX filtering: Load search results dynamically without reloading the page.
  • Multiple taxonomies: Allow filtering by both categories and tags.
  • Range filters: Add number or date filters using meta_query comparisons (e.g., price or date range).
  • Save user filters: Use cookies or sessions to remember selections.

Conclusion

Creating a custom search form with filters in WordPress helps users find content faster and improves UX. By customizing pre_get_posts and adding category or custom field filters, you can build powerful, precise search functionality — all without relying on plugins.

Give users control. Make search intuitive.

Avatar

Written by

satoshi

I’ve been building and customizing WordPress themes for over 10 years. In my free time, you’ll probably find me enjoying a good football match.