Custom Loop Pagination on WordPress

Edit

So, the reason that this isn’t working is because you’ve modified the question to specify that this is happening in a custom page template. Since this is the case, you’ll need to use two separate custom queries, and won’t need to bother with filtering the main query via pre_get_posts.

The first query will be the same as below. The second will be similar, but we’ll add some conditionals in to account for the featured post on the first page:

// Main posts query args
$posts_query_args = array(
    'posts_per_page' => 10
);

// Conditionally modify the query
if ( ! is_paged() ) {
    // Apply offset
    $posts_query_args['offset'] = 1;
    $posts_query_args['posts_per_page'] = 9;
}

// Run the query
$posts_query = new WP_Query( $posts_query_args );

// Loop
if ( $posts_query->have_posts() ) : while ( $posts_query->have_posts() ) : $posts_query->the_post();
    // Loop markup here
endwhile; endif;
// Reset post
wp_reset_postdata();

To get pagination working properly, you’ll need to refer to this answer.

Original Answer

I think the easiest solution would be:

  1. Use a custom query for the single, latest post
  2. Filter the main query at pre_get_posts, to apply an offset of 1

This method will assume that the latest post special styling will happen only on the first page; on subsequent pages, posts will all use the normal style. Otherwise, we’d have to add an extra fix to account for broken pagination due to our use of offset.

In the template:

// Only on the first page
if ( ! is_paged() ) {

    // Custom query - latest post
    $latest_post = new WP_Query( array(
        'posts_per_page' => 1
    ) );
    // Output latest post
    if ( $latest_post->have_posts() ) : while ( $latest_post->have_posts() ) : $latest_post->the_post();
        // Style 1 loop
    endwhile; endif;
    // Don't forget me
    wp_reset_postdata();

}

// Main query
if ( have_posts() ) : while ( have_posts() ) : the_post();
    // Style 2 loop
endwhile; endif;

// Pagination
next_posts_link();
previous_posts_link();

In functions.php:

function wpse121486_pre_get_posts( $query ) {
    // Main blog posts index, first page, main query
    if ( is_home() && ! $query->is_paged() && $query->is_main_query() ) {
        $query->set( 'posts_per_page', 9 );
        $query->set( 'offset', 1 );
    }
}
add_action( 'pre_get_posts', 'wpse121486_pre_get_posts' );

Leave a Comment