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 -->
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 -->
Share
Improve this question
edited Mar 29, 2019 at 16:29
user5854648
asked Mar 7, 2019 at 16:22
user5854648user5854648
16317 bronze badges
1
|
2 Answers
Reset to default 1Working Code Based On My Previous Answer
Without using nonce.. but you can check the previous answer on how you can implement a nonce check. And the code is based on your code.
misha_my_load_more_scripts()
in 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' );
misha_loadmore_ajax_handler()
in functions.php
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/post/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
front-page.php
(the #main
DIV)
$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/post/content', get_post_format() );
endwhile;
endif;
?>
</div>
<?php
wp_reset_postdata();
myloadmore.js
and content.php
No changes.
UPDATE
Actually, in my code (the one I actually tested with), I don't have the tax_query
parameter, but I mistakenly included it in the above code in the previous version of this answer (not the other one on this page).
Because a tax_query
like the following — which doesn't specify the required terms
parameter — would result in an 0 = 1
in the MySQL query, and eventually leads to no results (i.e. no posts):
$the_query = new WP_Query( array(
...
'tax_query' => array(
array(
'taxonomy' => 'topics',
'operator' => 'NOT EXISTS',
// missing the required 'terms' parameter
),
),
) );
So make certain to use tax_query
with the proper parameters.
And you may also want to use/check my myloadmore.js
script?
There are several issues with your code, such as:
The original code relies upon the global
$wp_query
object; see theglobal $wp_query;
in themisha_my_load_more_scripts()
function. But your code is using a customWP_Query
instance, which is$the_query
and which is used in themisha_loadmore_ajax_handler()
function.The
misha_loadmore_ajax_handler()
is an AJAX handler/callback and hence it shouldn't be called fromdiv#main
like so:<div id="main" class="container-fluid"> <?php misha_loadmore_ajax_handler(); ?> </div><!-- END CONTAINER -->
So the original code does work; however, for custom WP_Query
requests such as the $the_query
in your case, you'd need to put/define the AJAX JS variables after you make the WP_Query
request.
And here's how you could do that:
First off, I'm using the default code (JS/PHP) as provided on the page, and I'm using the "load posts on scroll (lazy load)" script/option.
Secondly, this is my
misha_my_load_more_scripts()
function:function misha_my_load_more_scripts() { // register our main script but do not enqueue it yet wp_register_script( 'my_loadmore', 'URL/to/the/load-more-script', array('jquery') ); wp_enqueue_script( 'my_loadmore' ); } add_action( 'wp_enqueue_scripts', 'misha_my_load_more_scripts' );
And my "main"
div
(the posts container):$current_page = max( 1, get_query_var( 'paged' ) ); $the_query = new WP_Query([ 'posts_per_page' => 5, 'paged' => $current_page, ]); ?> <div id="main"> <?php while ( $the_query->have_posts() ) : $the_query->the_post(); // This should match the one in misha_loadmore_ajax_handler(). get_template_part( 'template-parts/post/content', get_post_format() ); endwhile; ?> </div> <script> var misha_loadmore_params = { ajaxurl: '<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>', posts: '<?php echo json_encode( $the_query->query_vars ); ?>', current_page: <?php echo $current_page; ?>, max_page: <?php echo $the_query->max_num_pages; ?> }; </script> <?php wp_reset_postdata();
Those are the only changes I made and the original
misha_loadmore_ajax_handler()
code (on that page) can be used as it is.
I have tried and tested the/my code, and it is working as expected. And although I didn't use your code, I believe you can easily implement my code with your code/concept.
UPDATE
If you'd like to use wp_localize_script()
(and it might be better particularly if you wish to include translated text in the JS object/data), then you need to enqueue the load-more script in the footer:
wp_register_script( 'my_loadmore', 'URL/to/the/load-more-script', array('jquery'),
'version', true );
And then in the "main" div
, remove the <script>...</script>
and add this before the wp_reset_postdata()
:
wp_localize_script( 'my_loadmore', 'misha_loadmore_params', [
'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,
// These two are optional.
'my_text' => __( 'My text', 'text-domain' ),
'security' => wp_create_nonce( 'my-load-more-posts' ),
] );
And as you can see, I've included one translation there: My text
(misha_loadmore_params.my_text
).
Using a Nonce
In the above localized data, I've also included a nonce (security
), which is specifically useful when your AJAX PHP handler is making some write operations — e.g. updating a metadata.
And you can send it to the PHP handler like so:
// This is set in the load-more script.
var data = {
'action': 'loadmore',
'query': misha_loadmore_params.posts,
'page' : misha_loadmore_params.current_page,
'security': misha_loadmore_params.security
};
And then in the PHP handler, you can do so to verify the nonce:
function misha_loadmore_ajax_handler(){
check_ajax_referer( 'my-load-more-posts', 'security' );
...
wp_die();
}
PS: This is my load-more script, with only one difference compared to the original one, which is the misha_loadmore_params.security
part.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745571692a4633719.html
$.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. – Lachlan Arthur Commented Apr 14, 2020 at 1:55