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').