Skip to content

Instantly share code, notes, and snippets.

@soderlind
Last active February 13, 2025 11:06
Create a WordPress custom search

Create a WordPress custom search

This is not a complete plugin, but a how-to. Want more, take a look at my WP Loop plugin. Search is in class-wp-loupe-search.php

Sample below:

add_filter( 'posts_pre_query', 'my_posts_pre_query', 10, 2 );

/**
 * Filter posts before the main query is executed. This is where we intercept the query 
 * and replace the results with our own. Also, we calculate the pagination parameters.
 *
 * @param array    $posts Array of posts.
 * @param \WP_Query $query WP_Query object (passed by reference).
 * @return array
 */
function my_posts_pre_query( $posts, \WP_Query $query ) {
	/**
	 * Check if we are on the main query and on the search page. If not, return to the original posts.
	 */
	if ( ! ( ! is_admin() && $query->is_main_query() && $query->is_search() && ! $query->is_admin ) ) {
		return null; // To allow WP to run its normal queries.
	}

	$query->set( 'post_type', ['post','page'] ); // add cpt if needed

	/**
	 * Hits is an array of search results. Each hit is an array with the following key:
	 * - id: The post ID
	 * Eg.: [ [ 'id' => 1 ], [ 'id' => 2 ] ]
	 */
	$hits = search( $query->query_vars[ 'search_terms' ] ); // Your search function

	// Get all search results first
	$all_posts         = create_post_objects( $hits ); // see below
	$total_found_posts = count( $all_posts );

	// Get pagination parameters
	$posts_per_page = get_option( 'posts_per_page' );
	$paged          = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
	$offset         = ( $paged - 1 ) * $posts_per_page;

	// Calculate max pages
	$max_num_pages = ceil( $total_found_posts / $posts_per_page );

	// Slice the results for current page
	$paged_posts = array_slice( $all_posts, $offset, $posts_per_page );

	// Update the main query object with pagination info
	$query->found_posts   = $total_found_posts;
	$query->max_num_pages = $max_num_pages;

	// Set query pagination properties
	$query->is_paged = $paged > 1;

	return $paged_posts;

}

/**
 * Create array with post objects
 *
 * @param array $hits Array of hits.
 * @return array
 */
function create_post_objects( $hits ) {
	$posts = [];

	foreach ( $hits as $hit ) {
		$post            = new \stdClass();
		$post->ID        = $hit[ 'id' ];

		$post = new \WP_Post( $post );
		$posts[] = $post;
	}
	return $posts;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment