I think the title sums the problem up, but I'll explain more with the code below.

As you can see, I'm trying to start the loop from the second latest post for some theme reasons which forced me to alter the main loop, and I used the parameter offset to make that work, and everything worked just fine, but after I moved on with the development, I started developing the numbered pagination, and finally got surprised with my altered loop showing the same posts in every page.

I chose to use WP_Query and not touch query_posts(), as it's simple and faster, now I'm stuck with this problem, and tested everything and didn't work.

Here is the altered loop using class WP_Query:

    $paged = get_query_var( 'page' ) ? get_query_var( 'page' ) : 1;
    $args = array(
       'offset' => 1,
       'post_type'  => 'post',
       'paged'      => $paged
    $offset_loop = new WP_Query( $args );
<?php if ( $offset_loop->have_posts() ): ?>
    <?php while ( $offset_loop->have_posts() ): $offset_loop->the_post(); ?>
        <div class="blog_loop_container">
            <article class="blog_post <?php post_class(); ?>" id="post-<?php the_ID(); ?>">
                <div class="post_thumbnail"><?php the_post_thumbnail( 'medium_large' ); ?></div>
    <?php endwhile; ?>

    <?php // wp_reset_postdata(); ?>
    <?php echo thegreatguy_pagination(); ?>
<?php endif; ?>

And here is the pagination function i'm using :

function thegreatguy_pagination() {
    global $wp_query; // Calling The Global Variable Representing WP_Query Class.
    $totalPages = $wp_query->max_num_pages; // Retrieves The Maximum Pages The Blog has.
    $currentPage = max( 1, get_query_var( 'paged' ) ); // Retrieves The Number Of The Current Page.

    if ( $totalPages > 1 ) { // Check For More Pages To Return.
        return paginate_links( array(
            'format'        => 'page/%#%',
            'base'          => get_pagenum_link() . '%_%',
            'current'       => $currentPage,
            'prev_text'     => 'Previous',
            'next_text'     => 'Next'
        ) );
  • Have you verified the $paged variable on the pages that are showing the unexpected results? Commented Sep 19, 2019 at 20:39
  • Your pagination function should be able to support custom WP_Query calls - see this answer for example, or check the Codex. And you'd use thegreatguy_pagination( $offset_loop ); instead of simply thegreatguy_pagination().
    – Sally CJ
    Commented Sep 19, 2019 at 23:54
  • @czerspalace Yeah I checked and It worked as it should be, It shows page numbers based on the pagination, but don't work properly with the custom query. Commented Sep 20, 2019 at 13:07
  • @SallyCJ I'm checking right now, I'll test it out, and let you know the results, but please as you may noticed above, I'm using the parameter offset, and the pagination return the number of pages based on the main query. How can I make it work based on the altered query? Commented Sep 20, 2019 at 13:11
  • @SallyCJ After checking the functions one by one, I mentioned above the two parameters offset & paged, and I think you know they don't go together. The offset parameter breaks the entire pagination structure. Commented Sep 20, 2019 at 13:57

1 Answer 1


After few checking and testing, I figured the problem source and solved it myself, I'll share it here so anyone in future fall in the same problem, this can surely help.

As I mentioned above the problem wasn't from the pagination at all, well the pagination got broken yes, but the thing that broke it is the WP_Query parameter offset because it overridden the paged parameter which is an important parameter for pagination.

After few testings I figured how to make a clean and secured pagination after altering the WP_Query, and this is how it should be done, I'll showcase it below with a clean code and explanation.

function theme_pagination() {

    global $wp_query;
    $totalPages = $wp_query->max_num_pages ;
    $currentPage = max( 1, get_query_var( 'paged' ) );

    if ( $totalPages > 1 ) {

    $big = '9999999';
    return paginate_links( array(
        'format'        => 'page/%#%',
        'base'          => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ))),
        'current'       => $currentPage,
        'total'         => $totalPages,
        'prev_text'     => __( 'Prev', 'domain' ),
        'next_text'     => __( 'Next', 'domain' )
        ) );

I think you must be familiar with almost every parameter and function above in the function except the function given in the parameter base, which is mandatory for the pagination to work properly with the search page to not display the same posts in every page.

str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) );

As you know, my plan is to have a featured post in a separated query, and then make another second query to display the rest of posts without duplicating the featured post.

When I first tried to make it work with the offset parameter, It actually worked but it didn't agree to let the paged parameter work aswell, so I looked and thought of every method to make it work without the offset param, and here is how it worked without any problem.

This is the structure for the first query that displays the Featured Post :

$featured_args = array( 'posts_per_page'    => 1 );
$featured_loop = new WP_Query( $featured_args );

if ( $featured_loop->have_posts() ):
    while ( $featured_loop->have_posts() ): $featured_loop->the_post();
        $do_not_duplicate = $post->ID;

        <article class="featured_post">
            The body of the article goes here...
endif; ?>

Take a focus look on the variable $do_not_duplicate, I used it to store the Featured Post's ID in it, to use it later in the second query as below:

Note: If you want to store two posts (jump two posts in the next query), make sure to use it in an array like this:

$do_not_duplicate[] = $post->ID

Here's how it looks the second query, the part where we do the whole work :

if ( have_posts() ): 
    while ( have_posts() ): the_post();
        if ( $post->ID == $do_not_duplicate ) continue; ?>
            <div class="blog_loop_container">
                <article class="blog_post">
                    The body of the articles goes here...
    <?php endwhile; ?>
    <div class="pagination_container">
        <?php echo theme_pagination(); ?>
<?php endif; ?>

In the second query as you see, don't alter it, just use your basic query, just remember inside and before printing any article body, make sure to check if there's duplicated post's ID to skip it and move on like this :

if ( $post->ID == $do_not_duplicate ) continue; ?>

The variable I stored in the first Post's ID remember? I used it to check for any duplicated post to skip.

This was my approach to fix the entire pagination in the theme, in archives, search, pages, blog, and everypart of the theme, I hope it helps you, and if there's any problem, let me know below in a comment so I can help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.