0

I am currently building a WordPress site. Within this site are author pages that show first ten posts, with a load more button to get the next ten via an Ajax call. For one author in particular, it is duplicating the last post on the list and the only reason I can see is that they have a draft post within the first ten that is being counted by offset. This works flawlessly everywhere else so I can't figure out what's wrong.

Functions.php

if (!function_exists('bookreview_moreajax')) {
function bookreview_moreajax(){

    $ppp     = (isset($_POST['ppp'])) ? $_POST['ppp'] : 3;
    $cat     = (isset($_POST['cat'])) ? $_POST['cat'] : 0;
    $auth     = (isset($_POST['auth'])) ? $_POST['auth'] : 0;
    $offset  = (isset($_POST['offset'])) ? $_POST['offset'] : 0;

    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => $ppp,
        'cat'            => $cat,
        'offset'         => $offset,
        'author_name'    => $auth,
    );

    $loop = new WP_Query($args);

    $out = '';

    if ($loop -> have_posts()) :
        while ($loop -> have_posts()) :
            $loop -> the_post();
                $out = get_template_part( 'template-parts/content', 'list' );
        endwhile;
    endif;

    wp_reset_postdata();

    wp_die($out);
}
}

Ajax.js

(function ($) {

"use strict";
/*jslint browser: true*/
/*global $,console,ajaxpagination*/

//AJAX MORE POSTS

//global variables
var $content = $('.ajax_posts'),
    $pageloader = $('#more_posts'),
    $catloader = $('.categories_EBR .radio-buttons li.cat-item'),
    offset = 0,
    auth = '',
    cat = '',
    loading = false;

//show load more button and hide pagination
if (($pageloader).length) {
    $('.navigation').css('display', 'none');
    $pageloader.css('display', 'block');
}

function get_ajax_posts(ppp, method, $loader) {

    loading = true;

    //set offset depending on method
    if (method === 'append') {
        offset = $('#main').find('.type-post').length;
    } else {
        $content.css({ opacity: 0.5 });
        offset = 0;
    }

    //start ajax call
    $.ajax({
        type: 'POST',
        dataType: 'html',
        url: ajaxpagination.ajaxurl,
        data: {
            'cat': cat,
            'ppp': ppp,
            'offset': offset,
            'auth': auth,
            'action': 'bookreview_moreajax'
        },
        beforeSend : function () {
            $('body').addClass('ajax-loading');
        },
        success: function (data) {
            loading = false;
            var $data = $(data);
            if ($data.length) {
                var $newElements = $data.css({ opacity: 0 });
                //update or replace depending on method
                if (method === 'append') {
                    $content.append($newElements);
                } else if (method === 'replace') {
                    $content.html($data);
                } else {
                    console.log('Unknown method: ' + method);
                    return false;
                }
                //update Load More button with correct category
                $pageloader.data('category', cat);
                $newElements.animate({ opacity: 1 }, 200);
                $pageloader.css({ opacity: 1 }).html(ajaxpagination.loadmore);
            } else {
                $pageloader.css({ opacity: 1 }).addClass('no_more_posts').html(ajaxpagination.noposts);
            }
            $content.css({ opacity: 1});
            $loader.removeClass('ajax-loader');
            $('body').removeClass('ajax-loading');
        },
        error : function (jqXHR, textStatus, errorThrown) {
            loading = false;
            $pageloader.html($.parseJSON(jqXHR.responseText) + ' :: ' + textStatus + ' :: ' + errorThrown);
            console.log(jqXHR);
        }
    });
    offset += ppp;
    return false;
}

function get_more(event) {
    if (loading || $pageloader.hasClass('no_more_posts')) {
        console.log("Stahp!");
        return;
    }
    var ppp = 6,
        method = 'append',
        $loader = $(event.currentTarget);
    if ($pageloader.attr('data-category')) {
        cat = $pageloader.data('category');
    } else if ($pageloader.attr('data-author')) {
        auth = $pageloader.data('author');
    }
    $loader.addClass('ajax-loader');
    get_ajax_posts(ppp, method, $loader);
}

function get_cat(event) {
    event.preventDefault();
    if (loading) {
        console.log("Stahp!");
        return;
    }
    var $loader = $(event.currentTarget),
        $cats = $('.cat-item'),
        ppp = 10,
        method = 'replace';
    if (!($loader.hasClass('current-cat'))) {
        $cats.removeClass('current-cat');
        cat = $loader.attr('class').match(/\d+/)[0];
        $loader.addClass('current-cat');
    } else {
        cat = $('body').attr('class').match(/\d+/)[0];
        $cats.removeClass('current-cat');
    }
    $pageloader.removeClass('no_more_posts');
    get_ajax_posts(ppp, method, $loader);
}

//triggers
$pageloader.on('click', get_more);
$catloader.on('click', get_cat);

}(jQuery));

It just seems that when it goes to get the next ten posts, the offset number (10) seems to count the draft post and is therefore one behind what it should be, resulting in a duplicate post. Am I missing something obvious?

EDIT - When i add post_status => 'published' to the query args it skips 10 posts (same value as offset). When I force the offset to 0 it just repeats the first 10. If I remove the post status it continues to count draft posts.

EDIT2 - It turns out that it's because I have a load of private posts. By adding this to my Functions.php the problem is fixed:

    // check if user is editor or higher to allow viewing private posts
    if( current_user_can('editor') || current_user_can('administrator') ) {
        $post_status = array ('publish', 'private');
    } else {
        $post_status = array ('publish');
    }

    $args = array(
        'post_status'    => $post_status,
        'posts_per_page' => $ppp,
        'cat'            => $cat,
        'offset'         => $offset,
        'author_name'    => $auth,
    );

Still wondering why this doesn't happen automatically (as it does by default), seems a bit messy to have to do it this way. Any advice on how to do this more cleanly?

1

There is a argument for posts query is post_status. It's values are like below-

$args['post_status'] => array(                 //(string / array) - use post status. Retrieves posts by Post Status, default value i'publish'.
    'publish',                      // - a published post or page.
    'pending',                      // - post is pending review.
    'draft',                        // - a post in draft status.
    'auto-draft',                   // - a newly created post, with no content.
    'future',                       // - a post to publish in the future.
    'private',                      // - not visible to users who are not logged in.
    'inherit',                      // - a revision. see get_children.
    'trash'                         // - post is in trashbin (available with Version 2.9).
), 

So, you can filter the posts query by using this post_status. Just add the post_status to your $args which you need to pull from post like below-

    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => $ppp,
        'cat'            => $cat,
        'offset'         => $offset,
        'author_name'    => $auth,
        'post_status' => array(                 //(string / array) - use post status. Retrieves posts by Post Status, default value i'publish'.
            'publish',                      // - a published post or page.
            'pending',                      // - post is pending review.
            // 'draft',                        // - a post in draft status.
            // 'auto-draft',                   // - a newly created post, with no content.
            'future',                       // - a post to publish in the future.
            'private',                      // - not visible to users who are not logged in.
            'inherit',                      // - a revision. see get_children.
            'trash'                         // - post is in trashbin (available with Version 2.9).
        ),
    );

Hope that helps.

  • I tried just adding 'publish' and the result was that it would skip the next 10 and only show from 20 onwards. However i'll try with your suggestion and report back. Thanks – mikey242 Dec 18 '16 at 17:42
  • No good, it just seems to skip 10 posts when I do that, this is driving me up the wall as I just can't seem to figure it out. – mikey242 Dec 18 '16 at 21:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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