I built the ajax loader as follows.
How can I detect when it reaches the end of all posts? So that I can make the "More" button to disappear, or not clickable anymore.
In page template:
WP_Query stuff...
if ($press_posts->max_num_pages > 1) :
echo '<a class="link-button" id="load-more">More</a>';
endif;
functions.php
function more_post_ajax() {
$offset = $_POST["offset"];
$ppp = $_POST["ppp"];
header("Content-Type: text/html");
$args = array(
'cat' => 1,
'posts_per_page' => $ppp,
'offset' => $offset
);
$loop = new WP_Query($args);
while ($loop->have_posts()) { $loop->the_post();
get_template_part('template-parts/content', 'ajax');
}
exit;
}
add_action('wp_ajax_nopriv_more_post_ajax', 'more_post_ajax');
add_action('wp_ajax_more_post_ajax', 'more_post_ajax');
and javascripts:
<script>
var ajaxUrl = "<?php echo admin_url('admin-ajax.php')?>";
var page = 1;
var ppp = 6; // posts per page
jQuery("#load-more").on("click", function() {
jQuery("#load-more").addClass("disabled");
jQuery.post(ajaxUrl, {
action: "more_post_ajax",
offset: (page * ppp) + 1,
ppp: ppp
}).success(function(posts) {
page++;
jQuery("#press-listing").append(posts); // append to container
jQuery("#load-more").removeClass("disabled");
});
});
</script>
I built the ajax loader as follows.
How can I detect when it reaches the end of all posts? So that I can make the "More" button to disappear, or not clickable anymore.
In page template:
WP_Query stuff...
if ($press_posts->max_num_pages > 1) :
echo '<a class="link-button" id="load-more">More</a>';
endif;
functions.php
function more_post_ajax() {
$offset = $_POST["offset"];
$ppp = $_POST["ppp"];
header("Content-Type: text/html");
$args = array(
'cat' => 1,
'posts_per_page' => $ppp,
'offset' => $offset
);
$loop = new WP_Query($args);
while ($loop->have_posts()) { $loop->the_post();
get_template_part('template-parts/content', 'ajax');
}
exit;
}
add_action('wp_ajax_nopriv_more_post_ajax', 'more_post_ajax');
add_action('wp_ajax_more_post_ajax', 'more_post_ajax');
and javascripts:
<script>
var ajaxUrl = "<?php echo admin_url('admin-ajax.php')?>";
var page = 1;
var ppp = 6; // posts per page
jQuery("#load-more").on("click", function() {
jQuery("#load-more").addClass("disabled");
jQuery.post(ajaxUrl, {
action: "more_post_ajax",
offset: (page * ppp) + 1,
ppp: ppp
}).success(function(posts) {
page++;
jQuery("#press-listing").append(posts); // append to container
jQuery("#load-more").removeClass("disabled");
});
});
</script>
Share
Improve this question
asked Aug 22, 2018 at 20:27
StickersStickers
2521 gold badge6 silver badges17 bronze badges
5
- Have you tried instead using the REST API posts endpoint? It includes headers that tell you how many pages there are and which page you're on – Tom J Nowell ♦ Commented Aug 22, 2018 at 20:51
- @TomJNowell Thanks for the suggestion. But I don't have the knowledge for doing that at the moment. – Stickers Commented Aug 22, 2018 at 21:06
- You could ask here? It's easier than what you're doing at the moment, I would also note that you should not be returning HTML and inserting it, you should be returning data then construction the template in JS – Tom J Nowell ♦ Commented Aug 24, 2018 at 20:38
- @TomJNowell You're a moderator, you know that I can't ask without code. Can you point me to a right direction to get started quickly if possible? – Stickers Commented Aug 31, 2018 at 22:43
- If you're just asking how to do something and don't have code you can just ask. It's when you already have code that has an issue that you need to post it so that others can understand what's going on or spot things you might have missed – Tom J Nowell ♦ Commented Sep 1, 2018 at 0:07
3 Answers
Reset to default 2Page template:
<div class="entry-content">
<?php
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => '2',
'paged' => 1,
);
$my_posts = new WP_Query($args);
if ($my_posts->have_posts()) :
?>
<div class="my-posts">
<?php while ($my_posts->have_posts()) : $my_posts->the_post(); ?>
<h2><?php the_title(); ?></h2>
<?php the_excerpt(); ?>
<?php endwhile; ?>
</div>
<?php endif; ?>
<div class="loadmore">Load More...</div>
</div>
Ajax jQuery (Load more button):
<script type="text/javascript">
var ajaxurl = "<?php echo admin_url('admin-ajax.php'); ?>";
var page = 2;
jQuery(function($) {
$('body').on('click', '.loadmore', function() {
var data = {
'action': 'load_posts_by_ajax',
'page': page,
'security': '<?php echo wp_create_nonce("load_more_posts"); ?>'
};
max = <?php echo $my_posts->max_num_pages; ?>
$.post(ajaxurl, data, function(response) {
$('.my-posts').append(response);
if (page < max) {
// end of posts
}
page++;
});
});
});
</script>
Functions:
function load_posts_by_ajax_callback() {
check_ajax_referer('load_more_posts', 'security');
$paged = $_POST['page'];
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => '2',
'paged' => $paged,
);
$my_posts = new WP_Query($args);
if ($my_posts->have_posts()) :
?>
<?php while ($my_posts->have_posts()) : $my_posts->the_post(); ?>
<h2><?php the_title(); ?></h2>
<?php the_excerpt(); ?>
<?php endwhile; ?>
<?php
endif;
wp_die();
}
add_action('wp_ajax_load_posts_by_ajax', 'load_posts_by_ajax_callback');
add_action('wp_ajax_nopriv_load_posts_by_ajax', 'load_posts_by_ajax_callback');
Addition - Ajax jQuery (Load on scroll):
$(window).scroll(function() {
if ($(window).scrollTop() == $(document).height() - $(window).height()) {
var data = {
'action': 'load_posts_by_ajax',
'page': page,
'security': '<?php echo wp_create_nonce("load_more_posts"); ?>'
};
$.post(ajaxurl, data, function(response) {
$('.my-posts').append(response);
page++;
});
}
});
Source
I agree with the commenter @TomJNowell it could worth looking into the REST API. However, regarding your specific question:
Here's an idea:
- Check if there are any posts remaining in your
more_post_ajax()
function and include that in your response in addition to the posts you're sending back. For example, you could have amore_posts
boolean flag, or perhaps a count; however you'd like to do it. - On the js end of things, expand the implementation of
.success(function(posts) { ... })
to add logic that handles this new piece of information in the response. If no posts are remaining, you could disable/hide your#load-more
element and perhaps add a message to the user that no posts are remaining.
I'm not sure what exactly is in the template part that you call via get_template_part('template-parts/content', 'ajax')
or what its doing so its hard to be more specific regarding that area.
Either way, your instance of WP_Query
stored in $loop
has a posts
property that's an array of your posts. I could assume you want to send the posts
back as part of your response.
The WP_Query
property found_posts
is a count of all posts that match your criteria without consideration of your offset (i.e. its total count of posts), unless this is disabled with the arg no_found_rows
(N/A in this case). Since you know your posts per page and offset you have the information to pass back in your response if there are more posts available to load or not. Another way could be the max_num_pages
property.
You could combine these into an array/object and use wp_send_json()
or wp_send_json_success()
to send them and then process the response in js. You would need jQuery's parseJSON()
to parse the response.
If you're really married to what your template partial is outputting and liking how you are easily doing jQuery("#press-listing").append(posts)
on the js side to display it, you could capture the output of get_template_part('template-parts/content', 'ajax');
using output buffering (a little dirty) to collect it for including in your response, e.g.
ob_start();
get_template_part('template-parts/content', 'ajax');
// call ob_get_contents() and load the return value into an array or string to send back
ob_end_clean();
Change in your code $offet to $paged
variable WP_Query can keep track of the pages that will give you the total number of pages in your loop object as
$loop->max_num_pages
<script>
var ajaxUrl = "<?php echo admin_url('admin-ajax.php')?>";
var page = 1;
var ppp = 6; // posts per page
jQuery("#load-more").on("click", function() {
jQuery("#load-more").addClass("disabled");
jQuery.post(ajaxUrl, {
action: "more_post_ajax",
page: page,
ppp: ppp
}).success(function(posts) {
// execute this block only if there is post
if(posts) {
page++;
jQuery("#press-listing").append(posts); // append to container
jQuery("#load-more").removeClass("disabled");
}
});
});
</script>
And you php ajax function would be
function more_post_ajax() {
$page = $_POST["page"];
$ppp = $_POST["ppp"];
header("Content-Type: text/html");
$args = array(
'cat' => 1,
'posts_per_page' => $ppp,
'paged' => $page
);
$loop = new WP_Query($args);
if($loop->max_num_pages <= $page):
while ($loop->have_posts()) { $loop->the_post();
get_template_part('template-parts/content', 'ajax');
}
exit;
else:
echo 0;
die();
endif;
}
add_action('wp_ajax_nopriv_more_post_ajax', 'more_post_ajax');
add_action('wp_ajax_more_post_ajax', 'more_post_ajax');