Skip to main content
added info + improved function naming
Source Link

On every page load, WordPress executes these functions in their respective order:

init();
parse_request($query_args);
send_headers();
query_posts();
handle_404();
register_globals();

where the main query is finished after query_posts(). Note that in this point in time, WordPress knows the template AND all the query variables like max_num_pages.

In handle_404(), if the main query has any posts in it, the function returns and WordPress continues to load the template. Else it sends a 404 HTTP status, aborts loading the template and loads the 404 template instead.

Since WordPress 4.5, there is a filter hook called pre_handle_404. If it's set to true, handle_404() returns (whether or not the main query has any posts!) and the template continues to load.

So after a lot of fiddling around, this finally works. Add this to your functions.php:

function rerun_query_when_404ignore_404_past_max_page($bool = false, $query) {
  $paged = (get_query_var('paged')) ? intval(get_query_var('paged')) : 1;
  if (is_author() && ($paged > $query->max_num_pages))
    $bool = true;
  return $bool;
}
add_filter( 'pre_handle_404', 'rerun_query_when_404''ignore_404_past_max_page', 10, 2);

That's it.! No editing of existing functions, clean and does exactly what I wantedyou'd want it to do: prevent WP from 404ing. Just make sure to update WordPress to version 4.5 (and above)!

An unwanted side effect may be that now you can paginate untill PHP_INT_MAX and get empty pages (unless you add some get_the_author_meta() and get_wp_user_avatar() for example). You could probably memorize the maximum page number for each author in the database, then query it and compare it to $paged to set $bool to false in the function above. But I'm really happy with how it works now.

On every page load, WordPress executes these functions in their respective order:

init();
parse_request($query_args);
send_headers();
query_posts();
handle_404();
register_globals();

where the main query is finished after query_posts(). Note that in this point in time, WordPress knows the template AND all the query variables like max_num_pages.

In handle_404(), if the main query has any posts in it, the function returns and continues to load the template. Else it sends a 404 HTTP status, aborts loading the template and loads the 404 template instead.

Since WordPress 4.5, there is a filter hook called pre_handle_404. If it's set to true, handle_404() returns (whether or not the main query has any posts!) and the template continues to load.

So after a lot of fiddling around, this finally works. Add this to your functions.php:

function rerun_query_when_404($bool = false, $query) {
  $paged = (get_query_var('paged')) ? intval(get_query_var('paged')) : 1;
  if (is_author() && ($paged > $query->max_num_pages))
    $bool = true;
  return $bool;
}
add_filter( 'pre_handle_404', 'rerun_query_when_404', 10, 2);

That's it. No editing of existing functions, clean and exactly what I wanted. Just make sure to update WordPress to version 4.5 (and above)!

On every page load, WordPress executes these functions in their respective order:

init();
parse_request($query_args);
send_headers();
query_posts();
handle_404();
register_globals();

where the main query is finished after query_posts(). Note that in this point in time, WordPress knows the template AND all the query variables like max_num_pages.

In handle_404(), if the main query has any posts, the function returns and WordPress continues to load the template. Else it sends a 404 HTTP status and loads the 404 template instead.

Since WordPress 4.5, there is a filter hook called pre_handle_404. If it's set to true, handle_404() returns (whether or not the main query has any posts!) and the template continues to load.

So after a lot of fiddling around, this finally works. Add this to your functions.php:

function ignore_404_past_max_page($bool = false, $query) {
  $paged = (get_query_var('paged')) ? intval(get_query_var('paged')) : 1;
  if (is_author() && ($paged > $query->max_num_pages))
    $bool = true;
  return $bool;
}
add_filter( 'pre_handle_404', 'ignore_404_past_max_page', 10, 2);

That's it! No editing of existing functions, clean and does exactly what you'd want it to do: prevent WP from 404ing. Just make sure to update WordPress to version 4.5 (and above)!

An unwanted side effect may be that now you can paginate untill PHP_INT_MAX and get empty pages (unless you add some get_the_author_meta() and get_wp_user_avatar() for example). You could probably memorize the maximum page number for each author in the database, then query it and compare it to $paged to set $bool to false in the function above. But I'm really happy with how it works now.

added 67 characters in body
Source Link

On every page load, WordPress executes these functions in their respective order:

init();
parse_request($query_args);
send_headers();
query_posts();
handle_404();
register_globals();

where the main query is finished after query_posts(). Note that in this point in time, WordPress knows the template AND all the query variables like max_num_pages.

In handle_404(), if the main query has any posts in it, the function returns and continues to load the template. Else it sends a 404 HTTP status, aborts loading the template and loads the 404 template instead.

