Changing the posts per page on first page without breaking pagination in WordPress

Posted on

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.