# 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](https://github.com/soderlind/wp-loupe). Search is in [class-wp-loupe-search.php](https://github.com/soderlind/wp-loupe/blob/main/includes/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](https://github.com/soderlind/wp-loupe)) with [Twenty Twenty-Four](https://wordpress.org/themes/twentytwentyfour/) and [Twenty Twenty-Five](https://wordpress.org/themes/twentytwentyfive/) ```php 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; } ```