Since WordPress 4.5, there is a filter hook called pre_handle_404. If it's set to true, handle_404() returns (whether or not the main query has any posts!) and the template continues to load.

So after a lot of fiddling around, this finally works. Add this to your functions.php:

function rerun_query_when_404($bool = false, $query) {
  $paged = (get_query_var('paged')) ? intval(get_query_var('paged')) : 1;
  if (is_author() && ($paged > $query->max_num_pages))
    $bool = true;
  return $bool;
}
add_filter( 'pre_handle_404', 'rerun_query_when_404', 10, 2);

That's it. No editing of existing functions, clean and exactly what I wanted. Just make sure to update WordPress to version 4.5 (and above)!

On every page load, WordPress executes these functions in their respective order:

init();
parse_request($query_args);
send_headers();
query_posts();
handle_404();
register_globals();

where the main query is finished after query_posts(). Note that in this point in time, WordPress knows the template AND all the query variables like max_num_pages.

In handle_404(), if the main query has any posts in it, the function returns and continues to load the template. Else it sends a 404 HTTP status, aborts loading the template and loads the 404 template instead.

Since WordPress 4.5, there is a filter hook called pre_handle_404. If it's set to true, handle_404() returns (whether or not the main query has any posts!) and the template continues to load.

So after a lot of fiddling around, this finally works. Add this to your functions.php:

function rerun_query_when_404($bool = false, $query) {
  $paged = (get_query_var('paged')) ? intval(get_query_var('paged')) : 1;
  if (is_author() && ($paged > $query->max_num_pages))
    $bool = true;
  return $bool;
}
add_filter( 'pre_handle_404', 'rerun_query_when_404', 10, 2);

That's it. No editing of existing functions, clean and exactly what I wanted.

On every page load, WordPress executes these functions in their respective order:

init();
parse_request($query_args);
send_headers();
query_posts();
handle_404();
register_globals();

where the main query is finished after query_posts(). Note that in this point in time, WordPress knows the template AND all the query variables like max_num_pages.

In handle_404(), if the main query has any posts in it, the function returns and continues to load the template. Else it sends a 404 HTTP status, aborts loading the template and loads the 404 template instead.

Since WordPress 4.5, there is a filter hook called pre_handle_404. If it's set to true, handle_404() returns (whether or not the main query has any posts!) and the template continues to load.

So after a lot of fiddling around, this finally works. Add this to your functions.php:

function rerun_query_when_404($bool = false, $query) {
  $paged = (get_query_var('paged')) ? intval(get_query_var('paged')) : 1;
  if (is_author() && ($paged > $query->max_num_pages))
    $bool = true;
  return $bool;
}
add_filter( 'pre_handle_404', 'rerun_query_when_404', 10, 2);

That's it. No editing of existing functions, clean and exactly what I wanted. Just make sure to update WordPress to version 4.5 (and above)!

the former solution did not work, edited it
Source Link

I completely ditched the template_redirect stuff for this solution which FINALLY works. It hasn't much to do with handling 404sOn every page load, I rather altered the queryWordPress executes these functions in the pre_get_posts hooktheir respective order:

function my_post_queries( $query ) {
  if (!is_admin() && $query->is_main_query()){
    if (is_author()){
      $query->setinit('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 parse_request($paged > $query->max_num_pages$query_args) {;
        $query->setsend_headers('paged', $query->max_num_pages); 
        // THE SETTING IN THE LINE ABOVE MUST BE SET TO max_num_pages!
        // query_posts(see NOTE below)
        $original_page_request = $paged;
    } else {;
      $query->sethandle_404('posts_per_page', 9);
    }
 }
}
add_actionregister_globals( 'pre_get_posts', 'my_post_queries' );

IMPORTANT NOTE

I came across something interesting, whichwhere the main query is thatfinished after pagedquery_posts(). Note that MUST!!in this point in time, WordPress knows the template AND all the query variables be set tolike $query->max_num_pagesmax_num_pages. If you set it to 1, max_num_pages is 0, even if you

In echo $query->max_num_pageshandle_404() in a line before. It completely breaks, if the solution heremain query has any posts in it, pagination will always redirectthe function returns and continues to page 1load the template. Else it sends a 404 HTTP status, aborts loading the template and loads the 404 template instead.


 

From now onSince WordPress 4.5, there is a filter hook called get_query_var('paged')pre_handle_404 will always return the. If it's set to max_num_pagestrue of my, handle_404() returns (whether or not the main query even if it says blabla/page/2 in the URL. So I'll usehas any posts!) and the global $original_page_request for everything that needs ittemplate continues to load.

In mySo after a authorlot of fiddling around, this finally works. Add this to your functions.php, the code

  1. checks if max_num_pages is exceeded (= $original_page_request exists)

  2. shows none of my main loop's posts after the page exceeds my main query's max_num_page

  3. and then initializes my $secondloop

