Wordpress AJAX load more check end of posts - php

My AJAX load more function doesn't check end of posts properly - it shows preloader one more time if there are no posts. This is caused by removing pleroader's hidden class every time before send ajax request.
How should I check end of posts correct?
AJAX
If response is 0 - just hide the preloader. So preloader is shown one more time when it shouldn't be.
var page = 3;
var emptyQuery = false;
function load_posts() {
page++;
var category = $('.cat-list__item.active').data('category');
$.ajax({
url: flow.ajax_url,
type: 'POST',
beforeSend: function (jqXHR) {
$('body').addClass('loading');
if ($('.preloader').length) {
$('.preloader').removeClass('preloader--hidden');
}
},
data: {
action: 'scroll_post_load',
page: page,
category: category
},
success: function (response) {
if ( response==0 ) {
emptyQuery = true;
if ($('.preloader').length) {
$('.preloader').addClass('preloader--hidden');
}
} else {
if ($('.preloader').length) {
$('.preloader').addClass('preloader--hidden');
}
var html = response;
$(html).hide().appendTo('.posts-list').fadeIn(1000);
}
$('body').removeClass('loading');
}
});
}
// Scripts which runs on scrolling
$( window ).on( 'scroll', function() {
if( $(window).scrollTop() > $('.posts-list').height() && !$('body').hasClass('loading')) {
if(emptyQuery == false) {
load_posts();
}
}
} );
PHP
If it is the last page - returns 0 in response
function scroll_post_load(){
$paged = $_POST['page'];
$category = $_POST['category'];
if( $category=='all' || !$category ) {
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => '3',
'paged' => $paged
);
}
if( $category ) {
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => '3',
'paged' => $paged,
'cat' => $category
);
}
$wp_query = new WP_Query( $args );
if ( $wp_query->max_num_pages == get_query_var('paged')) {
return '0';
}
if ($wp_query->have_posts()) :
while ($wp_query->have_posts()) : $wp_query->the_post();
show_template('loop-post');
endwhile;
endif;
wp_die();
}
add_action('wp_ajax_scroll_post_load', 'scroll_post_load');
add_action('wp_ajax_nopriv_scroll_post_load', 'scroll_post_load');

You can resolve this if you just return in your response what is the total number of pages and then in the script check if next page is last or something.
That's how I do it usually. I always return the max number of pages along with the content so I can check if I need to execute the AJAX call one last time.

Related

jQuery AJAX call not returning results in Wordpress

I'm trying to build out a Load More button in my Wordpress app, but the AJAX return value is always 'success: false', even though I know there are more posts in the DB. I followed a tutorial I found on YouTube, but not sure what I'm missing.
JS
jQuery(document).ready(function () {
const button = document.getElementById('loadmore');
button.addEventListener('click', () => {
let current_page = document.querySelector('#main-content').dataset.page;
// let max_pages = document.querySelector('#main-content').dataset.max;
const params = {
'action': 'load_more_posts',
'current_page': current_page
}
$.post('/wp-admin/admin-ajax.php', params, (data) => {
console.log(data);
});
});
})
PHP (functions.php)
wp_enqueue_script('loadmore', get_template_directory_uri() . '/js/loadmore.js', array('jquery'), filemtime(get_template_directory() . '/js/loadmore.js'));
add_action('wp_ajax_nopriv_load_more_posts', 'load_more_posts');
add_action('wp_ajax_load_more_posts', 'load_more_posts');
function load_more_posts() {
$next_page = $_POST['current_page'] + 1;
$query = new WP_Query([
'posts_per_page' => 12,
'paged' => $next_page
]);
if ($query->has_posts()):
ob_start();
while($query->have_posts()) : $query->the_post();
get_template_parts('partials/blog','posts');
endwhile;
wp_send_json_success(ob_get_clean());
else:
wp_send_json_error('no more posts');
endif;
}
The returned result continues to be:
data: "no more posts"
success: false
One thing that usually gets me too, your ajax function should always end in a wp_die(); function call, otherwise it will always return 0, even if the rest of your code is correct.
In this instance:
function load_more_posts() {
$next_page = $_POST['current_page'] + 1;
$query = new WP_Query([
'posts_per_page' => 12,
'paged' => $next_page
]);
if ($query->have_posts()):
ob_start();
while($query->have_posts()) : $query->the_post();
get_template_parts('partials/blog','posts');
endwhile;
wp_send_json_success(ob_get_clean());
else:
wp_send_json_error('no more posts');
endif;
wp_die();
}
Looks like u are passing wrong current page number, what there is in the let current_page = document.querySelector('#main-content').dataset.page; ??

