Here’s a suggestion for a general way to support different number of posts on the home page than on the other paginated pages. We should use the main query instead of sub-queries, if possible.
Formula
It seems to make sense to take the offset for paginated pages as:
offset_op = ( paged - 1 ) * pp_op + ( pp_fp - pp_op ) + offset_fp
= ( paged - 2 ) * pp_op + pp_fp + offset_fp
where paged
(pagination), pp_fp
(posts per first page), pp_op
(posts per other pages) and offset_fp (offset for the first page) are non-negative integers.
For paged=1
the offset is offset_fp
, else it’s offset_op
for other pages.
Example #1:
First we calculate the offset for few pages to better understand this:
For paged=1:
offset_fp = 0
For paged=2:
offset_op = (2-2)*10 + 13 + 0
= 13
For paged=3:
offset_op = (3-2)*10 + 13 + 0
= 10+13
= 23
...
Here’s a list of post indices on each page:
0,1,2,3,4,5,6,7,8,9,10,11,12 (offset_fp=0, pp_fp=13, paged=1)
13,14,15,16,17,18,19,20,21,22 (offset_op=13, pp_op=10, paged=2)
23,24,25,26, 27,28,29,30,31,32 (offset_op=23, pp_op=10, paged=3)
...
We can see that the offset matches the indices.
Example #2:
Let’s take pp_fp = 3
, pp_op = 5
, offset_fp=4
and calculate the offset_op:
For paged=1:
offset_fp = 4
For paged=2:
offset_op = (2-2)*5 + 3 + 4
= 7
For paged=3:
offset_op = (3-2)*5 + 3 + 4
= 5+3+4
= 12
...
and compare it to the indices:
4,5,6 (offset_fp=4, pp_fp=3, paged=1)
7,8,9,10,11 (offset_op=7, pp_op=5, paged=2)
12,13,14,15,16 (offset_op=12, pp_op=5, paged=3)
...
Demo Plugin
Here’s a demo implementation:
/**
* Plugin Name: WPSE demo
*/
add_action( 'pre_get_posts', function( \WP_Query $query )
{
// Nothing to do if backend or not home page or not the main query
if ( is_admin() || ! $query->is_home() || ! $query->is_main_query() )
return;
// Get current pagination
$paged = get_query_var( 'paged', 1 );
// Modify sticky posts display
$query->set( 'ignore_sticky_posts', true );
// Modify post status
$query->set( 'post_status', 'publish' );
// Edit to your needs
$pp_fp = 13; // posts per first page
$pp_op = 10; // posts per other pages
$offset_fp = 0; // offset for the first page
// Offset for other pages than the first page
$offset_op = ( $paged - 2 ) * $pp_op + $pp_fp + $offset_fp;
// Modify offset
$query->set( 'offset', $query->is_paged() ? $offset_op : $offset_fp );
// Modify posts per page
$query->set( 'posts_per_page', $query->is_paged() ? $pp_op : $pp_fp );
} );
Hope you can adjust it to your needs!