Note that with a custom WP_Query
class instance like the $homePageArticles
in your case, you should pass the max_num_pages
property of the class instance to paginate_links()
:
paginate_links( array(
'total' => $homePageArticles->max_num_pages,
) )
However, that alone will not work with custom offset which breaks the pagination, hence for example you got this issue:
it just shows the same posts on each page
But it can be fixed and it’s quite easy:
-
Calculate the offset based on the current page number and pass the offset to
WP_Query
:// Current page number. $paged = max( 1, get_query_var( 'paged' ) ); $per_page = 18; // posts per page $offset_start = 9; // initial offset $offset = $paged ? ( $paged - 1 ) * $per_page + $offset_start : $offset_start; $homePageArticles = new WP_Query( array( 'posts_per_page' => $per_page, 'offset' => $offset, 'post_type' => 'articles', // No need to set 'paged'. ) );
-
Recalculate the
max_num_pages
property and pass it topaginate_links()
:$homePageArticles->found_posts = max( 0, $homePageArticles->found_posts - $offset_start ) $homePageArticles->max_num_pages = ceil( $homePageArticles->found_posts / $per_page ); while ( $homePageArticles->have_posts() ) ... echo paginate_links( array( 'current' => $paged, 'total' => $homePageArticles->max_num_pages, ... ) );
But then, if you’re making the custom WP query in an archive template, e.g. archive-articles.php
(archive-<post type>
.php)
Then you should just forget that custom WP query.
And instead, use the pre_get_posts
hook to filter the main WP query args (to set the custom offset), then use the found_posts
hook to make sure we have the correct max_num_pages
value, then just loop through the posts in the main query.
-
In the theme functions file:
function my_pre_get_posts( $query ) { if ( ! is_admin() && $query->is_main_query() && is_post_type_archive( 'articles' ) ) { $query->set( 'offset_start', 9 ); $query->set( 'posts_per_page', 18 ); } if ( $offset = $query->get( 'offset_start' ) ) { $per_page = absint( $query->get( 'posts_per_page' ) ); $per_page = $per_page ? $per_page : max( 1, get_option( 'posts_per_page' ) ); $paged = max( 1, get_query_var( 'paged' ) ); $query->set( 'offset', ( $paged - 1 ) * $per_page + $offset ); } } add_action( 'pre_get_posts', 'my_pre_get_posts' ); function my_found_posts( $found_posts, $query ) { if ( $offset = $query->get( 'offset_start' ) ) { $found_posts = max( 0, $found_posts - $offset ); } return $found_posts; } add_filter( 'found_posts', 'my_found_posts', 10, 2 );
-
Then in your archive template:
// No need for the "new WP_Query()". while ( have_posts() ) : the_post(); ... your code. endwhile; // No need to set 'current' or 'total'. echo paginate_links( array( 'prev_text' => 'NEWER', 'next_text' => 'OLDER', ... ) );
And actually, with the custom functions in #1 above, you could simply use the custom offset_start
arg with any WP_Query
instances:
// Current page number.
$paged = max( 1, get_query_var( 'paged' ) );
$homePageArticles = new WP_Query( array(
'posts_per_page' => 18,
'offset_start' => 9, // <- set this
'post_type' => 'articles',
// No need to set 'paged' or 'offset'.
) );
while ( $homePageArticles->have_posts() ) ...
echo paginate_links( array(
'current' => $paged,
'total' => $homePageArticles->max_num_pages,
...
) );