I'm looking for a way to update order review (shipping price) when client change country on checkout page.
I want to use jQuery. but wc_checkout_params wc_checkout_params is deprecated.
function custom_checkbox_checker() {
if (is_checkout()) {
wp_enqueue_script('jquery');
?>
<script type="text/javascript">
jQuery(document).ready(function (e) {
var $ = jQuery;
// wc_checkout_params is required to continue, ensure the object exists
if (typeof wc_checkout_params === 'undefined')
return false;
var updateTimer,
dirtyInput = false,
xhr;
function update_shipping(billingstate, billingcountry) {
if (xhr)
xhr.abort();
$('#order_methods, #order_review').block({message: null, overlayCSS: {background: '#fff url(' + wc_checkout_params.ajax_loader_url + ') no-repeat center', backgroundSize: '16px 16px', opacity: 0.6}});
var data = {
action: 'woocommerce_update_order_review',
security: wc_checkout_params.update_order_review_nonce,
billing_state: billingstate,
billing_country: billingcountry,
post_data: $('form.checkout').serialize()
};
xhr = $.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: data,
success: function (response) {
var order_output = $(response);
$('#order_review').html(response['fragments']['.woocommerce-checkout-review-order-table'] + response['fragments']['.woocommerce-checkout-payment']);
$('body').trigger('updated_checkout');
},
error: function (code) {
console.log('ERROR');
}
});
}
jQuery('.state_select').change(function (e, params) {
update_shipping(jQuery(this).val(), jQuery('#billing_country').val());
});
});
</script>
<?php
}
}
add_action('wp_footer', 'custom_checkbox_checker', 50);
any clue?
All solutions related to AJAX for WC like this are useless since wc_checkout_params removed on 3.x version.
Nothing useful found in woocommerce documentations.
nothing in stack overflow!
wondering why no one answered questions like this for 2 years+
Normally woocommerce do it itself, and nothing is needed…
But you can try the following instead, that should work in Woocommerce 3+ versions:
add_action('wp_footer', 'billing_country_update_checkout', 50);
function billing_country_update_checkout() {
if ( ! is_checkout() ) return;
?>
<script type="text/javascript">
jQuery(function($){
$('select#billing_country, select#shipping_country').on( 'change', function (){
var t = { updateTimer: !1, dirtyInput: !1,
reset_update_checkout_timer: function() {
clearTimeout(t.updateTimer)
},
trigger_update_checkout: function() {
t.reset_update_checkout_timer(), t.dirtyInput = !1,
$(document.body).trigger("update_checkout")
}
};
$(document.body).trigger('update_checkout');
console.log('Event: update_checkout');
});
});
</script>
<?php
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Related
I have this script:
<script>
(function($){
load_data();
function load_data(query)
{
jQuery.ajax({
url:"fetch.php",
method:"post",
data:{query:query},
success:function(data)
{
$('#result').html(data);
}
});
}
$('#search_text').keyup(function(){
var search = $(this).val();
if(search != '')
{
load_data(search);
}
else
{
load_data();
}
});
})(jQuery);
</script>
on a php file, but I get constantly an error cause Wordpress doesn't recognize the ajax url (fetch.php) and it tries to generate a new URL in my domain.
How can I do it properly?
You need use wp_ajax or wp_ajax_nopriv action hooks to use WordPress ajax. check the below code.
For call the wp_ajax or wp_ajax_nopriv action hooks you need use
WP admin_url('admin-ajax.php') this will return wordperss ajax url.
And, also pass action in jQuery.ajax data params.
Check the below code. code goes in your active theme functions.php file.
function call_ajax(){ ?>
<script>
(function($){
load_data();
$('#search_text').keyup(function(){
var search = $(this).val();
if(search != ''){
load_data(search);
}else{
load_data();
}
});
function load_data( query ){
jQuery.ajax({
url:"<?php echo admin_url('admin-ajax.php'); ?>",
method:"post",
data:{acion:'your_action_name',query:query},
success:function( data ) {
$('#result').html( data );
}
});
}
})(jQuery);
</script>
<?php }
add_action( 'wp_footer', 'call_ajax', 10, 1 );
add_action( 'wp_ajax_your_action_name', 'your_action_name' );
add_action( 'wp_ajax_nopriv_your_action_name', 'your_action_name' );
function your_action_name(){
echo "ajax call";
echo $_POST['query'];
die;
}
I am trying to use update_meta_data via AJAX on the WooCommerce thank you page but I am stuck.
Here is what I have so far:
//Following function gets called from the page already
function renderForm() {
echo "<script>
jQuery(document).ready(function() {
$('body').on('click', '#button', function(){
$.ajax({
type: 'POST',
url: 'https://thepropdrop.com/wp-admin/admin-ajax.php',
data: {
action: 'create_user_meta'
},
success: function(textStatus){
console.log('Success');
},
error: function(MLHttpRequest, textStatus, errorThrown){
alert('errorThrown');
}
});
});
});
</script>";
}
add_action("wp_ajax_create_user_meta", "create_user_meta");
add_action("wp_ajax_nopriv_create_user_meta", "create_user_meta");
function create_user_meta() {
$order = wc_get_order($order_id);
$order->update_meta_data('hasAnswered', 'Yes');
$order->save();
die();
}
Any help you could provide would be greatly appreciated.
EDIT - My related code, that will provide some context:
Here is the button on the thankyou.php:
<span class="button gameStart">
Let's do this
</span>
<script>
jQuery(document).ready(function() {
$('.gameStart').click(function(event){
$(this).remove();
$('.gameHeader').remove();
$('.gamePage .gameContainer').css('display', 'block');
$.ajax({
type: 'GET',
url: '<?php echo admin_url("admin-ajax.php");?>',
data: {
action: 'CCAjax'
},
success: function(textStatus){
$( '.gameForm' ).prepend( textStatus );
},
error: function(MLHttpRequest, textStatus, errorThrown){
alert(errorThrown);
}
});
});
});
</script>
<div class="gameContainer">
<div class="timerWrapper">
<div id="timer">
</div>
</div>
<div class="gameForm">
<h3>Which of the following countries has the largest land mass?</h3>
<div id='answerSubmitButton'>Submit answer</div>
</div>
</div>
Then functions.php:
function CCAjax() {
get_template_part('template-parts/game');
die();
}
add_action('wp_ajax_CCAjax', 'CCAjax');
Then the game.php:
<?php
renderForm();
?>
Now here is the full render form function (It pulls 3 potential answers from DB and also has a countdown timer, hence why i didnt post it all i didnt want to confuse)
function renderForm() {
// Fetch contries object
global $wpdb;
$results = $wpdb->get_results("select * from ( select *,#curRow :=#curRow + 1 as row_number from ( select * from ( select * from wpCountriesDB order by rand() limit 3 )b order by Mass desc )a JOIN (select #curRow :=0)r)x order by RAND()");
// Create array for answers
if(!empty($results)) {
$i = 1;
foreach ($results as $r) {
echo "<div class='answerWrapper'>
<span class='questionNumber'><span>$i</span></span>
<label class='label' for='radio$i'>".$r->Country."</label>
<input type='radio' id='radio$i' name='like' value='$r->row_number' />
</div>";
$i++;
}
}
// Display timer and check answer correct
echo "<script>
var timeLeft = 3000;
var elem = document.getElementById('timer');
var timerId = setInterval(countdown, 1000);
function countdown() {
if (timeLeft < 0) {
clearTimeout(timerId);
$('#answerSubmitButton').click();
} else {
elem.innerHTML = timeLeft + 's';
timeLeft--;
}
}
jQuery(document).ready(function() {
$('body').on('click', '#answerSubmitButton', function(){
var fetchInput = document.querySelector('.answerWrapper input[name=\'like\']:checked');
var fetchSelected = fetchInput.value;
if (fetchSelected == 1) {
$.ajax({
type: 'POST',
url: 'ajaxURL',
data: {
action: adding_custom_meta
},
success: function(textStatus){
console.log('Success');
},
error: function(MLHttpRequest, textStatus, errorThrown){
alert('errorThrown');
}
});
} else {
console.log('incorrect')
}
});
});
</script>";
}
add_action("wp_ajax_create_user_meta", "create_user_meta");
add_action("wp_ajax_nopriv_create_user_meta", "create_user_meta");
function create_user_meta() {
$order = wc_get_order($order_id);
$order->update_meta_data('hasAnswered', 'Yes');
$order->save();
die();
}
Do i have to pass the Order ID at the very start?
Update (since your gave some context with the missing code):
Yes you have to pass the Order ID at the very start from your thankyou page (template).
You need to rethink differently your code, as you can't pass the order ID to your renderForm() function. The order ID is required to be passed through jQuery Ajax to your PHP Wordpress Ajax function that need it (to add to the order the custom meta data).
Also another mistake is (2 times):
jQuery(document).ready(function() {
that need to be instead (as you are using the jQuery shortand $):
jQuery(document).ready(function($) {
or (the same) in a shorter way:
jQuery(function($) {
Original answer:
There is some errors and missing things in your script, like the order Id that need to be passed through jQuery ajax to your PHP Wordpress/Ajax function that will add the custom meta data…
Also you don't provide in your code, the displayed button output…
So Here it is a complete example, based on your revisited code, that will display the button on Order received (thankyou) page and will add custom meta data to your order:
// PHP Wordpress AJAX: Add custom meta data to the Order
add_action("wp_ajax_adding_custom_meta", "adding_custom_order_metadata");
add_action("wp_ajax_nopriv_adding_custom_meta", "adding_custom_order_metadata");
function adding_custom_order_metadata() {
if( isset($_POST['order_id']) && $_POST['order_id'] > 0 ){
update_post_meta(esc_attr($_POST['order_id']), '_has_answered', 'Yes');
echo json_encode($_POST['order_id']);
}
die();
}
// Display a button on thankyou page (+ jQuery Ajax script)
add_action( 'woocommerce_thankyou', 'jquery_thank_you_page', 90, 1 );
function jquery_thank_you_page( $order_id ) {
// Display the button on thankyou page
echo ''.__("Update").'';
// The jQuery script (Ajax)
?>
<script type="text/javascript">
jQuery(function($) {
$('body').on('click', '#button', function(e){
e.preventDefault();
$.ajax({
type: 'POST',
url: '<?php echo admin_url("admin-ajax.php");?>',
data: {
'action': 'adding_custom_meta',
'order_id': '<?php echo $order_id; ?>'
},
success: function(response){
console.log(response); // Just for testing
},
error: function(error){
console.log(error); // Just for testing
}
});
});
});
</script>
<?php
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Using update_post_meta() function is much better and lighter alternative than calling an instance of the WC_Order Object and use after the save() method.
I have changed the order custom meta key from hasAnswered to _has_answered
On "Order received" page, the displayed button (the order Id come back, see in the console):
In the database, the custom post meta data is created:
Something like this
function renderForm($order_id) { //add an argument
echo "<script>
jQuery(document).ready(function() {
$('body').on('click', '#button', function(){
$.ajax({
type: 'POST',
url: 'https://thepropdrop.com/wp-admin/admin-ajax.php',
data: {
action: 'create_user_meta',
order_id: {$order_id} //add to your request data
},
success: function(textStatus){
console.log('Success');
},
error: function(MLHttpRequest, textStatus, errorThrown){
alert('errorThrown');
}
});
});
});
</script>";
}
Then in your AJAX callback
function create_user_meta() {
if(empty($_POST['order_id'])) {
//return some error message
die();
}
$order = wc_get_order($_POST['order_id']); //get the id from the request
$order->update_meta_data('hasAnswered', 'Yes');
$order->save();
die();
}
As there is no way for me to know how you call renderForm there is no way for me to know how to put the order id in it. But at some point it will have to be either an argument or part of an argument (in the case of shortcode $attr such as [renderForm order_id=45]).
You may be also able to use something like
$order_id = get_the_ID();
Or
$order = get_post();
$order_id = $order->ID;
Depending on the context of how you use renderForm, you probably cant use them in the AJAX callback because it's a new request so you lose any of that context you had when building the page.
Hope that makes sense.
Not tested, but ... maybe it will work ... it should in theory.
I've removed the standard "Added to cart" message given by WooCommerce. I have then added the code below which is using the Sweet Alert. The idea is to remove all "added to cart" messages and to only use the sweet alert.
Based on "JS alert on ajax add to cart for specific product category count in Woocommerce" answer code by #LoicTheAztec, my code works for the first product added, but not for the following ones. So it works fine when the cart is empty and when adding the first product.
Here's the code I'm using:
// remove add to cart woocommerce message
add_filter('wc_add_to_cart_message_html', '__return_null');
// Wordpress Ajax PHP
add_action('wp_ajax_nopriv_checking_items', 'atc_sweet_message');
add_action('wp_ajax_checking_items', 'atc_sweet_message');
function atc_sweet_message() {
if (isset($_POST['id']) && $_POST['id'] > 0) {
$count = 0;
$product_id = $_POST['id'];
foreach(WC()-> cart-> get_cart() as $cart_item) {
$count += $cart_item['quantity'];
}
}
echo $count;
die();
}
// jQuery Ajax
add_action('wp_footer', 'item_count_check');
function item_count_check() {
if (is_checkout())
return;
?>
<script src="https://unpkg.com/sweetalert2#7.20.1/dist/sweetalert2.all.js"></script>
<script type="text/javascript">
jQuery( function($) {
if ( typeof wc_add_to_cart_params === 'undefined' )
return false;
$(document.body).on( 'added_to_cart', function( event, fragments, cart_hash, $button ) {
$.ajax({
type: 'POST',
url: wc_add_to_cart_params.ajax_url,
data: {
'action': 'checking_items',
'id' : $button.data( 'product_id' )
},
success: function (response) {
if(response == 1 ){
const toast = swal.mixin({
toast: true,
showConfirmButton: false,
timer: 3000
});
toast({
type: 'success',
title: 'Product Added To Cart'
})
}
}
});
});
});
</script>
<?php
}
I tried removing if(response == 1 ){ without success. Any input on this is appreciated.
There was little mistakes in your code on the function for Wordpress Ajax PHP. Try the following:
// remove add to cart woocommerce message
add_filter('wc_add_to_cart_message_html', '__return_null');
// Wordpress Ajax PHP
add_action('wp_ajax_nopriv_item_added', 'addedtocart_sweet_message');
add_action('wp_ajax_item_added', 'addedtocart_sweet_message');
function addedtocart_sweet_message() {
echo isset($_POST['id']) && $_POST['id'] > 0 ? (int) esc_attr($_POST['id']) : false;
die();
}
// jQuery Ajax
add_action('wp_footer', 'item_count_check');
function item_count_check() {
if (is_checkout())
return;
?>
<script src="https://unpkg.com/sweetalert2#7.20.1/dist/sweetalert2.all.js"></script>
<script type="text/javascript">
jQuery( function($) {
if ( typeof wc_add_to_cart_params === 'undefined' )
return false;
$(document.body).on( 'added_to_cart', function( event, fragments, cart_hash, $button ) {
var $pid = $button.data('product_id');
$.ajax({
type: 'POST',
url: wc_add_to_cart_params.ajax_url,
data: {
'action': 'item_added',
'id' : $pid
},
success: function (response) {
if(response == $pid){
const toast = swal.mixin({
toast: true,
showConfirmButton: false,
timer: 3000
});
toast({
type: 'success',
title: 'Product Added To Cart'
})
}
}
});
});
});
</script>
<?php
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
It works now for all ajax added to cart items (and not just the first one).
I want to prevent the user to stop selecting or drag and drop while the previous ajax request is in process.
How can i do this...
Here is the code js code :
#drag is the div id of drag and drop area
$( '#drag ' ).bind( 'dragover',function(event) {
event.stopPropagation();
event.preventDefault();
});
$( '#drag ' ).bind( 'drop',function(event) {
event.stopPropagation();
event.preventDefault();
if( upfiles == 0 )
{
upfiles = event.originalEvent.dataTransfer.files;
console.dir(upfiles);
upfiles = Array.prototype.slice.call(upfiles, 0);
}
else {
if(confirm( "Drop: Do you want to clear files selected already?" ) == true) {
upfiles = event.originalEvent.dataTransfer.files;
upfiles = Array.prototype.slice.call(upfiles, 0);
$('#fileToUpload').val('');
}
else
return;
}
$( "#fileToUpload" ).trigger( 'change' );
});
after clicking on upload button:
$("#upload_btn").click( function() {
if ( upfiles ) {
$( '#fileToUpload' ).trigger('upload'); // trigger the first 'upload' - custom event.
$(this).prop("disabled", true);
}
});
Here is the ajax request :
$( '#container' ).on( 'upload', '#fileToUpload' , function( ) {
if ( typeof upfiles[count] === 'undefined') return false;
var data = new FormData();
var fileIn = $( "#fileToUpload" )[0];
if( !upfiles )
upfiles = fileIn.files;
$(upfiles).each(function(index, file)
{
data.append( 'file'+index, file );
});
var request = $.ajax({
url: 'files.php',
type: 'POST',
data: data,
cache: false,
contentType: false,
processData: false,
beforeSend: function( ) {
$(".progressbar").show();
},
xhr: function() {
var xhr = $.ajaxSettings.xhr();
if(xhr.upload){
xhr.upload.addEventListener( 'progress', showProgress, false);
}
return xhr;
},
success: function(data){
if( percentComplete <= 100 ) {
$('#pb div').animate({ width: '100%' }, { step: function(now) {
$(this).text( Math.round(now) + '%' );
}, duration: 10});
}
$('#uplcomp').append( data );
}
});
How can i prevent the user while the previous files upload is in progress.
Updated
ok got it upto some extent (but this is also not a good idea, user can add div back from the firebug and send files again)
i have used
$( document ).ajaxStart(function() {
$( "#total" ).remove();
});
and in ajax start :
$(document).ajaxStop( function( ) {
//how can i add div back say : add <div id='total'></div> after <div id='someid'></div>
});
Is there any possibility that i can stop second ajax request while the first ajax is in process?
Apart from enabling/disabling drag and drop while ajax is in progress, I believe a better solution will be to show an transparent or translucent overlay which covers that area and prevent the user from selecting any draggable.
For disabling/enabling using jquery:
Use $( "#total" ).draggable( "disable" ); inside beforeSend() function of ajax.
Use $( "#total" ).draggable( "enable" ); inside success() of function ajax
Using CSS:
demo: http://jsfiddle.net/lotusgodkk/GCu2D/184/
CSS:
.checked {
position:fixed;
top:0;
left:0;
right:0;
bottom:0;
background:#BFBFBF;
opacity:0.5;
text-align:center;
}
.checked div {
margin:0 auto;
top:50%;
left:50%;
position:absolute;
}
HTML:
<div class="checked">
<div>Please wait...</div>
</div>
Just toggle the hide/show during ajax
Use $('.checked').show(); in beforeShow() and $('.checked').hide(); in success()
Finally i have used
if($.active === 0)
{
call ajax
}
else
{
alert("please wait previous request is in process");
}
I have this ajax-loaded #container and I'm trying to get it to play nice with some of my plugins. So far I managed to get scrollTo and a lightbox working inside this "container of death" using jquery.live but no luck with my fancy "add to cart" buttons. I've been playing around with .delegate, the livequery plugin, etc., for a few days now but I'm really not advanced enough to figure out what goes where. (I have a pretty shallow understanding of what I'm doing.)
Here's my shopping cart plugin, it's fairly small and straightforward. Can you give suggestions on what (.live, .delegate, or .livequery, or perhaps something else entirely) should be inserted where?
(Note: shopme p = the add to cart buttons, which need to be inserted inside the ajax-loaded "container of death." The rest of the cart exists outside said container and works fine since it's not ajax'ed in.)
$(document).ready(function(){
$('.wooo').bloooming_shop();
$('body').append('<div id="panel"><div id="panelcontent"></div><div class="panelbutton" id="hidepanel" style="display: none;"><a><font class="cartfont2">hide cart</font></a></div></div><div id="showpanel" class="panelbutton" style="display: visible;"><a><font class="cartfont">shopping cart</font></a></div><div id="btntarget"></div>');
$('#panelcontent').hide();
$.ajax({
type: "GET",
url: "/wooo/cart.php",
async: false,
dataType: "html",
success: function(html){
$('#panelcontent').html(html);
}
});
$(".panelbutton").click(function(){
$("#panel").animate({
height: "200px"
}, "fast",function(){
$('#panelcontent').show();
});
$("#hidepanel").fadeIn();
$("#showpanel").fadeOut();
});
$("#hidepanel").click(function(){
$("#panel").animate({
height: "0px"
}, "fast", function(){
$("#showpanel").fadeIn();
$('#panelcontent').hide();
});
$("#hidepanel").fadeOut();
});
// START 'ADD TO CART' BUTTONS
$('.shopme p').click(function(){
var pid = $(this).attr('rel');
$('body').prepend('<div class="shadow" id="'+$(this).attr('rel')+'_shadow"></div>');
var shadow = $('#'+pid+'_shadow');
shadow.width($(this).parent().css('width')).height($(this).parent().css('height')).css('top', $(this).parent().offset().top).css('left', $(this).parent().offset().left).css('opacity', 0.5).show();
shadow.css('position', 'absolute');
shadow.animate( {
width: $('#btntarget').innerWidth(),
height: $('#btntarget').innerHeight(),
top: $('#btntarget').offset().top,
left: $('#btntarget').offset().left
}, {
duration: 2000
} )
.animate({
opacity: 0
},
{
duration: 700,
complete: function(){
shadow.remove();
}
});
var option = $('#'+pid+' .woooptions').val();
var formData = 'pid=' + pid + '&option=' + option;
$.ajax({
type : 'POST',
url : '/wooo/cart.php',
data : formData,
success : function (html) {
$('#panelcontent').html(html);
}
});
});
$('.removeitem').live('click', function() { // .LIVE is used here
rid = $(this).attr('id');
rop = $(this).attr('rel');
var remData = 'remove=' + rid + '&rop=' + rop;
$.ajax({
type : 'POST',
url : '/wooo/cart.php',
data : remData,
success : function (html) {
$('#panelcontent').html(html);
// alert('thx');
}
});
});
}); // document
function checkOut(){
jQuery.ajax({
url: "/wooo/cart.php",
type: "POST",
data : "destroysession=true",
success: function(data, textStatus, jqXHR){
if(data){
window.location.href=jQuery('a.checkout').attr("data-href");
}else{
console.log("There is no data!")
}
},
error: function(jqXHR, textStatus, errorThrown){
console.log("AJAX ERROR: "+errorThrown)
}
});
}
/** replace ******/
jQuery.fn.bloooming_shop = function(){
this.each(function(){
var elem = $(this);
var cl = 'bt1';
var id = $(this).html();
var opt = $(this).attr('options');
var text = $(this).attr('text');
var price = $(this).attr('price');
// alert(price);
if (text == undefined) {
text = 'add to cart';
}
if (opt == 'true' && price != 'true' ) {
cl = 'bt3';
}
if (price == 'true' && opt == 'true') {
cl = 'bt4';
}
if (price == 'true' && opt != 'true') {
cl = 'bt2';
}
elem.removeClass('wooo');
elem.addClass('shopme');
elem.addClass(cl);
elem.attr('id','pid'+id);
elem.html('<p rel="pid'+id+'" class="'+cl+'">'+ text +'</p>');
// get product data
if (price == 'true' || opt == 'true') {
$.ajax({
type : 'GET',
url : '/wooo/functions.php?mode=p_data&id='+id+'&opt='+opt+'&price='+price,
success : function (html) {
elem.append(html);
if (jQuery().sSelect) {
elem.children('.woooptions').sSelect();
}
// change price
$('.woooptions').change(function(){
var selid = $(this).attr('id');
var rel = $('#'+selid+' option:selected').attr('rel');
if (rel != undefined) {
$(this).parent().children('.woooprice').html(rel);
}
});
}
});
}
});
return false;
};
How do I keep this plugin alive, even within ajax'ed-in #container? I really just need the 'add to cart' buttons (shopme p) to be in said container div. Thank you.
.live("click", function(){
instead of just click.