Pagination broken when merging search results with additional WP_Query

I think the only solution is to skip the sql pagination and handle it only via php.
My idea involves 2 functions, one hooked on pre_get_posts, the second to filter the_posts.

The first function does 2 things:

  1. unset the paged value for search, in this way all the posts are returned from the SQL query.
  2. save the queried paged value in global variable, in this way can be used in the second function that run later

Here the function:

function filter_my_search_query( $query ) {
  if ( is_search() && $query->is_main_query() && ! is_admin() ) {
    global $the_original_paged;
    $the_original_paged = $query->get('paged') ? $query->get('paged') : 1;
    $query->set('paged', NULL );
    $query->set('nopaging', TRUE );
  }
}
add_action('pre_get_posts', 'filter_my_search_query', 1);

Now the search query return all the posts, with no pagination, and the paged required is saved in the global variable $the_original_paged.

So we can filter the_posts merging the wanted additional posts, then get only the correct posts based on required page and posts per page setting, and finally reset the paged and other $wp_query properties to let pagination link works:

function add_posts_to_search_query( $posts ) {
  global $wp_query, $the_original_paged;
  if ( ! is_main_query() || is_admin() || ! is_search() || is_null($the_original_paged) )
      return $posts;
  // the wanted posts per page here setted on general settings
  $perpage = get_option('posts_per_page'); 
  remove_filter( 'the_posts', 'add_posts_to_search_query' );
  $new = new WP_Query( 'year=2012&monthnum=12&day=12&nopaging=1' );
  $merged = array_merge( $posts, $new->posts );
  $wp_query->found_posts += $new->found_posts;
  // getting the right posts based on current page and posts per page
  $wp_query->posts = array_slice($merged, ( $perpage * ($the_original_paged-1) ), $perpage );
  // set the paged and other wp_query properties to the right value, to make pagination work
  $wp_query->set('paged', $the_original_paged);
  $wp_query->post_count = count($wp_query->posts);
  $wp_query->max_num_pages = ceil( $wp_query->found_posts / $perpage ); 
  unset($the_original_paged); // clean up global variable
  return $wp_query->posts; 
}
add_filter('the_posts', 'add_posts_to_search_query');

Leave a Comment