WordPress Pagination Bug: Second Page Shows the Same Posts as the First

A common WordPress pagination bug causes the second (and subsequent) pages to display exactly the same posts as the first page. The fix is a single missing line in your WP_Query arguments.

Problem: A custom WP_Query loop generates correct pagination links but clicking "Page 2" loads the same posts as page 1 — the paged parameter is never passed to the query.

Solution: Pass the paged argument to WP_Query using get_query_var('paged') ?: 1. Avoid query_posts() for custom loops, and note that the query variable is paged on inner pages and page on the static front page — the distinction matters.

Here is the problematic query — it generates correct pagination links but always loads page one because it never passes the current page number to WP_Query:

<?php
$args = [
    'post_type'      => $post_type,
    'posts_per_page' => $posts_per_page,
    'order'          => 'DESC',
    'orderby'        => 'date',
];

$query       = new WP_Query( $args );
$total_pages = $query->max_num_pages;

if ( $query->have_posts() ) :
    while ( $query->have_posts() ) : $query->the_post();
        // … output
    endwhile;

    if ( $total_pages > 1 ) : ?>
        <div class="pagination">
            <?php
            $current_page = max( 1, get_query_var( 'paged' ) );
            echo paginate_links( [
                'base'      => get_pagenum_link( 1 ) . '%_%',
                'format'    => 'page/%#%',
                'current'   => $current_page,
                'total'     => $total_pages,
                'prev_text' => '',
                'next_text' => '',
            ] );
            ?>
        </div>
    <?php endif;
    wp_reset_postdata();
endif; ?>

The fix: read get_query_var('paged') before building $args and pass the result as the 'paged' argument:

<?php
$paged = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;

$args = [
    'post_type'      => $post_type,
    'posts_per_page' => $posts_per_page,
    'paged'          => $paged,
    'order'          => 'DESC',
    'orderby'        => 'date',
];

Without the 'paged' key, WP_Query always defaults to page one regardless of which page the URL points to. Adding it makes the query correctly offset the results for each page.

NOTE: If your archive or listing is set as the static front page in Settings → Reading, WordPress uses the page query variable instead of paged. In that case, replace get_query_var('paged') with get_query_var('page').