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.