WP_Query offset is returning post from prevois loop

On archive pages, I let WordPress handle the archive page and load the first 10 posts, then I load more posts with AJAX requests, and this AJAX request is returning weird results.

My query inside the AJAX handler looks like this:

$query_args = array(
    'post_type' = 'post',
    'posts_per_page' = get_option( 'posts_per_page' ), // 10 by default
    'offset' = get_option( 'posts_per_page' ), // 10 by default
    'cat' = 8 // the category ID
);
$wp_query_archive = new WP_Query( $query_args );

The problem: If the post count of the AJAX query is less than 10, i get one duplicate post.

If the posts were numbered, the first query (the default archive query that returns the first 10 posts in selected category) returns: 1,2,3,4,5,6,7,8,9,10, the second query made by AJAX request and described above returns: 10,11. Which then results in post duplication on front end.

However, if there is 10 or more post for the AJAX query, the query returns: 11,12,13,14,15,16,17,18,19,20

If there is only one post returned by the AJAX query, the query returns only that one post: 11, which is right, but when there are two posts to return, the query returns: 10,11,12.

When there's 5 posts for the AJAX query, the query returns the right posts too, meaning: 11,12,13,14,15

Is there some magic to WP_Query() that makes it behave this way?

Addition: I can't use paged query parameter, as Jacob Peattie pointed out, because I am using that query to load posts from multiple "pages" when the user hits page with hash containing string "#page3" for example.

Topic offsets post-duplication ajax wp-query Wordpress

Category Web


Fixed it. After all it was really dumb error on my part. The WP_Query() does not filter out unpublished posts by default. The internal archive page query does filter these posts out.

I had to add 'post_status' => 'publish' to the $query_args array and everything is now working as expected.

The final query then looks like this:

$query_args = array(
    'post_status' => 'publish'
    'post_type' => 'post',
    'posts_per_page' => get_option( 'posts_per_page' ), // 10 by default
    'offset' => get_option( 'posts_per_page' ), // 10 by default
    'cat' => 8 // the category ID
);

Just use the paged parameter to get the 2nd (or 3rd or 4th etc.) page:

$query_args = array(
    'post_type' => 'post',
    'paged'     => 2,
    'cat'       => 8
);
$wp_query_archive = new WP_Query( $query_args );

If you keep track of which page you're up to in JS then you can just pass that page number directly into paged to get the right posts.

PS: You were missing a > for the cat argument, and if you're getting the category by ID you should use an integer. I've corrected both of these in my example.

EDIT: If you need to handle multiple pages at once on initial load, based on the URL hash, then handle that with a different parameter in AJAX:

$query_args = array(
    'post_type' => 'post',
    'cat'       => 8
);

if ( isset( $_GET['pages'] ) ) {
    $query_args['posts_per_page'] = $_GET['pages'] * get_option( 'posts_per_page' );
} else if ( isset( $GET['page'] ) ) {
    $query_args['paged'] = $_GET['page'];
}

$wp_query_archive = new WP_Query( $query_args );

Then in your JS, if you want multiple pages at once send pages with the number of pages worth of posts that you want, but when loading more send page with the specific page number you are after.

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.