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:
- expects that you've created your own
search()
function, which returns an array with post id. (eg.: Eg.:[ [ 'id' => 1 ], [ 'id' => 2 ] ]
) - includes pagination
- tested (using WP Loop plugin) with Twenty Twenty-Four and Twenty Twenty-Five
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;
}