Foreach-generated custom tax queries, each with an ajax “Load more” button

I finally found some helpful information in this post: How to “Load More” posts via AJAX?

The issue ended up being a combination of counting the number of total pages of posts, and sharing that number with the hooked ajax function in functions.php.

Here’s my page template loop:

<div class="events">

    <?php
    $socal_cats = array( 'Los Angeles', 'San Diego', 'Las Vegas' );

    foreach( $socal_cats as $the_cat ) {
        $cat_slug = str_replace(' ', '-', strtolower($the_cat));
        $cat_string = str_replace('-', '_', $cat_slug);
    ?>

    <div id="<?php echo $cat_slug; ?>-events">
        <header>
            <h2><?php echo $the_cat; ?></h2>
        </header>
    <div class="events-list">

    <?php
    // WP_Query arguments
    $posts_per_page = 20;
    $paged_main = ( get_query_var('page') ) ? get_query_var('page') : 1;
    $args = array(
        'post_type'              => array( 'tribe_events' ),
        'post_status'            => array( 'publish' ),
        'posts_per_page'         => $posts_per_page,
        'paged'                  => $paged_main,
        'tax_query'              => array(
            array(
                'taxonomy'         => 'tribe_events_cat',
                'field'            => 'name',
                'terms'            => $the_cat,
            ),
        ),
    );

    // The Query
    $socalquery = new WP_Query( $args );

    // The Loop
    if ( $socalquery->have_posts() ) {

        $total_posts = $socalquery->found_posts;
        $total_pages = ( ceil( $total_posts / $posts_per_page ) + 1 );
    ?>

    <div class="posts-wrap" id="<?php echo $cat_slug; ?>" data-totalpages="<?php echo $total_pages; ?>">

    <?php
    while ( $socalquery->have_posts() ) {
        $socalquery->the_post();
        get_template_part( 'template-parts/event', 'small' );
    }

    // don't display the button if there are not enough posts
    if ( $socalquery->found_posts > $posts_per_page )
        echo '<div class="load-more-wrap"><button class="loadmore"><span class="moretext" data-page="'.$total_pages.'">Load more</span></button></div>';
    ?>
    </div><!-- .posts-wrap -->
    <?php

    } else { 

        get_template_part( 'template-parts/event', 'none' );

    }
    ?>

    </div><!-- .events-list -->
</div><!-- .*category*-events -->

<? } // end foreach ?>

<script type="text/javascript">
// Set starting values which to send from Javascript to WP query function...
var ajaxurl = "<?php echo admin_url( 'admin-ajax.php' ); ?>";

jQuery(function($) {

// When this selector is clicked
$('body').on('click', '.loadmore', function() {

    // Get ID of clicked link parent
    var clicked_cat = $(this).parent().parent().attr('id');

    // Get total pagination pages for this section
    var total_pages_for_section = $('#'+clicked_cat+'.posts-wrap').data().totalpages;
    // alert(total_pages_for_section);

    // Change link text to provide feedback
    $('#'+clicked_cat+'.posts-wrap .load-more-wrap .loadmore .moretext').text('Loading...');
    $('#'+clicked_cat+'.posts-wrap .load-more-wrap .loadmore .moretext').after('<i class="icon fas fa-sync fa-spin"></i>');
    // $('#'+clicked_cat+'.load-more-wrap .loadmore i').attr('class', 'fas fa-cog fa-spin');

    // Pick up data-page attribute from the clicked link (defaults to 2 at load)
    var clicked_page = $('#'+clicked_cat+'.posts-wrap .load-more-wrap .loadmore').find('span').data().page;

    // 1. Send this package of variables to WP query function
    var data = {
        'action': 'loadmore',
        'page': clicked_page, // page of posts to get is the number set in data-page attribute
        'clicked_cat': clicked_cat,
        'security': '<?php echo wp_create_nonce("load_more_posts"); ?>'
    };

    // 2. Send to query function and get results
    $.post(ajaxurl, data, function(response) {

        // Append the returned output to this selector
        $(response).insertBefore('#'+clicked_cat+'.posts-wrap .load-more-wrap').fadeIn(500);

        // If we have exhausted all post pages, hide the whole "Load More" link
        if (clicked_page >= total_pages_for_section) {
            $('#'+clicked_cat+'.posts-wrap .load-more-wrap').hide();
        // Otherwise, restore it and increment counter
        } else {
            // Change link text back to original
            $('#'+clicked_cat+'.posts-wrap .load-more-wrap .loadmore .moretext').text('Load More');
            $('#'+clicked_cat+'.posts-wrap .load-more-wrap .loadmore').find('svg').remove();
            // Increment "data-page" attribute of clicked link for next click
            $('#'+clicked_cat+'.posts-wrap .load-more-wrap .loadmore').find('span').data().page++;
        }
    });

});

});
</script>

</div><!-- .events -->

And functions.php:

// Events Load More button
function bos_loadmore_ajax_handler(){

    check_ajax_referer('load_more_posts', 'security');

    // 1. Query values are passed from referring page, to Javascript and to this query...
    $paged = $_POST['page'];                  // Passed from page: Which page we are on
    $clicked_cat = $_POST['clicked_cat'];     // ID of the clicked "More" link

    switch ($clicked_cat) {
        case "los-angeles":
            $event_tax_query_term = "los-angeles";
            break;
        case "san-diego":
            $event_tax_query_term = "san-diego";
            break;
        case "las-vegas":
            $event_tax_query_term = "las-vegas";
            break;
        case "bay-area":
            $event_tax_query_term = "bay-area";
            break;
        case "sacramento":
            $event_tax_query_term = "sacramento";
            break;
        case "reno":
            $event_tax_query_term = "reno";
            break;
    }

    // 3. Set query arguments
    $args = array(
        'post_type' => array( 'tribe_events' ),
        'post_status' => 'publish',
        'posts_per_page' => 10,
        'paged' => $paged,
        'tax_query' => array(
            array(
                'taxonomy'         => 'tribe_events_cat',
                'field'            => 'slug',
                'terms'            => $event_tax_query_term,
            ),
        ),
    );

    // 4. Query for posts
    $query = new WP_Query( $args );

    // 5. Send results to Javascript
    if ( $query->have_posts() ) :
        ?>
        <?php while ( $query->have_posts() ) : $query->the_post(); ?>
            <?php get_template_part( 'template-parts/event', 'small' ); ?>
        <?php endwhile; ?>
        <?php
    endif;

    wp_die();
}
add_action('wp_ajax_loadmore', 'bos_loadmore_ajax_handler'); // wp_ajax_{action}
add_action('wp_ajax_nopriv_loadmore', 'bos_loadmore_ajax_handler'); // wp_ajax_nopriv_{action}

Hope this helps someone who needs ajax load more on multiple custom WP_Querys on the same page.

Leave a Comment