EDIT – ANSWER REVISITED
I’ve being working on another solution which is actually better the original answer. This does not involve any custom query and I think for all purposes my original answer can be dropped but kept for informational purposes
I still believe you are on the homepage and will also treat this as such. So this is my new solution
STEP 1
Remove the custom query from the homepage and replace it with the default loop
<?php
if ( have_posts() ) :
// Start the Loop.
while ( have_posts() ) : the_post();
///<---YOUR LOOP--->
endwhile;
//<---YOUR PAGINATION--->
else :
//NO POSTS FOUND OR SOMETHING
endif;
?>
STEP 2
Use pre_get_posts
to alter the main query to add your custom taxonomy to the main query to display on the home page.
STEP 3
Now, get the posts_per_page
option set from the back end (which I assume is 2) and also set your offset
which we are going to use. That will be 1
as you will need 3 posts on page one and 2 on the rest
$ppg = get_option('posts_per_page');
$offset = 1;
STEP 4
On page one, you’ll need to add the offset
to posts_per_page
will add up to 3 to get your three posts on page one.
$query->set('posts_per_page', $offset + $ppp);
STEP 5
You must apply your offset
to all subsequent pages, otherwise you will get a repetition of the last post of the page on the next page
$offset = $offset + ( ($query->query_vars['paged']-1) * $ppp );
$query->set('posts_per_page',$ppp);
$query->set('offset',$offset);
STEP 6
Lastly, you need to subtract your offset from found_posts
otherwise your pagination on the last page will be wrong and give you a 404
error as the last post will be missing due to the incorrect post count
NOTE: This piece of code broke pagination on the search page. This is now fixed, see the updated code
function homepage_offset_pagination( $found_posts, $query ) {
$offset = 1;
if( $query->is_home() && $query->is_main_query() ) {
$found_posts = $found_posts - $offset;
}
return $found_posts;
}
add_filter( 'found_posts', 'homepage_offset_pagination', 10, 2 );
ALL TOGETHER
This is how your complete query will look like that should go into functions.php
function tax_and_offset_homepage( $query ) {
if ($query->is_home() && $query->is_main_query() && !is_admin()) {
$query->set( 'post_type', 'my_post_type' );
$query->set( 'post_status', 'publish' );
$query->set( 'ignore_sticky_posts', '-1' );
$tax_query = array(
array(
'taxonomy' => 'my_taxo',
'field' => 'slug',
'terms' => array('slug1', 'slug2', 'slug3')
)
);
$query->set( 'tax_query', $tax_query );
$ppp = get_option('posts_per_page');
$offset = 1;
if (!$query->is_paged()) {
$query->set('posts_per_page',$offset + $ppp);
} else {
$offset = $offset + ( ($query->query_vars['paged']-1) * $ppp );
$query->set('posts_per_page',$ppp);
$query->set('offset',$offset);
}
}
}
add_action('pre_get_posts','tax_and_offset_homepage');
function homepage_offset_pagination( $found_posts, $query ) {
$offset = 1;
if( $query->is_home() && $query->is_main_query() ) {
$found_posts = $found_posts - $offset;
}
return $found_posts;
}
add_filter( 'found_posts', 'homepage_offset_pagination', 10, 2 );