search-form.php

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.

Leave a Reply

Your email address will not be published. Required fields are marked *