How to get Wordpress post filter (misha_filter_function) to filter CPT categories associated by a tag

Edited for Clarity:
I'm using the misha_filter_function from: https://rudrastyh.com/wordpress/ajax-post-filters.html to filter posts.
The initial array is displaying the correct posts by the location_and_season (made with ACF) tag. But something weird is going on with the second array because when I click my dropdown select to sort the posts by category it's filtering all of the posts within the post type, and effectively ignoring 'tag' => $value,
I'm relatively new to Wordpress PHP and JS, so my Google-Fu hasn't been too helpful since I don't really know what to search. Any help would be appreciated. Thanks!
Here's the filter Code:
<?php
add_action('wp_ajax_myfilter', 'misha_filter_function'); //
wp_ajax_{ACTION HERE}
add_action('wp_ajax_nopriv_myfilter', 'misha_filter_function');
function misha_filter_function()
{
$value = get_field('location_and_season');
$args = array(
'post_type' => 'shows',
'tag' => $value,
'posts_per_page' => - 1, // show all posts.
'orderby' => 'name', // we will sort posts by name
'order' => 'ASC'
//$_POST['name'] // ASC or DESC
);
// for taxonomies / categories
// IMPORTANT! Adding && !empty( $_POST['categoryfilter'] ) fixes the no posts found for All Categories
if (isset($_POST['categoryfilter']) &&
!empty($_POST['categoryfilter'])) $args['tax_query'] = array(
array(
'taxonomy' => 'category',
'field' => 'id',
'terms' => $_POST['categoryfilter']
)
);
$query = new WP_Query($args);
// The Query
query_posts($args);
// The Loop
while (have_posts()):
the_post(); ?>
Here's the front end dropdown code:
<form action="<?php echo site_url() ?>/wp-admin/admin-ajax.php"
method="POST" id="filter" style="float:right; margin-right: 15px;">
<?php
if ($terms = get_terms(array(
'taxonomy' => 'category',
'orderby' => 'name'
))):
echo '<select name="categoryfilter"><option id="refresh" value="all"
class="dropdown-select">All Topics...</option>';
foreach ($terms as $term):
echo '<option value="' . $term->term_id . '">' . $term->name .
'</option>';
endforeach;
echo '</select>';
endif;
?>
<div class="processing" style="height:30px;"></div>
<input type="hidden" name="action" value="myfilter">
</form>
And the JS
jQuery(function ($) {
$('#filter').change(function () {
var filter = $('#filter');
$.ajax({
url: filter.attr('action'),
data: filter.serialize(), // form data
type: filter.attr('method'), // POST
beforeSend: function (xhr) {
filter.find('.processing').html('<img src="spinner.gif" class="spinner">'); // changing the button label
},
success: function (data) {
filter.find('.processing').text(''); // changing the button label back
$('#response').html(data); // insert data
}
});
$(document).ready(function () {
$('#filter').on("click", function () {
$('.post-section').toggleClass("active");
});
});
return false;
});
I don't see anything that actually calls your php function. Wordpress ajax calls require an action in the data.
$.ajax({
url: filter.attr('action'),
type: filter.attr('method'), // POST
data: {
action: 'misha_filter_function',
categoryfilter: $(select['name ="categoryfilter"]').val()
},
beforeSend: function (xhr) {
filter.find('.processing').html('<img src="spinner.gif" class="spinner">'); // changing the button label
},
success: function (data) {
filter.find('.processing').text(''); // changing the button label back
$('#response').html(data); // insert data
},
failure: function(response){
console.log(response); //Debug only
}
});
Also, do you enqueue the js script with wp_localize_script?

Load More Custom Posts On Click Ajax WordPress

I'm trying to create a load more button that loads more custom post types on click, however, I keep receiving a 400 (Bad Request) error. Here is the code i'm using.
// Header.php
<!doctype html>
<html <?php language_attributes(); class="no-js">
<head>
<!-- meta tags & links --->
<script type="text/javascript">
ajaxurl = <?php echo admin_url('admin-ajax.php'); ?>;
    
// HTML:
<div class="project">
<?php
$posts_array = array(
'post_type' => 'project',
'status' => 'publish',
'order' => 'ASC',
'posts_per_page' => -1,
'paged' => $paged
);
$posts = get_posts($posts_array);
$count = 0;
?>
<?php foreach ($posts as $post) : $count++; ?>
<div class="project">
<php echo the_title(); ?>
</div>
<?php endforeach; wp_reset_query(); ?>
</div>
<button id="more_posts">Load More</button>
// JavaScript:
$("#more_posts").on("click", function() {
// When btn is pressed.
$.ajax({
url: ajaxurl,
action: "more_post_ajax",
offset: page * ppp + 1,
ppp: ppp
}).success(function(posts) {
page++;
$(".projects").append(posts);
});
});
// Functions.php
function more_post_ajax(){
$offset = $_POST["offset"];
$ppp = $_POST["ppp"];
header("Content-Type: text/html");
$args = array(
'post_type' => 'project',
'status' => 'publish',
'posts_per_page' => $ppp,
'order' => 'ASC',
'offset' => $offset,
);
$loop = new WP_Query($args);
while ($loop->have_posts()) { $loop->the_post();
the_title();
}
exit;
}
add_action('wp_ajax_nopriv_more_post_ajax', 'more_post_ajax');
add_action('wp_ajax_more_post_ajax', 'more_post_ajax');
There is a good amount here to fix.
Your Ajax is syntax is off a bit. Also, you can specify posts per page for the return with PHP, so you don't need to send that, you can keep your page attribute on the frontend.
$("#more_posts").on("click", function(e) {
$.ajax({
// use the ajax object url
url: ajax_object.ajax_url,
data: {
action: "more_post_ajax", // add your action to the data object
offset: page * 4 // page # x your default posts per page
},
success: function(data) {
// add the posts to the container and add to your page count
page++;
$('.projects').append(data);
},
error: function(data) {
// test to see what you get back on error
console.log(data);
}
});
});
For your initial PHP function, you should only specify the amount of posts you want to show at first. If you use -1 it will just show all posts at the start, which you don't want. You also don't need to use the paged parameter. You only need offsets.
<?php
$args = array(
'post_type' => 'project',
'status' => 'publish',
'order' => 'ASC',
'posts_per_page' => 4,
);
$posts = new WP_Query($args);
?>
<div class="projects">
<?php
while ($posts->have_posts()) {
$posts->the_post(); ?>
<div class="project">
<?php the_title(); ?>
</div>
<?php
wp_reset_postdata();
}; ?>
</div>
For your more posts function, you only need to specify an offset, and can add your additional posts right in that function.
function more_post_ajax(){
$offset = $_POST["offset"];
$args = array(
'post_type' => 'project',
'status' => 'publish',
'posts_per_page' => 4,
'order' => 'ASC',
'offset' => $offset,
);
$post = new WP_Query($args);
while ($post->have_posts()) { $post->the_post();
<div class="project">the_title();</div>
}
wp_reset_postdata();
die(); // use die instead of exit
}
add_action('wp_ajax_nopriv_more_post_ajax', 'more_post_ajax');
add_action('wp_ajax_more_post_ajax', 'more_post_ajax');
I have not tested this, but this should get you closer to a working set.
Just in case anyone is looking at this in the future and aren't sure on why they can't make it work theres a couple of things that need changing in the above code for starters in the js you need to define the variable page before the on click function...
var page = 1;
$("#more_posts").on("click", function(e) {
$.ajax({
// use the ajax object url
url: ajax_object.ajax_url,
data: {
action: "more_post_ajax", // add your action to the data object
offset: page * 4 // page # x your default posts per page
},
success: function(data) {
// add the posts to the container and add to your page count
page++;
$('.projects').append(data);
},
error: function(data) {
// test to see what you get back on error
console.log(data);
}
});
});
This code appends the data to the admin-ajax url which means you have to use $_GET not $_POST to retrieve the offset variable in your php function:
$offset = $_GET["offset"];

Using AJAX to load more products WooCommerce

I am using AJAX to load more products on a WooCommerce archive. I have used AJAX to "Load More" once before on this page. I have used the same code for the most part, just altered the WP_Query arguments to suit my needs. I can't understand why my code doesn't work.
JS
/**
* AJAX Load (Lazy Load) events
*/
$('#load-more').click( function(e){
e.preventDefault();
ajax_next_posts()
$('body').addClass('ajaxLoading');
});
var ajaxLock = false; // ajaxLock is just a flag to prevent double clicks and spamming
if( !ajaxLock ) {
function ajax_next_posts() {
ajaxLock = true;
// How many posts there's total
var totalPosts = parseInt( jQuery( '#found-posts' ).text() );
// How many have been loaded
var postOffset = jQuery( 'li.product' ).length
// How many do you want to load in single patch
var postsPerPage = 1;
// Ajax call itself
$.ajax({
method: 'POST',
url: leafshop.ajax_url,
data: {
action: 'ajax_next_posts',
post_offset: postOffset,
posts_per_page: postsPerPage,
product_cat: cat_id
},
dataType: 'json'
})
.done( function( response ) { // Ajax call is successful
// console.log( response );
// Add new posts
jQuery( '.product-grid' ).append( response[0] );
// Log SQL query
jQuery( '#query > pre' ).text( response[2] );
// Update the count of total posts
// jQuery( '#found-posts' ).text( response[1] );
ajaxLock = false;
console.log( 'Success' );
$('body').removeClass('ajaxLoading');
// How many posts there's total
var totalPosts = parseInt( jQuery( '#found-posts' ).text() );
console.log( "Total Posts: " + totalPosts );
// How many have been loaded
var postOffset = jQuery( 'li.product' ).length
console.log( "Posts currently showing: " + postOffset );
// Hide button if all posts are loaded
if( totalPosts < postOffset + ( 1 * postsPerPage ) ) {
jQuery( '#load-more' ).fadeOut();
}
})
// .fail( function() {
.fail( function(jqXHR, textStatus, errorThrown) { // Ajax call is not successful, still remove lock in order to try again
ajaxLock = false;
console.log(XMLHttpRequest);
console.log(textStatus);
console.log(errorThrown);
console.log( 'Failed' );
});
}
}
PHP
<?php
/**
* Load next 12 products using AJAX
*/
function ajax_next_posts() {
global $wpdb;
// Build query
$args = array(
'post_type' => 'product'
);
// Get offset
if( !empty( $_POST['post_offset'] ) ) {
$offset = $_POST['post_offset'];
$args['offset'] = $offset;
// Also have to set posts_per_page, otherwise offset is ignored
$args['posts_per_page'] = 12;
}
// Get posts per page
if( !empty( $_POST['posts_per_page'] ) ) {
// Also have to set posts_per_page, otherwise offset is ignored
$args['posts_per_page'] = $_POST['posts_per_page'];
}
// Set tax query if on cat page
if( !empty( $_POST['product_cat'] ) ){
$args['tax_query'] = array(
'taxonomy' => 'product_cat',
'terms' => array( (int)$_POST['product_cat'] ),
'field' => 'id',
'operator' => 'IN',
'include_children' => 1
);
}
$count_results = '0';
$ajax_query = new WP_Query( $args );
// Results found
if ( $ajax_query->have_posts() ) {
$count_results = $ajax_query->found_posts;
// Start "saving" results' HTML
$results_html = '';
ob_start();
while( $ajax_query->have_posts() ) {
$ajax_query->the_post();
echo wc_get_template_part( 'content', 'product' );
}
// "Save" results' HTML as variable
$results_html = ob_get_clean();
}
// Build ajax response
$response = array();
// 1. value is HTML of new posts and 2. is total count of posts
global $wpdb;
array_push ( $response, $results_html, $count_results, $wpdb->last_query );
echo json_encode( $response );
// Always use die() in the end of ajax functions
die();
}
add_action('wp_ajax_ajax_next_posts', 'ajax_next_posts');
add_action('wp_ajax_nopriv_ajax_next_posts', 'ajax_next_posts');
The AJAX call runs successfully but doesn't return what I'd expect it to. I'd expect it to return the next product from the current category, instead it returns a product from a different category. The development site is accessible on http://leaf.kalodigital.co.uk and I have been using the "Black Tea" page in my testing. Any help would be greatly appreciated.
Method
After some further research, I found that WooCommerce contains a class names WC_Poduct_Query. Following their documentation, found here, I rebuilt my query. This was working in the sense that it was querying for the correct products and returns the ones I'd expect it to as an array of WC_Product_Variable Objects. I proceeded to, within a foreach loop, use setup_postdata( $post ); to set the product Objects up so that I could use the wc_get_template_parts(); function to call the content-product.php template to format the output of the data. I found that this didn't work, although I couldn't figure to why this was the case, using setup-postdata(); was causing the object to turn into [{id:0,filter:raw},{id:0,filter:raw}]. I imagine this would be related to the WC_Product_Variable Objects not matching the expect format that setup_postdata(); usually expects from a WP_Post Object.
Nonetheless, I reverted to using WP_Query for my query, rebuilt the query script from scratch and, would you believe it, everything worked as expected to. Below is my working code to AJAX load the next "bunch" of products on any WooCommerce Archive page, at the click of a button.
Code
JS
/**
* AJAX Load (Lazy Load) events
*/
//-- Settings
// How many do you want to load each button click?
var postsPerPage = 12;
//-- /Settings
// How many posts there's total
var totalPosts = parseInt( jQuery( '#found-posts' ).text() );
// if( totalPosts == postOffset ) {
// jQuery( '#load-more' ).fadeOut();
// }
$('#load-more').click( function(e){
e.preventDefault();
// Get current category
var cat_id = $(this).data('product-category');
ajax_next_posts( cat_id );
$('body').addClass('ajaxLoading');
});
var ajaxLock = false; // ajaxLock is just a flag to prevent double clicks and spamming
if( !ajaxLock ) {
function ajax_next_posts( cat_id ) {
ajaxLock = true;
// How many have been loaded
var postOffset = jQuery( 'li.product' ).length;
// Ajax call itself
$.ajax({
method: 'POST',
url: leafshop.ajax_url,
data: {
action: 'ajax_next_posts',
post_offset: postOffset,
posts_per_page: postsPerPage,
product_cat: cat_id
},
dataType: 'json'
})
.done( function( response ) { // Ajax call is successful
// Add new posts
jQuery( '.product-grid' ).append( response[0] );
// Update Post Offset
var postOffset = jQuery( 'li.product' ).length;
ajaxLock = false;
console.log( 'Success' );
$('body').removeClass('ajaxLoading');
// How many posts there's total
console.log( "Total Posts: " + totalPosts );
// How many have been loaded
var postOffset = jQuery( 'li.product' ).length
console.log( "Posts on Page: " + postOffset );
// Hide button if all posts are loaded
if( ( totalPosts - postOffset ) <= 0 ) {
jQuery( '#load-more' ).fadeOut();
}
})
// .fail( function() {
.fail( function(jqXHR, textStatus, errorThrown) { // Ajax call is not successful, still remove lock in order to try again
ajaxLock = false;
console.log(XMLHttpRequest);
console.log(textStatus);
console.log(errorThrown);
console.log( 'Failed' );
});
}
}
PHP
<?php
/**
* Load next 12 products using AJAX
*/
function ajax_next_posts() {
global $product;
// Build Query
$args = array(
'post_type' => 'product',
'posts_per_page' => (int)$_POST['posts_per_page'],
'orderby' => 'title',
'order' => 'ASC',
'offset' => (int)$_POST['post_offset'],
);
if( !empty( $_POST['product_cat'] ) ) {
$args['tax_query'] = array(
'relation' => 'AND',
array (
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => $_POST['product_cat'],
'operator' => 'IN'
),
);
}
$count_results = '0';
$ajax_query = new WP_Query( $args );
// Results found
if( $ajax_query->have_posts() ){
// Start "saving" results' HTML
$results_html = '';
ob_start();
while( $ajax_query->have_posts() ) {
$ajax_query->the_post();
echo wc_get_template_part( 'content', 'product' );
}
wp_reset_postdata();
// "Save" results' HTML as variable
$results_html = ob_get_clean();
} else {
// Start "saving" results' HTML
$results_html = '';
ob_start();
echo "none found!";
// "Save" results' HTML as variable
$results_html = ob_get_clean();
}
// Build ajax response
$response = array();
// 1. value is HTML of new posts and 2. is total count of posts
array_push ( $response, $results_html );
echo json_encode( $response );
// Always use die() in the end of ajax functions
die();
}
add_action('wp_ajax_ajax_next_posts', 'ajax_next_posts');
add_action('wp_ajax_nopriv_ajax_next_posts', 'ajax_next_posts');
Use Cases
By refactoring the supplied AJAX code, it would be possible to turn this solution into an "infinite scrolling" system as opposed to a "Load More" button solution. Please feel free to reuse this code where it may see fit!

WP_Query shows wrong result for queries that user not logged in

I have some issue to load posts from widgets using ajax ,I have this code in my own widget to fetch some posts:
$query_args = array(
'post_type' => 'post',
'posts_per_page' => 15,
'post_status' => 'publish',
'cat' => $catID
);
$q = new WP_Query($query_args);
while($q->have_posts()){
$q->the_post();
the_title();
}
wp_reset_query();
And this code in mysidebar.php
<div>
<?php dynamic_sidebar('mysidebar'); ?>
</div>
In wordpress admin I drag and drop 4 widget in mysidebar with different category ID.
At last register a ajax function like blow:
add_action("wp_ajax_itr", "itr");
add_action("wp_ajax_nopriv_itr", "itr");
function itr() {
require 'path/to/mysidebar.php';
wp_die();
}
This is my jquery code to load mysidebar.php data:
$.post(ajaxurl, {
action : "itr"
}, function (data, status) {
// Success Response ...
if (status === "success") {
$("#the_id").html(data);
}
}
});
What is the problem? the problem is when user not logged in, wp_query return wrong posts! Its load some posts for all categories!
Note: There is no private or protected post

Categories