How add the Woocommerce notices(without reload) when using add to cart with ajax? - ajax

I try to make the add to cart buttons and notices on the productpages(and everywhere else) work with ajax. But the notices (e.g. You cannot add that amount to the cart - we have X in stock and you already have Y in your cart.) don't work.
How do I make it work?
This is what I have right now:
JS for AJAX Add to Cart handling
/**
* JS for AJAX Add to Cart handling
*/
function ace_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%%', 'ace_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; // 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', 'ace_product_page_ajax_add_to_cart_js' );
Add to cart handler:
/**
* Add to cart handler
*/
function ace_ajax_add_to_cart_handler() {
WC_Form_Handler::add_to_cart_action();
WC_AJAX::get_refreshed_fragments();
}
add_action( 'wc_ajax_ace_add_to_cart', 'ace_ajax_add_to_cart_handler' );
add_action( 'wc_ajax_nopriv_ace_add_to_cart', 'ace_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:
/**
* Add fragments for notices
*/
function ace_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', 'ace_ajax_add_to_cart_add_fragments' );

Try replacing in last snippet 'messages' => array_filter( ... with 'notices' => array_filter( ... and it should work.

Related

Load more posts with AJAX and also add pagination in URL

On load more button, posts load without page load using AJAX, but wanted to implement Wordpress pagination on load more along with URL changing. Suggestions are welcome.
/* Category/tag page Masonry Grid */
var $mgrid = $( '.post-grid' ).masonry();
$mgrid.masonry( {
itemSelector: '.post-outer',
} );
/* ------------------ Load More Posts Category/tag page ------------------ */
$( document ).on( 'click', '#post-button', function(e) {
e.preventDefault();
var offset = $( this ).attr( 'data-value' );
var cat = $( this ).attr( 'data-cat' ); //load more button attribute
var tag = $( this ).attr( 'data-tag' ); //load more button attribute
var page = $( this ).attr( 'data-page' ); //load more button attribute
var $content;
$.ajax( {
type: "post",
async: false,
dataType: "json",
url: localizeObj.ajaxurl, //localize script in functions.php
data: {
action: 'fetch_posts', //ajax load more function in functions.php
offset: offset,
cat: cat,
tag: tag,
page: page,
search_term: localizeObj.search_term,
current_page: localizeObj.current_page
},
beforeSend: function() {
},
success: function(response) {
/* Adding page numbers on ajax load more */
var pathname = window.location.pathname;
if ( response.success == 'yes' ) {
$content = $(response.posts);
$( '.post-masonry-grid' ).append( $content ).masonry( 'appended', $content );
page = parseInt(page) + 1;
offset = parseInt(offset) + 6;
$('.post-grid-outer').each( function() {
$('.post-grid-outer').addClass(offset);
});
$( '#post-grid-button' ).attr( 'data-value', offset );
$( '#post-grid-button' ).attr( 'data-page', page );
var page_num = '';
if(page <= 2) {
var page_num = 'page/'+ page;
} else {
var page_num = page;
}
window.history.pushState("URL", "Title", page_num); // Add page numbers to URL
} else {
$( '#post-button' ).hide();
}
},
complete : function() {
}
} );
} );

A simple Ajax call in wordpress doesn't give the expecetd output

Here is my javascript file:-
jQuery(document).ready( function($) {
$('#test_button').click(function(e){
alert("test");
$.ajax({
url : my_ajax_object.ajaxurl ,
type : 'post',
dataType : 'json',
data : {
action : 'do_ga'
},
complete: function(res, status) {
if( status == 'success' ) {
console.log("success "+res);
} else {
console.log("fail "+res);
}
}
});
});
});
here is my php code in functions.php:-
function do_ga() {
die("test" );
}
add_action( 'wp_ajax_do_ga', 'do_ga' );
add_action( 'wp_ajax_nopriv_do_ga', 'do_ga' );
//this is the script en queuing
function my_enqueue() {
wp_enqueue_script( 'ga-loadmore', get_template_directory_uri() . '/pl-custom/front-end-assets/js/ga-loadmore.js', array('jquery') );
wp_localize_script( 'ga-loadmore', 'my_ajax_object',
array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
}
add_action( 'wp_enqueue_scripts', 'my_enqueue' );
So,upon the click of the button with id "#test_button" , instead of outputting success [object][object] , it outputs fail [object][object]. What needs to be done here. Precisely , i want "success test". please add the json_encode and decode wherever required in the solution.Thanks
I've separated the PHP code in another file and included it in functions.php and also separated the enqueuing, and changed the syntax of the request a little. I hereby attach my code and it works:
function do_ga() {//server code
$x="test";
wp_die( $x);
exit;
}
add_action( 'wp_ajax_do_ga', 'do_ga' );
add_action( 'wp_ajax_nopriv_do_ga', 'do_ga' );
client side(already enqueued):-
jQuery(document).ready( function($) {
$('#test_button').click(function(e){
url = window.location.origin + '/wp-admin/admin-ajax.php?action=do_ga';
alert("test");
$.ajax({
async: true,
type: 'POST',
url: url,
data: {
'my_number':1 //you need not pass data
},
complete: function(res, status) {
if( status == 'success' ) {
alert("success "+ res.responseText);
} else {
alert("unable to process request");
}
}
})
});
});

Istotope ajax content load

I'm stuck implementing load next set of posts in WordPress with isotope masonry layout.
It's just not triggered for appended elements and I can't figure out why.
If someone could point me in right direction I would appreciate.
jQuery AJAX function
function load_content( args ) {
$container = $('#container-async');
$status = $('.status');
$.ajax({
url: ajax_url,
data: {
action: 'do_load_posts',
nonce: nonce,
args: args
},
type: 'post',
dataType: 'json',
success: function( data, textStatus, XMLHttpRequest ) {
$items = data.posts;
if ( args.action === 'filter') {
/**
* Replace items
*/
$container.imagesLoaded( function() {
$container.isotope({
itemSelector: '.grid-item',
percentPosition: true,
masonry: {
columnWidth: '.grid-sizer'
}
});
$container.html( $items ).isotope( 'appended', $items, function() {
console.log('inserted');
});
});
}
else {
/**
* Append items
*/
$container.imagesLoaded( function() {
$container.isotope({
itemSelector: '.grid-item',
percentPosition: true,
masonry: {
columnWidth: '.grid-sizer'
}
});
$container.append( $items ).isotope( 'appended', $items, function() {
console.log('appended');
});
});
}
},
error: function( MLHttpRequest, textStatus, errorThrown ) {
$status.toggleClass('active');
}
});
}
WordPress AJAX:
function ajax_do_load_posts() {
// Verify nonce
if( !isset( $_POST['nonce'] ) || !wp_verify_nonce( $_POST['nonce'], 'nonce' ) )
die('Permission denied');
$response = [
'status' => 500,
'posts' => 0,
];
$filter = $_POST['args'];
$type = get_post_type_object( $filter['type'] );
$args = [
'post_type' => sanitize_text_field($filter['type']),
'paged' => intval($filter['page']),
'posts_per_page' => $filter['qty'],
];
$qry = new WP_Query($args);
if ($qry->have_posts()) :
ob_start();
while($qry->have_posts()) : $qry->the_post(); ?>
<div class="grid-item col-xs-12 col-sm-6 col-md-4 col-lg-3">
<?php get_template_part('templates/loop', 'card' ); ?>
</div>
<?php endwhile;
$response = [
'status' => 200,
'posts' => ob_get_clean(),
];
endif;
wp_reset_query();
wp_reset_postdata();
die(json_encode($response));
}
add_action('wp_ajax_do_load_posts', 'ajax_do_load_posts');
add_action('wp_ajax_nopriv_do_load_posts', 'ajax_do_load_posts');
Items are inserted or appended into container but masonry is triggered only on items that are already there on page load.
I have googled around and tried various solutions but none of them work, neither with isotope or masonry jquery plugin.
I was able to fix my issue, and kind of looks like the problem is because I was using jQuery default append/insert methods.
I have switched to isotope methods and now things look fine.
So basically instead of
$container.html( $items ).isotope( 'appended', $items, function() {
console.log('inserted');
});
I am now using:
$grid.isotope('insert', jQuery($items));
It looks logical actually that isotope cannot know items are appended if I don't use isotopes append/insert method. And notice that I also wrapped $items inside jQuery.
Anyhow my working JS for same PHP function is:
function load_content( args ) {
$container = $('#container-async');
$status = $('.status');
$.ajax({
url: ajax_url,
data: {
action: 'do_load_posts',
nonce: nonce,
args: args
},
type: 'post',
dataType: 'json',
success: function( data, textStatus, XMLHttpRequest ) {
$items = data.posts;
var $grid = $('.masonry').imagesLoaded( function() {
$grid.isotope({
itemSelector: '.grid-item',
percentPosition: true,
masonry: {
columnWidth: '.grid-sizer'
}
});
if ( args.action === 'filter') {
$grid.isotope('remove', $('.grid-item'));
}
$grid.isotope('insert', jQuery($items));
});
$grid.on( 'layoutComplete', function( event, laidOutItems ) {
$container.removeClass(data.action);
});
},
error: function( MLHttpRequest, textStatus, errorThrown ) {
$status.toggleClass('active');
}
});
}

WP_Query with ajax handler returns the same posts

I have a problem that is getting me bald atm. I have a ajax call that handles a loop that handles some querys and returns posts for me.
So far so good, but the first time the user sees the page we should load 10 posts, and then we want to click a button to request 5 more.
So far so good.
But when we request the 5 more posts we get the 5 first posts again.
My batchloop
<?php
// Our include
define('WP_USE_THEMES', false);
require_once('../../../wp-load.php');
// Our variables
$posts = (isset($_GET['numPosts'])) ? $_GET['numPosts'] : 0;
$page = (isset($_GET['pageNumber'])) ? $_GET['pageNumber'] : 0;
$category = (isset($_GET['category_name'])) ? $_GET['category_name'] : 0;
var_dump($posts);
$args = array(
'posts_per_page' => $posts,
'category_name' => $category,
'post_status' => 'publish',
'orderby' => 'date',
'order' => 'DESC',
'paged' => $page
);
query_posts($args);
// $query = new WP_query($args);
// our loop
if (have_posts()) {
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1; query_posts($args);
while (have_posts()){
the_post();
get_template_part( 'thumbs', get_post_format() );
}
}
// unset($page, $posts, $category);
// wp_reset_postdata();
wp_reset_query();
?>
Does anybody sees what im doing wrong?
EDIT:
batch handler
function _batchhandler() {
var getamount = localStorage.getItem('amount');
console.log('amount of posts to retrive ' + JSON.parse(getamount));
// Ajax call
$.ajax({
type: 'GET',
data: {
posts: getamount,
page: page,
category: 'work'
},
dataType: 'html',
url: 'http://dev.xxx.se/wp-content/themes/xxx/batch.php',
beforeSend: function() {
_setHeader;
if( page != 1 ) {
console.log('Loading');
// Show the preloader
$('body').prepend('<div class="preloader"><span class="rotate"></span></div>');
}
// If we reach the end we hide the show more button
if( page >= total ) {
$('.load').hide();
}
},
success: function(data) {
console.log(page);
var scroll = ($('.thumb').height() * posts);
// If thumbs exist append them
if( data.length ) {
// Append the data
$('#batch').append(data);
// Remove the crappy width and height attrs from the image * Generated by WP *
$('img').removeAttr('height').removeAttr('width');
// Animate each new object in a nice way
(function _showitem() {
$('#batch .thumb:hidden:first').addClass('show', 80, _showitem);
// On the last request do load any more
loading = false;
})();
// Remove the preloader
$('.preloader').fadeOut(200, function() {
$('.preloader').remove();
});
}
// return false;
},
complete: function() {
// Delete storage
localStorage.clear();
// Update the scroller to match the updated content length
if (scroller)
setTimeout("scroller.refresh()", 300);
// Initalize the load more button
_clickhandler();
},
error: function() {
console.log('No page found');
}
});
}
and my load more button function
$('.load').on('click', function(event) {
event.preventDefault();
// Delete storage
localStorage.clear();
if(!loading) {
loading = true;
// Increase our pagenumber per click
page++;
count++;
// Remove preloader
$('.preloader').remove();
setTimeout(function() {
$('#batch').css({
'-webkit-transform' : 'translateY(-' + ($('#batch li').outerHeight() * count) + 'px)'
});
}, 30);
// Clear storage and set a new
localStorage.setItem('amount', JSON.stringify(amount.medium));
var getamount = localStorage.getItem('amount');
// Send the request to the handler
_batchhandler(page);
}
});
Everything seems fine, the first 10 (1-10) posts loads as the should, but the first time "load more" is clicked we get the next 5 results but the results are posts that loaded the first time (5-10). If we click the "load more" again, we get the correct result
I don't think you have defined a start value for page, set it to 1 at the start of your script so when it increments on click it goes to page 2. Otherwise it'll just get the first page.

Cakephp 2.1 and Jquery UI autocomplete

Mission:
Implement autocomplete of departments(saved in departments table) in employee form field called department.
A user enters a few spellings of department name
That brings up list of the names matching departments
The user select one and that's it.
Platforms
CakePhp 2.1
Jquery UI Autocomplete(part of Jquery UI library version 1.8.18)
Database Model
Emplyee (id, first_name,last_name,department_id)
department(id,name)
so in my add.ctp file ajax call is something like
$( "#auto_complete" ).autocomplete({
source: function( request, response ) {
$.ajax({
url: "/employees/showDepartment",
dataType: "json",
data: {
featureClass: "P",
style: "full",
maxRows: 12,
name_startsWith: request.term
},
success: function( data ) {
alert("success--");
response( $.map( data, function( item ) {
//alert(item);
return {
label: item.name,
value: item.id
}
}));
}
});
},
minLength: 2,
select: function( event, ui ) {
log( ui.item ?
"Selected: " + ui.item.label :
"Nothing selected, input was " + this.value);
},
open: function() {
$( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" );
},
close: function() {
$( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" );
}
});
i have a action in my EmployeeController called show_depatment()
public function getAddress() {
$this->autoRender = false;// I do not want to make view against this action.
$this->log($this->params->query['name_startsWith'] , 'debug');
$str = $this->params->query['name_startsWith'];
$this->log($str, 'debug');
$this->layout = 'ajax';
$departments = $this->Employee->Department->find('all', array( 'recursive' => -1,
'conditions'=>array('Department.name LIKE'=>$str.'%'),
'fields'=>array('name', 'id')));
//$this->set('departments',$departments);
$this->log($departments, 'debug');
echo json_encode($departments);
}
I dont want show_department action to have any view so i have made $this->autoRender = false;
but it is not working as expected.
when i debug the response using firebug in response and HTLM section it shows
[{"Department":{"name":"Accounting","id":"4"}}] // when i type "acc" in input field
Question
How to make it to display in form field.
echo json_encode($departments); is it right method of sending response in json format?
when i alert in sucess part of ajax call (alert(item);) it gives error as "undefined"
i'm friend of fat Model and skinny Controller so my Controller action looks like this
public function getAddress()
{
if($this->RequestHandler->isAjax()) {
Configure::write('debug', 0);
$this->layout = 'ajax';
$this->autoRender = false;
echo json_encode($this->Employee->Department->getAddress($this->params['url']['term']));
exit;
}
}
and my Department model method:
public function getAddress($str)
{
$rs = array();
$search = $this->find('all', array(
'recursive' => -1,
'conditions'=>array('Department.name LIKE'=>$str.'%'),
'fields'=>array('name', 'id')
));
if (!empty($search))
{
//the jquery ui autocomplete requires object with label/value so we need to traverse the query results and create required array
foreach ($search as $key => $val)
{
$rs[] = array('label' => $val['Department']['name'],
'value' => $val['Department']['id']);
}
}
return $rs;
}
and finaly my view entry is like this:
$( "#auto_complete" ).autocomplete({
minLength: 2,
source: function( request, response ) {
var term = request.term;
if ( term in cache ) {
response( cache[ term ] );
return;
}
lastXhr = $.getJSON( "/employees/showDepartment", request, function( data, status, xhr ) {
cache[ term ] = data;
if ( xhr === lastXhr ) {
response( data );
}
});
}
});
hope this helps.

Resources