I am trying to utilize AJAX on my WordPress site for posts as a user scrolls. I followed this tutorial but it has no effect on my WordPress website.
I have used a plugin that works, but I'd much rather learn how to do this without a plugin both to learn and also to avoid using unnecessary plugins. The below code does not work, instead all of my posts show up on the page despite posts per page being set to 5.
Help is appreciated!
functions.php
function misha_my_load_more_scripts() {
global $wp_query;
wp_enqueue_script('jquery');
wp_register_script( 'my_loadmore', get_stylesheet_directory_uri() . '/js/myloadmore.js', array('jquery') );
wp_localize_script( 'my_loadmore', 'misha_loadmore_params', array(
'ajaxurl' => site_url() . '/wp-admin/admin-ajax.php',
'posts' => json_encode( $wp_query->query_vars ),
'current_page' => get_query_var( 'paged' ) ? get_query_var('paged') : 1,
'max_page' => $wp_query->max_num_pages
) );
wp_enqueue_script( 'my_loadmore' );
}
add_action( 'wp_enqueue_scripts', 'misha_my_load_more_scripts' );
function misha_loadmore_ajax_handler(){
$args = array(
'cat' => -21,
'post_type' => 'post',
'posts_per_page' => 5,
'paged' => 1,
'tax_query' => array(
array(
'taxonomy' => 'topics',
'operator' => 'NOT EXISTS'
)
)
);
$args = json_decode( stripslashes( $_POST['query'] ), true );
$args['paged'] = $_POST['page'] + 1; //need next page to be loaded
$args['post_status'] = 'publish';
$the_query = new WP_Query ( $args );
if($the_query->have_posts()) :
while($the_query->have_posts()) :
$the_query->the_post();
get_template_part( 'template-parts/post/content', get_post_format() );
endwhile;
endif;
die;
}
add_action('wp_ajax_loadmore', 'misha_loadmore_ajax_handler'); // wp_ajax_{action}
add_action('wp_ajax_nopriv_loadmore', 'misha_loadmore_ajax_handler'); // wp_ajax_nopriv_{action}
myloadmore.js
jQuery(function($){
var canBeLoaded = true,
bottomOffset = 2000; //I've played with this number to see if it was the offset calling posts too soon but it has no effect
$(window).scroll(function(){
var data = {
'action': 'loadmore',
'query': misha_loadmore_params.posts,
'page' : misha_loadmore_params.current_page
};
if( $(document).scrollTop() > ( $(document).height() - bottomOffset ) && canBeLoaded == true ){
$.ajax({
url : misha_loadmore_params.ajaxurl,
data:data,
type:'POST',
beforeSend: function( xhr ){
canBeLoaded = false;
},
success:function(data){
if( data ) {
$('#main').find('div:last-of-type').after( data );
canBeLoaded = true;
misha_loadmore_params.current_page++;
}
}
});
}
});
});
content.php
<div class="row">
<div class="col-sm-6">
<?php $image = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'single-post-thumbnail' ); ?>
<a href="<?php the_permalink(); ?>"><img src="<?php echo $image[0]; ?>" class="img-fluid"></a>
</div>
<div class="col-sm-6">
<?php
$categories = get_the_category();
if ( $categories ) :
$deepChild = get_deep_child_category( $categories );
?>
<p><?php echo $deepChild->name; ?></p>
<?php endif; ?>
<h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
</div>
</div><!-- END ROW-->
front-page.php
<div id="main" class="container-fluid">
<?php misha_loadmore_ajax_handler(); ?>
</div><!-- END CONTAINER -->
UPDATED CODE
This following is updated code based on answers. I am posting this because it is still not working and I may be overlooking/misunderstanding something and I want to understand where I have gone wrong.
functions.php
function misha_my_load_more_scripts() {
wp_register_script( 'my_loadmore', get_stylesheet_directory_uri() . '/js/myloadmore.js',
array( 'jquery' ), '', true );
wp_enqueue_script( 'my_loadmore' );
}
add_action( 'wp_enqueue_scripts', 'misha_my_load_more_scripts' );
function misha_loadmore_ajax_handler() {
$args = json_decode( wp_unslash( $_POST['query'] ), true );
$args['paged'] = $_POST['page'] + 1; // load the next page
$the_query = new WP_Query( $args );
if ( $the_query->have_posts() ) :
while ( $the_query->have_posts() ) : $the_query->the_post();
get_template_part( 'template-parts/content', get_post_format() );
endwhile;
endif;
wp_die();
}
add_action( 'wp_ajax_loadmore', 'misha_loadmore_ajax_handler' ); // Authenticated users
add_action( 'wp_ajax_nopriv_loadmore', 'misha_loadmore_ajax_handler' ); // Non-authenticated users
myloadmore.js
jQuery(function($){
var canBeLoaded = true, // this param allows to initiate the AJAX call only if necessary
// the distance (in px) from the page bottom when you want to load more posts,
bottomOffset = ( $( '#main > div.post:last' ).offset() || {} ).top;
$(window).scroll(function(){
if ( misha_loadmore_params.current_page >= misha_loadmore_params.max_page ) {
// console.log( 'max_page reached; AJAX canceled' );
return; // we've already reached the last page, so let's do no more AJAX.
}
var data = {
'action': 'loadmore',
'query': misha_loadmore_params.posts,
'page' : misha_loadmore_params.current_page
};
if( $(document).scrollTop() > ( $(document).height() - bottomOffset ) && canBeLoaded == true ){
$.ajax({
url : misha_loadmore_params.ajaxurl,
data: data,
type: 'POST',
beforeSend: function( xhr ){
// you can also add your own preloader here
// you see, the AJAX call is in process, we shouldn't run it again until complete
canBeLoaded = false;
},
success:function(data){
if( data ) {
$('#main').find('div.post:last-of-type').after( data ); // where to insert posts
canBeLoaded = true; // the ajax is completed, now we can run it again
misha_loadmore_params.current_page++;
bottomOffset = ( $( '#main > div.post:last' ).offset() || {} ).top
}
}
});
}
});
});
content.php
<div class="row post">
<div class="col-sm-6">
<?php $image = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'single-post-thumbnail' ); ?>
<a href="<?php the_permalink(); ?>"><img src="<?php echo $image[0]; ?>" class="img-fluid"></a>
</div>
<div class="col-sm-6">
<?php
$categories = get_the_category();
if ( $categories ) :
$deepChild = get_deep_child_category( $categories );
?>
<p><?php echo $deepChild->name; ?></p>
<?php endif; ?>
<h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
</div>
</div><!-- END ROW-->
front-page.php
<?php
$current_page = max( 1, get_query_var( 'paged' ) );
$the_query = new WP_Query( array(
'cat' => '-21',
'post_type' => 'post',
'posts_per_page' => 5,
'paged' => $current_page,
) );
wp_localize_script( 'my_loadmore', 'misha_loadmore_params', array(
'ajaxurl' => admin_url( 'admin-ajax.php', 'relative' ),
'posts' => json_encode( $the_query->query_vars ),
'current_page' => $current_page,
'max_page' => $the_query->max_num_pages
) );
?>
<div id="main" class="container-fluid">
<?php
if ( $the_query->have_posts() ) :
while ( $the_query->have_posts() ) : $the_query->the_post();
// Should match the one in misha_loadmore_ajax_handler().
get_template_part( 'template-parts/content', get_post_format() );
endwhile;
endif;
?>
</div>
<?php wp_reset_postdata(); ?>
</div><!-- END CONTAINER -->
$.ajax({ url : misha_loadmore_params.ajaxurl, data: { post_status: 'private' } })
? They can read all your private posts. What if you have WooCommerce and they use{ post_type: 'shop_order', post_status: 'any' }
? Never trust user input.