Lazy Load using WP_Query pagination

Take a look at this rough example. This requires a little bit of adaptation but as a whole, it does what you want – it loads X amount of next posts if user clicks a button which should be below already loaded posts.

If you want to automatically load more posts if user scrolls down, just replace click event with some other code that keeps an eye on scrolling. There’s plenty of examples online.

  • Keep an eye on jQuery('some-html-element')-s, make sure to rename these element names or change your own HTML to make them fit
  • Total posts count: you can make it visible if you want users to see total posts count or use CSS opacity to hide it. It still needs to be somewhere in order to have a place to store the value

This goes to your main .js:

This function handles all the DOM manipulation and ajax. It can be called however you wish.

//ajaxLock is just a flag to prevent double clicks and spamming
var ajaxLock = false;

if( ! ajaxLock ) {

    function ajax_next_posts() {

        ajaxLock = true;

        //How many posts there's total
        var totalPosts = parseInt( jQuery( '#total-posts-count' ).text() );
        //How many have been loaded
        var postOffset = jQuery( '.single-post' ).length;
        //How many do you want to load in single patch
        var postsPerPage = 24;

        //Hide button if all posts are loaded
        if( totalPosts < postOffset + ( 1 * postsPerPage ) ) {

            jQuery( '#more-posts-button' ).fadeOut();
        }

        //Change that to your right site url unless you've already set global ajaxURL
        var ajaxURL = 'http://www.my-site.com/wp-admin/admin-ajax.php';

        //Parameters you want to pass to query
        var ajaxData="&post_offset=" + postOffset + '&action=ajax_next_posts';

        //Ajax call itself
        jQuery.ajax({

            type: 'get',
            url:  ajaxURL,
            data: ajaxData,
            dataType: 'json',

            //Ajax call is successful
            success: function ( response ) {

                //Add new posts
                jQuery( '#posts-container' ).append( response[0] );
                //Update the count of total posts
                jQuery( '#total-posts-count' ).text( response[1] );

                ajaxLock = false;
            },

            //Ajax call is not successful, still remove lock in order to try again
            error: function () {

                ajaxLock = false;
            }
        });
    }
}

This goes to your main .js:

This is an example how to call function above with button, this is better in my opinion, user can choose if he/she wants to see more..

//Load more posts button
jQuery( '#more-posts-button' ).click( function( e ) {

    e.preventDefault(); 

    ajax_next_posts(); 

});

This goes to functions.php or create a mu-plugin:

This is the function that “runs” in your server, ajax calls this, it does it’s thing and sends results back.

//More posts - first for logged in users, other for not logged in
add_action('wp_ajax_ajax_next_posts', 'ajax_next_posts');
add_action('wp_ajax_nopriv_ajax_next_posts', 'ajax_next_posts');

function ajax_next_posts() {

    //Build query
    $args = array(
        //All your query arguments
    );

    //Get offset
    if( ! empty( $_GET['post_offset'] ) ) {

        $offset = $_GET['post_offset'];
        $args['offset'] = $offset;

        //Also have to set posts_per_page, otherwise offset is ignored
        $args['posts_per_page'] = 24;
    }

    $count_results="0";

    $query_results = new WP_Query( $args );

    //Results found
    if ( $query_results->have_posts() ) {

        $count_results = $query_results->found_posts;

        //Start "saving" results' HTML
        $results_html="";
        ob_start();

        while ( $query_results->have_posts() ) { 

            $query_results->the_post();

            //Your single post HTML here
        }    

        //"Save" results' HTML as variable
        $results_html = ob_get_clean();  
    }

    //Build ajax response
    $response = array();

    //1. value is HTML of new posts and 2. is total count of posts
    array_push ( $response, $results_html, $count_results );
    echo json_encode( $response );

    //Always use die() in the end of ajax functions
    die();  
}