all in here:

// 1.
global $original_page_request;
iffunction (issetrerun_query_when_404($original_page_request)) {
    $is_within_max = false;
    $paged$bool = $original_page_request;
}false, else$query) {
    $is_within_max = true;
    $paged = (get_query_var('paged')) ? intval(get_query_var('paged')) : 1;
}

// 2.
if ($is_within_max && have_posts()) { ?>
    <div class="row archive-grid">
        <?php whileif (have_postsis_author()) :&& the_post();
          $paged > include(locate_template('parts/loop-archive$query-grid.php'>max_num_pages));
       $bool endwhile;= ?>true;
   return </div>$bool;
<?php }
 
// 3.
$loop = new WP_Query(arrayadd_filter(
    "post_type"      => "musikalbum"'pre_handle_404',
    "posts_per_page" => 3'rerun_query_when_404',
    "author_name"    => get_query_var('author_name')10,
    "paged"          => $paged
));

And in author_page_navi($loop) I've set the $paged variable similiarly:

if (isset($original_page_request))
  $paged = $original_page_request;
else
  $paged = intval(get_query_var("paged")2);

Which works like a charm! A big thank you to the commenters though which helped me find the solutionThat's it. No editing of existing functions, clean and exactly what I wanted.

I completely ditched the template_redirect stuff for this solution which FINALLY works. It hasn't much to do with handling 404s, I rather altered the query in the pre_get_posts hook:

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); 
        // THE SETTING IN THE LINE ABOVE MUST BE SET TO max_num_pages!
        // (see NOTE below)
        $original_page_request = $paged;
    } else {
      $query->set('posts_per_page', 9);
    }
 }
}
add_action( 'pre_get_posts', 'my_post_queries' );

IMPORTANT NOTE

I came across something interesting, which is that paged MUST!! be set to $query->max_num_pages. If you set it to 1, max_num_pages is 0, even if you echo $query->max_num_pages in a line before. It completely breaks the solution here, pagination will always redirect to page 1.


 

From now on, get_query_var('paged') will always return the max_num_pages of my main query even if it says blabla/page/2 in the URL. So I'll use the global $original_page_request for everything that needs it.

In my author.php, the code

  1. checks if max_num_pages is exceeded (= $original_page_request exists)

  2. shows none of my main loop's posts after the page exceeds my main query's max_num_page

  3. and then initializes my $secondloop

all in here:

// 1.
global $original_page_request;
if (isset($original_page_request)) {
    $is_within_max = false;
    $paged = $original_page_request;
} else {
    $is_within_max = true;
    $paged = get_query_var('paged') ? intval(get_query_var('paged')) : 1;
}

// 2.
if ($is_within_max && have_posts()) { ?>
    <div class="row archive-grid">
        <?php while (have_posts()) : the_post();
            include(locate_template('parts/loop-archive-grid.php'));
        endwhile; ?>
    </div>
<?php }
 
// 3.
$loop = new WP_Query(array(
    "post_type"      => "musikalbum",
    "posts_per_page" => 3,
    "author_name"    => get_query_var('author_name'),
    "paged"          => $paged
));

And in author_page_navi($loop) I've set the $paged variable similiarly:

if (isset($original_page_request))
  $paged = $original_page_request;
else
  $paged = intval(get_query_var("paged"));

Which works like a charm! A big thank you to the commenters though which helped me find the solution.

On every page load, WordPress executes these functions in their respective order:

init();
parse_request($query_args);
send_headers();
query_posts();
handle_404();
register_globals();

where the main query is finished after query_posts(). Note that in this point in time, WordPress knows the template AND all the query variables like max_num_pages.

In handle_404(), if the main query has any posts in it, the function returns and continues to load the template. Else it sends a 404 HTTP status, aborts loading the template and loads the 404 template instead.

Since WordPress 4.5, there is a filter hook called pre_handle_404. If it's set to true, handle_404() returns (whether or not the main query has any posts!) and the template continues to load.

So after a lot of fiddling around, this finally works. Add this to your functions.php:

function rerun_query_when_404($bool = false, $query) {
  $paged = (get_query_var('paged')) ? intval(get_query_var('paged')) : 1;
  if (is_author() && ($paged > $query->max_num_pages))
    $bool = true;
  return $bool;
}
add_filter( 'pre_handle_404', 'rerun_query_when_404', 10, 2);

That's it. No editing of existing functions, clean and exactly what I wanted.

added 7 characters in body
Source Link
Loading
added important note and hidden main loop posts after exceeding max_num_page in code example
Source Link
Loading
Source Link
Loading