Skip to main content
14 of 14
Edited in all attempts and formatted them, sharing all insight I gathered from it. Also removed pagination functions because they serve no purpose to problemsolving

Intentionally exceed max_num_pages on main query without getting 404?

In author.php I have two loops: the default main loop that gets all posts from that author, and another custom WP_Query called $secondloop. Both queries have posts_per_page set to 3. Now I'd like to paginate both query results.

For this I've added an argument to $secondloop = new WP_Query($args):

"paged" => (get_query_var('paged')) ? get_query_var('paged') : 1;

(read: set this query's page to the same page as the main query's).

THE PROBLEM:

  • If the main loop gives me 5 posts and my $secondloop gives me 2, then calling page 2 works no problemo. It shows me the remaining 2 posts from the main loop and none from my $secondloop (since it doesn't go inside while ($secondloop->have_posts())).

  • BUT if the main loop has 2 posts and $secondloop has 5, then calling page 2 results in 404 :( I obviously want $secondloop's remaining 2 posts instead.

Changing anything inside the author.php template doesn't help, because it seems that no PHP code in there is executed any more, once WordPress detects that max_num_pages from the main loop is exceeded.

How can I "override" that behaviour?


THE CODE:

author.php (just the useful bit)

<?php if (have_posts()) { ?>
    <div class="row archive-grid">
        <?php while (have_posts()) : the_post();
            include(locate_template('parts/loop-archive-grid.php'));
            endwhile; ?>
    </div>
<?php }

$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$secondloop = new WP_Query(array(
    "post_type"      => "musikalbum",
    "posts_per_page" => 3,
    "author_name"    => get_query_var('author_name'),
    "paged"          => $paged
));

if ($secondloop->have_posts()) { ?>
    <div class="row archive-grid">
        <?php while ($secondloop->have_posts()) : $secondloop->the_post();
            get_template_part( 'parts/loop', 'album-grid' );
        endwhile; ?>
    </div>
    <?php author_page_navi( $loop );
} else {
    joints_page_navi();
} ?>

Setting the posts_per_page for my main query in my functions.php

function my_post_queries( $query ) {
  if (!is_admin() && $query->is_main_query()){
    if (is_author()){
      $query->set('posts_per_page', 3);
    } else {
      $query->set('posts_per_page', 9);
    }
  }
}
add_action( 'pre_get_posts', 'my_post_queries' );

EDIT: ATTEMPT 1

Milo pointed me to an answer that suggested to add this to my functions.php:

function my_404_override() {
  global $wp_query;
  
  if (is_author()) {
    status_header( 200 );
    $wp_query->is_404 = false;
  }
}
add_filter('template_redirect', 'my_404_override');

But it still shows me a 404 error. If I remove the if clause, then it leads me to the index.php which is not reeeally what I intended. So I need that if clause...but WordPress doesn't seem to know it yet!

Pasting the code directly to the template didn't work either, even if it's just these three lines before get_header();:

global $wp_query;
status_header( 200 );
$wp_query->is_404 = false;

EDIT: ATTEMPT 2

I ditched template_redirect for hooking into pre_get_posts:

function my_post_queries( $query ) {
  if (!is_admin() && $query->is_main_query()){
    if (is_author()){
      $query->set('posts_per_page', 3);
      // NEW CODE:
      $paged = (get_query_var('paged')) ? intval(get_query_var('paged')) : 1;
      global $original_page_request; // saves the original value of $paged because I'm about to alter it!
      if ($paged > $query->max_num_pages) {
        $query->set('paged', $query->max_num_pages);
        $original_page_request = $paged;
    } else {
      $query->set('posts_per_page', 9);
    }
 }
}
add_action( 'pre_get_posts', 'my_post_queries' );

The idea was to manually reset paged for the main query when it exceeds max_num_pages and store the "actual page" in global $original_page_request for my $secondloop to set its paged parameter to. Unfortunately though, it doesn't work. I was so happy not to see a 404 any more, but now it automatically sets the main query page to 0. Why 0?!

Because in pre_get_posts, code is executed before WordPress got its posts. There's access to $query but that's just for setting query variables, there are no posts retreived, and thus no max_num_pages to calculate from.

So that means I have no idea when I'm about to exceed max_num_pages.

I then copied the new code from my_post_queries( $query ) to another function which hooks into wp. There, max_num_pages is a valid number and is_author() is correct too. As soon as I exceed the number of posts, still no luck. 404. I could set $wp_query->is_404 = false but that returns me to the index yet again.