Each page (first and subsequent paginated pages) of Posts page in WordPress shows the same number of posts as set for “Blog pages show at most” setting. If you want to display a different number of posts on the first page this can be done by specifying posts_per_page
for non/paginated page(s) in a function hooked to pre_get_posts
action. However this affects pagination and results in missing post(s).
Adding the following in child theme’s functions.php fixes the pagination issue when there’s an offset for the first page.
add_action( 'pre_get_posts', 'sk_query_offset', 1 ); | |
function sk_query_offset( &$query ) { | |
// Before anything else, make sure this is the right query... | |
if ( ! ( $query->is_home() || is_main_query() ) ) { | |
return; | |
} | |
// First, define your desired offset... | |
$offset = -1; | |
// Next, determine how many posts per page you want (we'll use WordPress's settings) | |
$ppp = get_option( 'posts_per_page' ); | |
// Next, detect and handle pagination... | |
if ( $query->is_paged ) { | |
// Manually determine page query offset (offset + current page (minus one) x posts per page) | |
$page_offset = $offset + ( ( $query->query_vars['paged']-1 ) * $ppp ); | |
// Apply adjust page offset | |
$query->set( 'offset', $page_offset ); | |
} | |
else { | |
// This is the first page. Set a different number for posts per page | |
$query->set( 'posts_per_page', $offset + $ppp ); | |
} | |
} | |
add_filter( 'found_posts', 'sk_adjust_offset_pagination', 1, 2 ); | |
function sk_adjust_offset_pagination( $found_posts, $query ) { | |
// Define our offset again... | |
$offset = -1; | |
// Ensure we're modifying the right query object... | |
if ( $query->is_home() && is_main_query() ) { | |
// Reduce WordPress's found_posts count by the offset... | |
return $found_posts - $offset; | |
} | |
return $found_posts; | |
} |
Set the value of your desired offset in both the instances. In the code above it’s set to -1 meaning the first page will show 1 post less than what’s set in Settings > Reading.
References:
https://codex.wordpress.org/Making_Custom_Queries_using_Offset_and_Pagination
[…] https://sridharkatakam.com/changing-posts-per-page-first-page-without-breaking-pagination-wordpress/ […]
Thanks for the script, but it doesn’t seem to work for me. The offset is there for sure, but the pagination is completely broken. I only want five posts on the first page and ten on the rest. Instead, I get five on the first page and going to /page/2 just brings up the same five pages.
I used this fro my query in combination with your function:
function be_home_loop() {
echo ”;
$news = new WP_Query( array( ‘posts_per_page’ => 10, ‘cat’ => ‘4,5,7,58,168’, ‘paged’ => $paged ));
while ($news->have_posts()): $news->the_post(); global $post;
echo ”;
echo ‘‘ . get_the_post_thumbnail( $post->ID, ‘full’ ) . ‘‘;
echo ‘‘ . get_the_title() . ‘‘;
echo ” . get_the_excerpt() . ”;
echo ‘‘;
endwhile; wp_reset_query();
echo ”;
?>
Just in case anyone wants to use this, here’s an updated version that prevents the offset from applying on the admin (I was having issues with ACF because of this):
function sk_query_offset( &$query ) {
if ( !( $query->is_home() || is_main_query() ) || is_admin() ) return;
$offset = 2;
$ppp = get_option( 'posts_per_page' );
if ( $query->is_paged ) {
$page_offset = $offset + ( ( $query->query_vars['paged']-1 ) * $ppp );
$query->set( 'offset', $page_offset );
} else $query->set( 'posts_per_page', $offset + $ppp );
} add_action( 'pre_get_posts', 'sk_query_offset', 1 );
function sk_adjust_offset_pagination( $found_posts, $query ) {
$offset = 2;
if ( is_admin() ) return;
else if ( $query->is_home() && is_main_query() ) return $found_posts - $offset;
return $found_posts;
} add_filter( 'found_posts', 'sk_adjust_offset_pagination', 1, 2 );
Thank you for sharing this! I was having an issue with media and pages in the Menu because of the original code, but this fixed it.