Why Does It Happen?
It’s because the number of pages in your second WP_Query
is large the number of pages in the main query.
So if there are 8 jobs, that’s 4 pages in your custom query, and 1 page in the main query. So when you go to page 2 there is no page 2 in the main query resulting in a 404. This isn’t a problem when using pre_get_posts
which modifies the main query instead of creating a second one.
A Solution
If you remove the custom WP_Query
you can revert to a standard main post loop, and standard pagination.
Then, to enforce the 2 jobs per page requirement, you can use pre_get_posts
to filter the main query before it goes to the database and add posts_per_page
:
// Lets modify the parameters on the main query
// whenever you create a WP_Query this runs, including the main query! ( aka $q )
add_action( 'pre_get_posts', 'only_2_jobs_per_page' );
function only_2_jobs_per_page( \WP_Query $q ) : void {
// we only want to change the frontend job post archives
if ( is_admin() || ! $q->is_main_query() || ! is_post_type_archive( 'jobs' ) ) {
return;
}
// we only want 2 jobs per page:
$q->set( 'posts_per_page', 2 );
}
With that your pagination will work without any of the weird hacks needed for a custom WP_Query
, your code is simpler, and it’ll be twice as fast!
This means that this code:
$loop = new WP_Query( array( 'post_type' => 'jobs', 'paged' => (get_query_var('paged')) ? get_query_var('paged') : 1, 'posts_per_page' => 2 ) );
if ( $loop->have_posts() ) :
while ( $loop->have_posts() ) : $loop->the_post(); ?>
Becomes:
if ( have_posts() ) :
while ( have_posts() ) : the_post(); ?>
And this code:
$total_pages = $loop->max_num_pages;
if ($total_pages > 1){
$big = 999999999; // need an unlikely integer
echo paginate_links( array(
'base' => str_replace( $big, '%#%', get_pagenum_link( $big ) ),
'format' => '?paged=%#%',
'current' => max( 1, get_query_var('paged') ),
'total' => $loop->max_num_pages
) );
}
wp_reset_postdata();
Becomes just:
echo paginate_links();