I have a page on a current project where I've successfully set up AJAX post filtering, so the user can click on a checkbox and filter the posts by the category the corresponds to it. I've also mostly successfully set up AJAX post loading where the user scrolls to the bottom and more posts are loaded in. I'll describe my problem and then post my code.
My Problem
When the new posts load in on scroll by AJAX, they aren't in the right category (or categories, depending on which checkboxes are clicked). Also, I have it set to load in 9 new posts at a time, and they're just repeating the same 9 posts every time.
My Code
In my functions.php file, I have the following code:
// Setup AJAX for filter posts by category and for load more button
function ajax_filter_posts_scripts() {
// Enqueue script
wp_register_script('afp_script', get_stylesheet_directory_uri() . '/js/ajax-filter-posts.js', false, null, false);
wp_enqueue_script('afp_script');
global $wp_query;
wp_localize_script( 'afp_script', 'afp_vars', array(
'afp_ajax_url' => admin_url( 'admin-ajax.php' ),
'posts' => json_encode( $wp_query->query_vars ), // everything about your loop is here
'current_page' => get_query_var( 'paged' ) ? get_query_var('paged') : 1,
'max_page' => $wp_query->max_num_pages
)
);
}
add_action('wp_enqueue_scripts', 'ajax_filter_posts_scripts', 100);
// Filter posts by category
function prefix_load_cat_posts () {
$cat_id = $_POST['category__in'];
$args = array (
'post_type' => 'post',
'post_status' => 'publish',
'category__in' => $cat_id,
'posts_per_page' => 9,
'orderby' => 'date',
'order' => 'DESC',
);
$filter_posts = new WP_Query($args);
ob_start ();
if ( $filter_posts->have_posts() ) : while ( $filter_posts->have_posts() ) : $filter_posts->the_post(); ?>
<article class="article-card">
<header class="card-header">
<div class="card-img" style="background: url('<?php echo the_post_thumbnail_url( 'small' ); ?>') no-repeat center center; width: 100%; background-size: cover;"></div>
<?php the_title( "<h4 class='article-title'>", "</h4>" ) ?>
<p class="article-author">By
<?php the_author(); ?>
</p>
</header>
<div class="card-content">
<p>
<?php echo wp_trim_words(get_post_meta(get_the_ID(), '_yoast_wpseo_metadesc', true), 15, '...'); ?>
</p>
</div>
<footer class="card-footer">
<a href="<?php the_permalink(); ?>" class="btn btn-article" role="button">Read Now</a>
</footer>
</article>
<?php $post_count = $filter_posts->current_post + 1; ?>
<?php if ($post_count % 3 == 0): ?>
<div class="ad-wrapper">
<?php the_ad(202070); ?>
</div>
<?php
endif;
endwhile; endif;
wp_reset_postdata();
$response = ob_get_contents();
ob_end_clean();
echo $response;
die(1);
}
add_action( 'wp_ajax_nopriv_load-filter', 'prefix_load_cat_posts' );
add_action( 'wp_ajax_load-filter', 'prefix_load_cat_posts' );
// AJAX Load More
function afp_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';
$args['category__in'] = $cat_id;
$args['order'] = 'DESC';
$args['orderby'] = 'date';
$args['offset'] = 9;
$args['posts_per_page'] = 9;
var_dump($args);
ob_start();
$loop = new WP_Query( $args );
if( $loop->have_posts() ): while( $loop->have_posts() ): $loop->the_post();
?>
<article class="article-card">
<header class="card-header">
<div class="card-img" style="background: url('<?php echo the_post_thumbnail_url( 'small' ); ?>') no-repeat center center; width: 100%; background-size: cover;"></div>
<?php the_title( "<h4 class='article-title'>", "</h4>" ) ?>
<p class="article-author">By
<?php the_author(); ?>
</p>
</header>
<div class="card-content">
<p>
<?php echo wp_trim_words(get_post_meta(get_the_ID(), '_yoast_wpseo_metadesc', true), 15, '...'); ?>
</p>
<p><?php $category = get_the_category(); echo $category[0]->cat_name; ?></p>
</div>
<footer class="card-footer">
<a href="<?php the_permalink(); ?>" class="btn btn-article" role="button">Read Now</a>
</footer>
</article>
<?php $post_count = $loop->current_post + 1; ?>
<?php if ($post_count % 3 == 0): ?>
<div class="ad-wrapper">
<?php the_ad(202070); ?>
</div>
<?php
endif;
endwhile; endif; wp_reset_postdata();
$res = ob_get_contents();
ob_end_clean();
echo $res;
wp_die();
}
add_action( 'wp_ajax_afp_load_more', 'afp_load_more' );
add_action( 'wp_ajax_nopriv_afp_load_more', 'afp_load_more' );
In my JavaScript file, I have this code:
// AJAX Post Filter scripts
var $checkbox = $("#filter input:checkbox");
let categoryIDs = [];
$checkbox.change((e) => {
let value = Number(e.currentTarget.value);
if ($checkbox.is(':checked')) {
categoryIDs.indexOf(value) === -1 ? (
categoryIDs.push(value)
) : (
categoryIDs = categoryIDs.filter((item) => item !== value)
)
} else {
categoryIDs = [3, 4, 28, 35, 353];
// TODO: move this to the functions.php file if possible? if/else to reset var to initial array if AJAX returns empty?
}
categoryIDs.forEach((item) => {
$.ajax({
type: 'POST',
url: afp_vars.afp_ajax_url,
data: {
action: "load-filter",
category__in: categoryIDs
},
success: function (response) {
$(".filter-section").empty().html(response);
return false;
}
})
});
});
// AJAX Load More Posts scripts
// TODO: Fix this.
var canBeLoaded = true;
var bottomOffset = 1200;
var page = 2;
var loading = false;
var scrollHandling = {
allow: true,
reallow: function () {
scrollHandling.allow = true;
},
delay: 400
};
$(window).scroll(function () {
if (!loading && scrollHandling.allow) {
scrollHandling.allow = false;
setTimeout(scrollHandling.reallow, scrollHandling.delay);
if ($(document).scrollTop() > ($(document).height() - bottomOffset) && canBeLoaded == true) {
$.ajax({
type: 'POST',
url: afp_vars.afp_ajax_url,
data: {
action: "afp_load_more",
page: page,
query: afp_vars.query
},
success: function (res) {
$(".filter-section").append(res);
page += 1;
}
})
}
}
});
And lastly, I have this code in my template file:
<!-- Filter Area -->
<div class="section">
<div class="container">
<h4 class="ctr">Choose a Filter Below</h4>
<div class="article-filters">
<form id="filter">
<?php
$args = array(
'include' => array(3, 4, 28, 35, 353),
'orderby' => 'name',
'order' => 'ASC',
'posts_per_page' => -1
);
$categories = get_categories($args);
foreach( $categories as $cat ) {
$cat_id = get_cat_ID( $cat->name );
echo '<span>
<input class="checkbox-custom" type="checkbox" id="check'. $cat_id .'" name="category-checks" value="' . $cat_id . '">
<label class="checkbox-custom-label" for="check'. $cat_id .'">' . $cat->name . '</label>
</span>';
}
wp_reset_postdata();
?>
</form>
</div>
<div class="filter-section">
<?php
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'category__in' => array(3, 4, 28, 35, 353),
'posts_per_page' => 9,
'orderby' => 'date',
'order' => 'DESC'
);
$filter_posts = new WP_Query($args);
if ( $filter_posts->have_posts() ) : while ( $filter_posts->have_posts() ) : $filter_posts->the_post();
?>
<article class="article-card">
<header class="card-header">
<div class="card-img" style="background: url('<?php echo the_post_thumbnail_url( 'small' ); ?>') no-repeat center center; width: 100%; background-size: cover;"></div>
<?php the_title( "<h4 class='article-title'>", "</h4>" ) ?>
<p class="article-author">By <?php the_author(); ?></p>
</header>
<div class="card-content">
<p><?php echo wp_trim_words(get_post_meta(get_the_ID(), '_yoast_wpseo_metadesc', true), 15, '...'); ?></p>
</div>
<footer class="card-footer">
<a href="<?php the_permalink(); ?>" class="btn btn-article" role="button">Read Now</a>
</footer>
</article>
<?php $post_count = $filter_posts->current_post + 1; ?>
<?php if ($post_count % 3 == 0): ?>
<div class="ad-wrapper">
<?php the_ad(202070); ?>
</div>
<?php
endif;
endwhile; endif;
wp_reset_query();
?>
</div>
</div>
</div>
I used two or three different guides to patch this all together, so I'm sure I've made an error somewhere. Unfortunately, I can't figure out where. I don't expect anyone to do my work for me, but if you could help me find the problem, I'd be super grateful!
afp_load_more()
function is setting$args['category__in']
to$cat_id
, but I don't see$cat_id
being set anywhere in that function.