I’ll build this as a powerful WordPress search-form.php template, but I’ll keep it safe: the form file will handle markup and UX, while heavier logic should stay in functions.php or inc/ files.
Below is an advanced search-form.php for your rx theme. It includes many practical search features: keyword search, category filter, post type filter, sort option, date filter, author filter, exact phrase option, title-only option, accessibility, nonce, reset button, popular quick searches, and mobile-friendly structure.
Create this file:
rx-theme/search-form.php
Then paste this code:
<?php
/**
* Advanced Search Form Template
*
* File: search-form.php
* Theme: RX Theme
*
* This file controls the WordPress search form output.
* It is loaded by get_search_form().
*
* Security:
* - Escapes all output.
* - Uses safe GET method.
* - Adds nonce for custom advanced search handling.
*
* @package RX_Theme
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$rx_unique_id = wp_unique_id( 'rx-search-form-' );
$rx_search_query = get_search_query();
$rx_current_category = isset( $_GET['cat'] ) ? absint( $_GET['cat'] ) : 0;
$rx_current_post_type = isset( $_GET['post_type'] )
? sanitize_key( wp_unslash( $_GET['post_type'] ) )
: '';
$rx_current_orderby = isset( $_GET['orderby'] )
? sanitize_key( wp_unslash( $_GET['orderby'] ) )
: 'relevance';
$rx_current_date = isset( $_GET['date_range'] )
? sanitize_key( wp_unslash( $_GET['date_range'] ) )
: '';
$rx_current_author = isset( $_GET['author'] )
? absint( $_GET['author'] )
: 0;
$rx_exact_phrase = isset( $_GET['rx_exact'] )
? absint( $_GET['rx_exact'] )
: 0;
$rx_title_only = isset( $_GET['rx_title_only'] )
? absint( $_GET['rx_title_only'] )
: 0;
$rx_available_post_types = array(
'' => esc_html__( 'All Content', 'rx-theme' ),
'post' => esc_html__( 'Posts', 'rx-theme' ),
'page' => esc_html__( 'Pages', 'rx-theme' ),
);
$rx_sort_options = array(
'relevance' => esc_html__( 'Best Match', 'rx-theme' ),
'date' => esc_html__( 'Newest First', 'rx-theme' ),
'modified' => esc_html__( 'Recently Updated', 'rx-theme' ),
'title' => esc_html__( 'Title A-Z', 'rx-theme' ),
'comment' => esc_html__( 'Most Discussed', 'rx-theme' ),
);
$rx_date_options = array(
'' => esc_html__( 'Any Time', 'rx-theme' ),
'today' => esc_html__( 'Today', 'rx-theme' ),
'week' => esc_html__( 'This Week', 'rx-theme' ),
'month' => esc_html__( 'This Month', 'rx-theme' ),
'year' => esc_html__( 'This Year', 'rx-theme' ),
);
$rx_quick_searches = array(
esc_html__( 'Health', 'rx-theme' ),
esc_html__( 'Medicine', 'rx-theme' ),
esc_html__( 'Symptoms', 'rx-theme' ),
esc_html__( 'Diagnosis', 'rx-theme' ),
esc_html__( 'Treatment', 'rx-theme' ),
);
?>
<form
role="search"
method="get"
class="rx-search-form rx-advanced-search-form"
id="<?php echo esc_attr( $rx_unique_id ); ?>"
action="<?php echo esc_url( home_url( '/' ) ); ?>"
aria-label="<?php echo esc_attr__( 'Advanced site search form', 'rx-theme' ); ?>"
>
<?php wp_nonce_field( 'rx_advanced_search_action', 'rx_advanced_search_nonce', false ); ?>
<div class="rx-search-box">
<label class="screen-reader-text" for="<?php echo esc_attr( $rx_unique_id . '-field' ); ?>">
<?php echo esc_html__( 'Search for:', 'rx-theme' ); ?>
</label>
<div class="rx-search-input-wrap">
<input
type="search"
id="<?php echo esc_attr( $rx_unique_id . '-field' ); ?>"
class="rx-search-field"
name="s"
value="<?php echo esc_attr( $rx_search_query ); ?>"
placeholder="<?php echo esc_attr__( 'Search articles, diseases, symptoms, treatments...', 'rx-theme' ); ?>"
autocomplete="off"
spellcheck="true"
enterkeyhint="search"
aria-describedby="<?php echo esc_attr( $rx_unique_id . '-help' ); ?>"
/>
<button type="submit" class="rx-search-submit" aria-label="<?php echo esc_attr__( 'Submit search', 'rx-theme' ); ?>">
<span aria-hidden="true">🔍</span>
<span class="rx-search-submit-text">
<?php echo esc_html__( 'Search', 'rx-theme' ); ?>
</span>
</button>
</div>
<p id="<?php echo esc_attr( $rx_unique_id . '-help' ); ?>" class="rx-search-help">
<?php echo esc_html__( 'Type a keyword and use filters for better results.', 'rx-theme' ); ?>
</p>
</div>
<details class="rx-search-filters" <?php echo ( $rx_current_category || $rx_current_post_type || $rx_current_date || $rx_current_author || $rx_exact_phrase || $rx_title_only ) ? 'open' : ''; ?>>
<summary class="rx-search-filter-title">
<?php echo esc_html__( 'Advanced Search Filters', 'rx-theme' ); ?>
</summary>
<div class="rx-search-filter-grid">
<div class="rx-search-filter-item">
<label for="<?php echo esc_attr( $rx_unique_id . '-category' ); ?>">
<?php echo esc_html__( 'Category', 'rx-theme' ); ?>
</label>
<?php
wp_dropdown_categories(
array(
'show_option_all' => esc_html__( 'All Categories', 'rx-theme' ),
'name' => 'cat',
'id' => $rx_unique_id . '-category',
'class' => 'rx-search-select rx-search-category',
'orderby' => 'name',
'order' => 'ASC',
'hierarchical' => true,
'hide_empty' => false,
'selected' => $rx_current_category,
'value_field' => 'term_id',
)
);
?>
</div>
<div class="rx-search-filter-item">
<label for="<?php echo esc_attr( $rx_unique_id . '-post-type' ); ?>">
<?php echo esc_html__( 'Content Type', 'rx-theme' ); ?>
</label>
<select
name="post_type"
id="<?php echo esc_attr( $rx_unique_id . '-post-type' ); ?>"
class="rx-search-select rx-search-post-type"
>
<?php foreach ( $rx_available_post_types as $rx_post_type_value => $rx_post_type_label ) : ?>
<option value="<?php echo esc_attr( $rx_post_type_value ); ?>" <?php selected( $rx_current_post_type, $rx_post_type_value ); ?>>
<?php echo esc_html( $rx_post_type_label ); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="rx-search-filter-item">
<label for="<?php echo esc_attr( $rx_unique_id . '-orderby' ); ?>">
<?php echo esc_html__( 'Sort Results', 'rx-theme' ); ?>
</label>
<select
name="orderby"
id="<?php echo esc_attr( $rx_unique_id . '-orderby' ); ?>"
class="rx-search-select rx-search-orderby"
>
<?php foreach ( $rx_sort_options as $rx_order_value => $rx_order_label ) : ?>
<option value="<?php echo esc_attr( $rx_order_value ); ?>" <?php selected( $rx_current_orderby, $rx_order_value ); ?>>
<?php echo esc_html( $rx_order_label ); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="rx-search-filter-item">
<label for="<?php echo esc_attr( $rx_unique_id . '-date-range' ); ?>">
<?php echo esc_html__( 'Date Range', 'rx-theme' ); ?>
</label>
<select
name="date_range"
id="<?php echo esc_attr( $rx_unique_id . '-date-range' ); ?>"
class="rx-search-select rx-search-date-range"
>
<?php foreach ( $rx_date_options as $rx_date_value => $rx_date_label ) : ?>
<option value="<?php echo esc_attr( $rx_date_value ); ?>" <?php selected( $rx_current_date, $rx_date_value ); ?>>
<?php echo esc_html( $rx_date_label ); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="rx-search-filter-item">
<label for="<?php echo esc_attr( $rx_unique_id . '-author' ); ?>">
<?php echo esc_html__( 'Author', 'rx-theme' ); ?>
</label>
<?php
wp_dropdown_users(
array(
'name' => 'author',
'id' => $rx_unique_id . '-author',
'class' => 'rx-search-select rx-search-author',
'show_option_all' => esc_html__( 'All Authors', 'rx-theme' ),
'selected' => $rx_current_author,
'who' => 'authors',
'include_selected' => true,
)
);
?>
</div>
<div class="rx-search-filter-item rx-search-checkboxes">
<label class="rx-search-checkbox-label">
<input
type="checkbox"
name="rx_exact"
value="1"
<?php checked( $rx_exact_phrase, 1 ); ?>
/>
<span><?php echo esc_html__( 'Exact phrase search', 'rx-theme' ); ?></span>
</label>
<label class="rx-search-checkbox-label">
<input
type="checkbox"
name="rx_title_only"
value="1"
<?php checked( $rx_title_only, 1 ); ?>
/>
<span><?php echo esc_html__( 'Search in title only', 'rx-theme' ); ?></span>
</label>
</div>
</div>
<div class="rx-search-filter-actions">
<button type="submit" class="rx-search-filter-submit">
<?php echo esc_html__( 'Apply Filters', 'rx-theme' ); ?>
</button>
<a class="rx-search-reset" href="<?php echo esc_url( home_url( '/' ) ); ?>">
<?php echo esc_html__( 'Reset Search', 'rx-theme' ); ?>
</a>
</div>
</details>
<?php if ( ! empty( $rx_quick_searches ) ) : ?>
<div class="rx-quick-searches" aria-label="<?php echo esc_attr__( 'Popular searches', 'rx-theme' ); ?>">
<strong class="rx-quick-searches-title">
<?php echo esc_html__( 'Popular:', 'rx-theme' ); ?>
</strong>
<?php foreach ( $rx_quick_searches as $rx_quick_search ) : ?>
<a
class="rx-quick-search-link"
href="<?php echo esc_url( add_query_arg( 's', rawurlencode( $rx_quick_search ), home_url( '/' ) ) ); ?>"
>
<?php echo esc_html( $rx_quick_search ); ?>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
</form>
Now add this helper code in your functions.php, otherwise some advanced filters like date range, exact phrase, title-only, and custom sorting will not fully work.
<?php
/**
* RX Theme Advanced Search Query Handler
*
* Add this to functions.php or better:
* inc/search/search-query.php
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
function rx_theme_advanced_search_query( $query ) {
if ( is_admin() || ! $query->is_main_query() || ! $query->is_search() ) {
return;
}
/*
|--------------------------------------------------------------------------
| Security nonce check
|--------------------------------------------------------------------------
| Search can still work without nonce because WordPress native search uses GET.
| But for advanced options, nonce adds an extra safety layer.
|--------------------------------------------------------------------------
*/
$has_nonce = isset( $_GET['rx_advanced_search_nonce'] ) &&
wp_verify_nonce(
sanitize_text_field( wp_unslash( $_GET['rx_advanced_search_nonce'] ) ),
'rx_advanced_search_action'
);
/*
|--------------------------------------------------------------------------
| Post type filter
|--------------------------------------------------------------------------
*/
if ( isset( $_GET['post_type'] ) ) {
$post_type = sanitize_key( wp_unslash( $_GET['post_type'] ) );
$allowed_post_types = array( 'post', 'page' );
if ( in_array( $post_type, $allowed_post_types, true ) ) {
$query->set( 'post_type', $post_type );
} else {
$query->set( 'post_type', array( 'post', 'page' ) );
}
} else {
$query->set( 'post_type', array( 'post', 'page' ) );
}
/*
|--------------------------------------------------------------------------
| Category filter
|--------------------------------------------------------------------------
*/
if ( isset( $_GET['cat'] ) && absint( $_GET['cat'] ) > 0 ) {
$query->set( 'cat', absint( $_GET['cat'] ) );
}
/*
|--------------------------------------------------------------------------
| Author filter
|--------------------------------------------------------------------------
*/
if ( isset( $_GET['author'] ) && absint( $_GET['author'] ) > 0 ) {
$query->set( 'author', absint( $_GET['author'] ) );
}
/*
|--------------------------------------------------------------------------
| Date range filter
|--------------------------------------------------------------------------
*/
if ( isset( $_GET['date_range'] ) ) {
$date_range = sanitize_key( wp_unslash( $_GET['date_range'] ) );
$date_query = array();
if ( 'today' === $date_range ) {
$date_query[] = array(
'after' => '1 day ago',
'inclusive' => true,
);
}
if ( 'week' === $date_range ) {
$date_query[] = array(
'after' => '1 week ago',
'inclusive' => true,
);
}
if ( 'month' === $date_range ) {
$date_query[] = array(
'after' => '1 month ago',
'inclusive' => true,
);
}
if ( 'year' === $date_range ) {
$date_query[] = array(
'after' => '1 year ago',
'inclusive' => true,
);
}
if ( ! empty( $date_query ) ) {
$query->set( 'date_query', $date_query );
}
}
/*
|--------------------------------------------------------------------------
| Sorting
|--------------------------------------------------------------------------
*/
if ( isset( $_GET['orderby'] ) ) {
$orderby = sanitize_key( wp_unslash( $_GET['orderby'] ) );
switch ( $orderby ) {
case 'date':
$query->set( 'orderby', 'date' );
$query->set( 'order', 'DESC' );
break;
case 'modified':
$query->set( 'orderby', 'modified' );
$query->set( 'order', 'DESC' );
break;
case 'title':
$query->set( 'orderby', 'title' );
$query->set( 'order', 'ASC' );
break;
case 'comment':
$query->set( 'orderby', 'comment_count' );
$query->set( 'order', 'DESC' );
break;
case 'relevance':
default:
$query->set( 'orderby', 'relevance' );
break;
}
}
/*
|--------------------------------------------------------------------------
| Posts per page
|--------------------------------------------------------------------------
*/
$query->set( 'posts_per_page', 12 );
}
add_action( 'pre_get_posts', 'rx_theme_advanced_search_query' );
/**
* RX exact phrase search.
*/
function rx_theme_exact_phrase_search( $search, $wp_query ) {
global $wpdb;
if ( is_admin() || ! $wp_query->is_main_query() || ! $wp_query->is_search() ) {
return $search;
}
if ( empty( $_GET['rx_exact'] ) || empty( $_GET['s'] ) ) {
return $search;
}
$search_term = sanitize_text_field( wp_unslash( $_GET['s'] ) );
if ( '' === $search_term ) {
return $search;
}
$like = '%' . $wpdb->esc_like( $search_term ) . '%';
$search = $wpdb->prepare(
" AND (
{$wpdb->posts}.post_title LIKE %s
OR {$wpdb->posts}.post_excerpt LIKE %s
OR {$wpdb->posts}.post_content LIKE %s
) ",
$like,
$like,
$like
);
return $search;
}
add_filter( 'posts_search', 'rx_theme_exact_phrase_search', 10, 2 );
/**
* RX title-only search.
*/
function rx_theme_title_only_search( $search, $wp_query ) {
global $wpdb;
if ( is_admin() || ! $wp_query->is_main_query() || ! $wp_query->is_search() ) {
return $search;
}
if ( empty( $_GET['rx_title_only'] ) || empty( $_GET['s'] ) ) {
return $search;
}
$search_term = sanitize_text_field( wp_unslash( $_GET['s'] ) );
if ( '' === $search_term ) {
return $search;
}
$like = '%' . $wpdb->esc_like( $search_term ) . '%';
$search = $wpdb->prepare(
" AND {$wpdb->posts}.post_title LIKE %s ",
$like
);
return $search;
}
add_filter( 'posts_search', 'rx_theme_title_only_search', 20, 2 );
Add this CSS to your style.css:
/* RX Advanced Search Form */
.rx-advanced-search-form {
width: 100%;
max-width: 980px;
margin: 24px auto;
padding: 20px;
border: 1px solid #e5e7eb;
border-radius: 16px;
background: #ffffff;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.04);
}
.rx-search-box {
width: 100%;
}
.rx-search-input-wrap {
display: flex;
gap: 10px;
align-items: stretch;
width: 100%;
}
.rx-search-field {
width: 100%;
min-height: 52px;
padding: 12px 16px;
font-size: 16px;
line-height: 1.4;
border: 1px solid #d1d5db;
border-radius: 12px;
background: #ffffff;
color: #111827;
outline: none;
}
.rx-search-field:focus {
border-color: #2563eb;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}
.rx-search-submit,
.rx-search-filter-submit {
min-height: 52px;
padding: 12px 20px;
border: none;
border-radius: 12px;
background: #2563eb;
color: #ffffff;
font-size: 15px;
font-weight: 700;
cursor: pointer;
transition: 0.2s ease;
}
.rx-search-submit:hover,
.rx-search-filter-submit:hover {
background: #1d4ed8;
}
.rx-search-help {
margin: 8px 0 0;
font-size: 14px;
color: #6b7280;
}
.rx-search-filters {
margin-top: 18px;
padding: 16px;
border: 1px solid #e5e7eb;
border-radius: 14px;
background: #f9fafb;
}
.rx-search-filter-title {
font-weight: 700;
cursor: pointer;
color: #111827;
}
.rx-search-filter-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
margin-top: 18px;
}
.rx-search-filter-item label {
display: block;
margin-bottom: 6px;
font-size: 14px;
font-weight: 700;
color: #374151;
}
.rx-search-select {
width: 100%;
min-height: 44px;
padding: 8px 12px;
border: 1px solid #d1d5db;
border-radius: 10px;
background: #ffffff;
color: #111827;
}
.rx-search-checkboxes {
display: flex;
flex-direction: column;
gap: 10px;
justify-content: center;
}
.rx-search-checkbox-label {
display: flex !important;
gap: 8px;
align-items: center;
margin: 0;
font-weight: 600;
}
.rx-search-filter-actions {
display: flex;
gap: 12px;
align-items: center;
margin-top: 18px;
}
.rx-search-reset {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 44px;
padding: 10px 16px;
border-radius: 10px;
background: #e5e7eb;
color: #111827;
font-weight: 700;
text-decoration: none;
}
.rx-search-reset:hover {
background: #d1d5db;
}
.rx-quick-searches {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
margin-top: 16px;
}
.rx-quick-searches-title {
margin-right: 4px;
color: #374151;
}
.rx-quick-search-link {
display: inline-flex;
padding: 6px 12px;
border-radius: 999px;
background: #eff6ff;
color: #1d4ed8;
font-size: 14px;
font-weight: 700;
text-decoration: none;
}
.rx-quick-search-link:hover {
background: #dbeafe;
}
.screen-reader-text {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
@media (max-width: 768px) {
.rx-search-input-wrap {
flex-direction: column;
}
.rx-search-filter-grid {
grid-template-columns: 1fr;
}
.rx-search-filter-actions {
flex-direction: column;
align-items: stretch;
}
.rx-search-submit,
.rx-search-filter-submit,
.rx-search-reset {
width: 100%;
}
}
Use it anywhere in your theme like this:
<?php get_search_form(); ?>
Best places:
header.php
sidebar.php
search.php
404.php
template-parts/content-none.php
For your RX theme, this is a strong and safe structure: search-form.php gives the visible search UI, and functions.php makes the advanced filters actually work.