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!
Related
I am trying to get AJAX to work for the Add to Cart button on the WooCommerce product pages of my site. I am using the below code snippet to get AJAX functionality and it all works as it should, except for the last portion of the code.
I don't see any success/notice/error messages when the Add to Cart button is clicked. The item(s) get added to the cart, but there's no visual notice (apart from the loading animation on the button) to let the user know that the item has been added successfully.
If I remove the last section of the code, below, "Add fragments for notices", I see the notifications when the item is added, but only AFTER I reload the page.
I am trying to make it so that when the Add to Cart button is hit, the item gets added to the cart and the success message is shown, or an error message accordingly. What am I doing wrong?
/**
* JS for AJAX Add to Cart handling
*/
function product_page_ajax_add_to_cart_js() {
?><script type="text/javascript" charset="UTF-8">
jQuery(function($) {
$('form.cart').on('submit', function(e) {
e.preventDefault();
var form = $(this);
form.block({ message: null, overlayCSS: { background: '#fff', opacity: 0.6 } });
var formData = new FormData(form.context);
formData.append('add-to-cart', form.find('[name=add-to-cart]').val() );
// Ajax action.
$.ajax({
url: wc_add_to_cart_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'add_to_cart' ),
data: formData,
type: 'POST',
processData: false,
contentType: false,
complete: function( response ) {
response = response.responseJSON;
if ( ! response ) {
return;
}
if ( response.error && response.product_url ) {
window.location = response.product_url;
return;
}
// Redirect to cart option
if ( wc_add_to_cart_params.cart_redirect_after_add === 'yes' ) {
window.location = wc_add_to_cart_params.cart_url;
return;
}
var $thisbutton = form.find('.single_add_to_cart_button'); //
// var $thisbutton = null; // uncomment this if you don't want the 'View cart' button
// Trigger event so themes can refresh other areas.
$( document.body ).trigger( 'added_to_cart', [ response.fragments, response.cart_hash, $thisbutton ] );
// Remove existing notices
$( '.woocommerce-error, .woocommerce-message, .woocommerce-info' ).remove();
// Add new notices
form.closest('.product').before(response.fragments.notices_html)
form.unblock();
}
});
});
});
</script><?php
}
add_action( 'wp_footer', 'product_page_ajax_add_to_cart_js' );
/**
* Add to cart handler.
*/
function ajax_add_to_cart_handler() {
WC_Form_Handler::add_to_cart_action();
WC_AJAX::get_refreshed_fragments();
}
add_action( 'wc_ajax_add_to_cart', 'ajax_add_to_cart_handler' );
add_action( 'wc_ajax_nopriv_add_to_cart', 'ajax_add_to_cart_handler' );
// Remove WC Core add to cart handler to prevent double-add
remove_action( 'wp_loaded', array( 'WC_Form_Handler', 'add_to_cart_action' ), 20 );
/**
* Add fragments for notices.
*/
function ajax_add_to_cart_add_fragments( $fragments ) {
$all_notices = WC()->session->get( 'wc_notices', array() );
$notice_types = apply_filters( 'woocommerce_notice_types', array( 'error', 'success', 'notice' ) );
ob_start();
foreach ( $notice_types as $notice_type ) {
if ( wc_notice_count( $notice_type ) > 0 ) {
wc_get_template( "notices/{$notice_type}.php", array(
'messages' => array_filter( $all_notices[ $notice_type ] ),
) );
}
}
$fragments['notices_html'] = ob_get_clean();
wc_clear_notices();
return $fragments;
}
add_filter( 'woocommerce_add_to_cart_fragments', 'ajax_add_to_cart_add_fragments' );
Replace the below code.
/**
* Add fragments for notices.
*/
function ajax_add_to_cart_add_fragments( $fragments ) {
$all_notices = WC()->session->get( 'wc_notices', array() );
$notice_types = apply_filters( 'woocommerce_notice_types', array( 'error', 'success', 'notice' ) );
ob_start();
foreach ( $notice_types as $notice_type ) {
if ( wc_notice_count( $notice_type ) > 0 ) {
wc_get_template( "notices/{$notice_type}.php", array(
'notices' => array_filter( $all_notices[ $notice_type ] ),
) );
}
}
$fragments['notices_html'] = ob_get_clean();
// wc_clear_notices();
return $fragments;
}
add_filter( 'woocommerce_add_to_cart_fragments', 'ajax_add_to_cart_add_fragments' );
I am trying to create a live search using ajax and jquery on my custom WordPress theme. If i use .click() function it is showing desired output but when using .keyup or on('input',function(){}) it display nothing.
Jquery code
var searchRequest = null;
var minlength = 3;
$(".search-submit").on('input',function(e){
e.preventDefault();
var st=$(".search-field").val();
if (st.length >= minlength )
{
if (searchRequest != null)
searchRequest.abort();
searchRequest=$.ajax({
type:"POST",
url: "./wp-admin/admin-ajax.php",
data: {
action:'wpa56343_search',
search_string:st
},
success:function(data){
$('.srch-result').append(data);
}
});
}
});
PHP code of function.php
add_action('wp_ajax_nopriv_wpa56343_search', 'wpa56343_search');
add_action('wp_ajax_wpa56343_search', 'wpa56343_search');
function wpa56343_search()
{
global $wp_query;
$search = $_POST['search_string'];
$args = array(
's' => $search,
'posts_per_page' => 5
);
$query = new WP_Query( $args );
if ( $query->have_posts() ) :
while ( $query->have_posts() ) :
$query->the_post();
get_template_part( 'template-parts/ajax-search-format', get_post_format() );
endwhile;
endif;
wp_reset_postdata();
}
Please show your html structure too.
I think you are trying to trigger with the wrong element.
Maybe $(".search-submit") is not a input field.
Try:
$(".search-field").on('input',function(e){
//** YOUR CODE **/
});
So I'm working on a WordPress website. I'm having a bit of a difficult time getting the user input to update the database.
JS:
var ID = $(this).attr('id');
var name = $("#name_input_"+ID).val();
var createDate = $("#created_input_"+ID).val();
var stats = $("#status_input_"+ID).val();
var dateExpire = $("#disbanded_input_"+ID).val();
var dataString = 'id=' + ID + '&name=' + name +
'&createDate=' + createDate + '&stats=' + stats + '&dateExpire=' + dateExpire;
// can place loading image here
if (name.length > 0 || createDate.length > 0 ||
stats.length > 0 || dateExpire.length > 0) {
$.ajax({
type: "POST",
url: "../edit-items.php",
data: dataString,
cache: false,
error: function(xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
alert(err.Message);
},
success: function (html) {
$("#name_"+ID).html(name);
$("#createDate_"+ID).html(createDate);
$("#stats_"+ID).html(stats);
$("#dateExpire_"+ID).html(dateExpire);
}
});
} else {
alert("Enter text to make an edit.");
}
});
PHP (edit-items.php)
global $wpdb;
if($_POST['id']) {
$id = esc_sql($_POST['id']);
$name = esc_sql($_POST['name']);
$created = esc_sql($_POST['createDate']);
$stats = esc_sql($_POST['stats']);
$dateExpire = esc_sql($_POST['dateExpire']);
$query = "UPDATE items SET itemName='$name', createDate='$created', itemStats='$stats', dateExpire='$dateExpire' WHERE committee_id='$id';"
$wpdb->query($wpdb->prepare($query));
}
Whenever I try to update the table, I am able to do it successfully on the front end, but on refresh, the data change does not stick. Checking the database further verifies that the data has not been changed... It seems like the "success" is passing in the AJAX, but for some reason, it's not updating the database.
Any insight on this would be helpful!
Edit
Decided to start using the admin-ajax.php method. Everything is the same except I changed the url in the JS to url: "/wp-admin/admin-ajax.php", and the code from edit-items.php is now in functions.php like so:
function editCommittee() {
global $wpdb;
if($_POST['id']) {
$id = esc_sql($_POST['id']);
$name = esc_sql($_POST['name']);
$created = esc_sql($_POST['createDate']);
$stats = esc_sql($_POST['stats']);
$dateExpire = esc_sql($_POST['dateExpire']);
$wpdb->update('itemsTable',
array(
'name' => $name
),
array(
'committee_id' => $id
),
array(
'%s'
)
);
echo $id;
exit();
}
}
add_action('wp_ajax_editItems', 'editItems');
Here is the issue, for ajax requests we use http://example.com/wp-admin/admin-ajax.php.
Also your data string should cantain &action=editItems ( same as you use in wp_ajax_editItems )
You ajax request code should look like...
$.ajax({
type: "POST",
url: "/wp-admin/admin-ajax.php",
data: dataString + '&action=editItems',
cache: false,
error: function(xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
alert(err.Message);
},
success: function (html) {
$("#name_"+ID).html(name);
$("#createDate_"+ID).html(createDate);
$("#stats_"+ID).html(stats);
$("#dateExpire_"+ID).html(dateExpire);
}
});
For more details check out https://codex.wordpress.org/AJAX_in_Plugins
Hope that helps :)
Ok, so first localize your ajaxurl object
add_action( 'wp_enqueue_scripts', 'frontend_enqueued_scripts' );
/**
* Localization object
*
* #since 1.0.0
*/
function frontend_enqueued_scripts() {
wp_enqueue_script( 'script', get_template_directory_uri() . '/js/custom.js', array( 'jquery' ), '', true );
wp_localize_script( 'script', 'ajax_object', array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
));
}
If you have, in your functions.php a place where you are enqueuing front end scripts place the wp_enqueue_script and wp_localize_script part in there. Also if you are placing your ajax calling javascript inside a file that is not called custom.js change the name to point to it. I always use custom.js as a file where I store all my theme related javascript.
The above code will create an ajax_object object on your front end that will be available to the code inside the custom.js, since you've attached it to that script. The handles in the enqueued file and localized script (in our case script) must be the same for this to work.
Then you can create, in functions.php file, or in any included file where you put your ajax functions, a callback function
/**
* Front and back end ajax hooks.
*/
add_action( 'wp_ajax_edit_committee', 'edit_committee' );
add_action( 'wp_ajax_nopriv_edit_committee', 'edit_committee' );
/**
* Ajax callback function
*
* #since 1.0.0
*/
function edit_committee() {
global $wpdb;
if ( isset( $_POST['id'], $_POST['committee_nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['committee_nonce'] ), 'committee_nonce_action' ) && '' !== $_POST['id'] ) { // Input var okay.
$id = ( isset( $_POST['id'] ) && '' !== $_POST['id'] ) ? sanitize_text_field( wp_unslash( $_POST['id'] ) ); : ''; // Input var okay.
$name = ( isset( $_POST['name'] ) && '' !== $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ); : ''; // Input var okay.
$created = ( isset( $_POST['create_date'] ) && '' !== $_POST['create_date'] ) ? sanitize_text_field( wp_unslash( $_POST['create_date'] ) ); : ''; // Input var okay.
$stats = ( isset( $_POST['stats'] ) && '' !== $_POST['stats'] ) ? sanitize_text_field( wp_unslash( $_POST['stats'] ) ); : ''; // Input var okay.
$date_expire = ( isset( $_POST['date_expire'] ) && '' !== $_POST['date_expire'] ) ? sanitize_text_field( wp_unslash( $_POST['date_expire'] ) ); : ''; // Input var okay.
$updated = $wpdb->update( 'itemsTable', array( 'name' => $name ), array( 'committee_id' => $id ), array( '%s' ) );
if( false !== $updated ) {
wp_die( 'success' );
} else {
wp_die( 'fail' );
}
}
}
I added the sanitization checks. It's crucial that you include a nonce in your form that you'll use to submit the data.
You can add it by placing
wp_nonce_field( 'committee_nonce_action', 'committee_nonce' );
inside the <form> element on your front end. This will generate a nonce, which is a good security measure, especially when you're writing to the database.
The callback function will check if the nonce is set, if the $_POST['id'] variable is set and not empty, and will first verify the nonce.
Then you can carry on with the execution of the function.
I left all the $POST variables there even though you're not using them, but maybe you'll want to use them later on. I also sanitized them and unslashed them.
The // Input var okay. comment is for phpcs purposes, you can ignore that.
Then you preform the update. If you have the itemsTable in the database it should update it with the data you provided.
The last but not the least is the javascript code. I assumed that you are preforming the ajax call on some kind of button click. This needs to be changed for it to work (I used #update_button, you'll place the correct id or class of your button)
jQuery(document).ready(function($) {
'use strict';
$('#update_button').on('click', function(e){
e.preventDefault();
var ID = $(this).attr('id'); // Button that is clicked is in $(this) object
var name = $('#name_input_'+ID).val();
var create_date = $('#created_input_'+ID).val();
var stats = $('#status_input_'+ID).val();
var date_expire = $('#disbanded_input_'+ID).val();
// Can place loading image here
if ( name.length > 0 || create_date.length > 0 || stats.length > 0 || date_expire.length > 0 ) {
$.ajax({
type: 'POST',
url: ajax_object.ajaxurl,
data: {
'action' : 'edit_committee',
'id' : ID,
'name' : name,
'create_date' : create_date,
'stats' : stats,
'date_expire' : date_expire,
'committee_nonce' : $( '#committee_nonce' ).val()
},
cache: false,
error: function( jqXHR, textStatus, errorThrown ) {
console.log( jqXHR + ' :: ' + textStatus + ' :: ' + errorThrown );
},
success: function (html) {
if ( html == 'success' ) {
$('#name_'+ID).html(name);
$('#createDate_'+ID).html(create_date);
$('#stats_'+ID).html(stats);
$('#dateExpire_'+ID).html(date_expire);
}
}
});
} else {
alert('Enter text to make an edit.');
}
});
});
I've also changed variable names to short_name format, instead of shortName. I find that neater.
Notice that for the url, we used ajax_object.ajaxurl - this is the localized ajax_object from the beginning, referencing to the correct path of the admin-ajax.php file. The data is just your string, but written as an object.
So when you click the button, your ajax call will put all your data in a global $_POST variable.
You can check it by having inspector running and clicking Network > XHR tab
Also if you're not sure what your $_POST variable holds, put
error_log(print_r($_POST, true));
in your edit_committee() function, right before the validation check (the if condition). If you have debugging enabled in your wp-config.php
define('WP_DEBUG', true);
ini_set('log_errors',TRUE);
ini_set('error_reporting', E_ALL);
ini_set('error_log', dirname(__FILE__) . '/error_log.txt');
You'll have error_log.txt in the root of your WordPress installation, and you can check what the contents of the $_POST variable is.
Hope this helps ;)
I'm quite sure that you didn't send POST data to PHP file - check it. Type var_dump($_POST) in php, and add console.log(html) in success part of ajax.
Try also change your dataString variable in JS to this:
var dataString = {
id:ID,
name:name,
createDate:createDate,
stats:stats,
dateExpire:dateExpire
};
$wpdb->update( 'table',
array( 'column' => $name),
array( 'ID' => 1 ),
array( '%s'),
array( '%d' )
);
Here is some working code for a promo modal but is this a safe and appropriate way to use the wordpress nonce in an ajax request?
Create the nonce in the tmp: $ajax_nonce = wp_create_nonce( "mynonce" );
Example URL: www.mysite.com/#345345
var asdf = location.hash.match(/^#?(.*)$/)[1];
if (asdf) {
$productID = asdf;
if ($.cookie("modalshow") === undefined) {
var expiryDate = new Date();
var minutes = 0.20; //12 seconds
expiryDate.setTime(expiryDate.getTime() + (minutes * 60 * 1000));
$.cookie("modalshow", "exists", { path: '/', expires: expiryDate });
var data = {
action: 'my_action',
product_id: $productID,
security: '<?php echo $ajax_nonce; ?>'
};
var ajaxurl = '/wp-admin/admin-ajax.php';
$.post(ajaxurl, data, function(response) {
$(".modal-content").append(response);
$('#Modal').modal({ show:true });
});
} //no cookie
};//if match
Plugin:
add_action( 'wp_ajax_my_action', 'my_action_function' );
function my_action_function() {
check_ajax_referer( 'mynonce', 'security' );
if( isset($_POST['product_id']) ) {
$my_report_num = $_POST['product_id']; // splash 443
$myposttype = get_post_type( $my_product_num );
if ( get_post_status( $my_product_num ) == 'publish' && $myposttype == "df_product" ) {
//we're good
$theid = $my_product_num;
} else {
$theid = "876";
}
//fedtch content using $theid
die();
} // end if
die;
}
In the above php, get_post_type() uses get_post() which uses sanitize_post() - so there is some validation being done, and currently my plan is that if anything malicious is appended to the URL or sent by some other means in the client, that $theid will be set to my white listed number "876" - so do I need to do additional validation either in the client or in php?
Any assistance is appreciated, thanks!
I'm trying to AJAX loading posts in my blog, I've successfully get it to work this way:
the page displays 3 posts on page load, then the visitor can get 3 more posts each time he clicks the button "LOAD MORE".
Now I want to load 9 posts on page load but keep 3 posts with each click on "LOAD MORE" button.
A problem occurs with the page number value in the WPQuery, it's getting the same 3 posts which were already displayed.
how can I prevent posts duplication?
Please check it here at my temp website
[note that I have less than 9 posts at the category page, it should load all of them]
(function($) {
$(document).ready(function(){
var $content = $('#list-content');
var $btnLoad = $('#btnLoad');
var loading = true;
var page = 1;
var load_posts = function($count){
var post_id = $(this).attr( 'id' );
/** Ajax Call */
$.ajax({
cache : false,
timeout : 8000,
url : php_array.admin_ajax,
type : "POST",
data : {action:'main_query', numPosts : $count, pageNumber: page, condition: php_array.condition, val: php_array.val},
beforeSend : function() {
$('#loadimg').slideToggle("fast");
$btnLoad.prop("disabled",true);
},
success : function(data, textStatus, jqXHR ){
var $data = $( data );
if($data.length){
$content.append( $data );
$btnLoad.prop("disabled",false);
}
else{
$btnLoad.html("That's it");
$btnLoad.prop("disabled",true);
}
},
error : function( jqXHR, textStatus, errorThrown ){
if(t==="timeout") {
alert("Server is too slow, try again later");
} else {
alert(t);
}
console.log( 'ajaxLoop.js: The following error occured: ' + textStatus, errorThrown );
},
complete : function( jqXHR, textStatus ){
$('#loadimg').slideToggle("fast");
loading = false;
page++;
}
});
}
$btnLoad.on("click", function(e) {
e.preventDefault();
loading = true;
load_posts(3);
});
load_posts(9); //load the first elements
});
})(jQuery);
PHP code:
function main_query_init() {
/** Made Query */
$numPosts = (isset($_POST['numPosts'])) ? $_POST['numPosts'] : 0;
$page = (isset($_POST['pageNumber'])) ? $_POST['pageNumber'] : 0;
$condition = (isset($_POST['condition'])) ? $_POST['condition'] : '';
$val = (isset($_POST['val'])) ? $_POST['val'] : '';
$args = array(
'posts_per_page'=> $numPosts,
'paged' => $page,
);
if($condition != ''){
$args[$condition] = $val;
}
$post_query = new WP_Query( $args );
if ($post_query->have_posts()) : while ($post_query->have_posts()) : $post_query->the_post();
You are probably looking for the offset parameter for WP_Query. Setting it to 3 will cause it to skip the first 3 results when using posts_per_page and paged.
The other option is to specify the post_ids that you don't want explicitly using the post__not_in parameter, but this will require passing the array of values to exclude with each request - you might be able to get away with just passing in the first 3 IDs, but I would go with offset.
The key is var currCount = $data.filter('article').length;
where I store the current count of posts from ajax response.
Since I ask for extra 3 posts every load button click, then if((currCount % 3) == 0) will tell me if it got 3 posts otherwise there are no more posts and there is no need to increment page counter.
success : function(data, textStatus, jqXHR ){
var $data = $( data );
var currCount = $data.filter('article').length;
totalCount += currCount;
if(currCount > 0){
$content.append( $data );
$btnLoad.prop("disabled",false);
if((currCount % 3) == 0)
page += currCount / 3;
else
page += (parseInt(totalCount/3) + 1);
return;
}
$btnLoad.html("That's it");
$btnLoad.prop("disabled",true);
},