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_querycomparisons (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.
🎨 Want to learn more? Visit our WordPress Customization Hub for tips and advanced techniques.