Infinite Scroll in Genesis

Posted on
5/5 - (147 votes)

This tutorial provides the steps to implement Bill Erickson’s Infinite Scroll in WordPress on the Posts page and archive pages in Genesis with minor improvements.

We are going to cover the case where user scrolling acts as the trigger to fade in the subsequent set of posts.

If you are looking for a button click trigger variation, follow this instead.

Step 1

Add the following in child theme’s functions.php:

add_action( 'wp_ajax_be_ajax_load_more', 'be_ajax_load_more' );
add_action( 'wp_ajax_nopriv_be_ajax_load_more', 'be_ajax_load_more' );
/**
 * AJAX Load More.
 *
 * @link http://www.billerickson.net/infinite-scroll-in-wordpress
 */
function be_ajax_load_more() {
    $args = isset( $_POST['query'] ) ? array_map( 'esc_attr', $_POST['query'] ) : array();
    $args['post_type'] = isset( $args['post_type'] ) ? esc_attr( $args['post_type'] ) : 'post';
    $args['paged'] = esc_attr( $_POST['page'] );
    $args['post_status'] = 'publish';

    ob_start();

    $loop = new WP_Query( $args );
    if ( $loop->have_posts() ): while( $loop->have_posts() ): $loop->the_post();
        genesis_markup( array(
            'open'    => '<article %s>',
            'context' => 'entry',
        ) );

            do_action( 'genesis_entry_header' );

            do_action( 'genesis_before_entry_content' );

            printf( '<div %s>', genesis_attr( 'entry-content' ) );
            do_action( 'genesis_entry_content' );
            echo '</div>';

            do_action( 'genesis_after_entry_content' );

            do_action( 'genesis_entry_footer' );

        genesis_markup( array(
            'close'   => '</article>',
            'context' => 'entry',
        ) );
    endwhile; endif; wp_reset_postdata();
    $data = ob_get_clean();
    wp_send_json_success( $data );
    wp_die();
}

Step 2

Create a file named load-more.js in child theme’s js directory having the following:

jQuery(function($){

    $('.post-listing').append( '<div class="loading"><img src="' + beloadmore.loadingimage + '" /></div>' );

    var loadingDiv = $('.post-listing .loading');

    var page = 2;

    var loading = false;

    var scrollHandling = {
        allow: true,
        reallow: function() {
            scrollHandling.allow = true;
        },
        delay: 1000 // (milliseconds) adjust to the highest acceptable value
    };

    $(window).scroll(function(){
        if( ! loading && scrollHandling.allow ) {
            scrollHandling.allow = false;
            setTimeout(scrollHandling.reallow, scrollHandling.delay);

            var offset = $(loadingDiv).offset().top - $(window).scrollTop();

            if( 750 > offset ) {
                loading = true;

                var data = {
                    action: 'be_ajax_load_more',
                    page: page,
                    query: beloadmore.query,
                };

                $.post(beloadmore.url, data, function(res) {
                    if( res.success) {
                        $(res.data).hide().appendTo('.post-listing').fadeIn(1000);

                        $('.post-listing').append( loadingDiv );

                        if ( page >= beloadmore.max ) {
                            $(loadingDiv).remove();
                        }

                        page = page + 1;
                        loading = false;
                    } else {
                        // console.log(res);
                    }
                }).fail(function(xhr, textStatus, e) {
                    // console.log(xhr.responseText);
                });

            }
        }
    });

});

Step 3

Upload loading.gif image (downloaded from here) to child theme’s images directory.

Step 4

Create a template part i.e., a file named content-archive.php in the child theme directory having:

add_action( 'wp_enqueue_scripts', 'be_load_more_js' );
/**
 * Javascript for Load More.
 *
 */
function be_load_more_js() {
    global $wp_query;

    $args = array(
        'url'   => admin_url( 'admin-ajax.php' ),
        'query' => $wp_query->query,
        'max' => $wp_query->max_num_pages,
        'loadingimage' => get_stylesheet_directory_uri() . '/images/loading.gif',
    );

    wp_enqueue_script( 'be-load-more', get_stylesheet_directory_uri() . '/js/load-more.js', array( 'jquery' ), '1.0', true );
    wp_localize_script( 'be-load-more', 'beloadmore', $args );

}

add_action( 'genesis_before_loop', 'sk_opening', 20 );
/**
 * Adds opening tag of a custom container for all the posts.
 *
 * A high priority of 20 to make this appear below .archive-description.
 */
function sk_opening() {
    echo '<div class="post-listing">';
}

add_action( 'genesis_after_loop', 'sk_closing' );
/**
 * Adds closing tag of a custom container for all the posts.
 */
function sk_closing() {
    echo '</div>';
}

// Removes Archive Pagination.
remove_action( 'genesis_after_endwhile', 'genesis_posts_nav' );

Step 5

Load the above template part in your desired templates i.e., create files named home.php (for the Posts page) and archive.php (for the archives) in the child theme directory both having:

get_template_part( 'content-archive' );

genesis();

References:

genesis/lib/structure/loops.php

https://gist.github.com/AlphaBlossom/845721ab5c556933de0e6092296944b5