Show product variations on shop pages in woocommerce - php

I have the same problem which was talked over here
I have added the code using PHP snippets plugin, but I'm not sure where to add the ajax code
I just want to add product variations on shop page with possiblity of adding to cart without reloading the page
you can also check my website over here

if you don't have access to your main script files and you can't add another files then you can add the script to WordPress Footer using wp_footer hook as follow:
add_action('wp_footer', 'myScript');
function myScript()
{
?>
<script>
jQuery(document).ready(function ($) {
"use strict";
$('.custom_add_to_cart').click(function (e) {
e.preventDefault();
var id = $(this).next().next().next().attr('value');
var data = {
product_id: id,
quantity: 1
};
$(this).parent().addClass('loading');
$.post(wc_add_to_cart_params.wc_ajax_url.toString().replace('%%endpoint%%', 'add_to_cart'), data, function (response) {
if (!response) {
return;
}
if (response.error) {
alert("Custom Massage ");
$('.custom_add_to_cart').parent().removeClass('loading');
return;
}
if (response) {
var url = woocommerce_params.wc_ajax_url;
url = url.replace("%%endpoint%%", "get_refreshed_fragments");
$.post(url, function (data, status) {
$(".woocommerce.widget_shopping_cart").html(data.fragments["div.widget_shopping_cart_content"]);
if (data.fragments) {
jQuery.each(data.fragments, function (key, value) {
jQuery(key).replaceWith(value);
});
}
jQuery("body").trigger("wc_fragments_refreshed");
});
$('.custom_add_to_cart').parent().removeClass('loading');
}
});
});
});
</script>
<?php
}

add the whole code under here into your php snippet plugin and it would work like a charm
thanks to #kacholo
/**
* Replace add to cart button in the loop.
*/
function iconic_change_loop_add_to_cart() {
remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart', 10 );
add_action( 'woocommerce_after_shop_loop_item', 'iconic_template_loop_add_to_cart', 10 );
}
add_action( 'init', 'iconic_change_loop_add_to_cart', 10 );
/**
* Use single add to cart button for variable products.
*/
function iconic_template_loop_add_to_cart() {
global $product;
if ( ! $product->is_type( 'variable' ) ) {
woocommerce_template_loop_add_to_cart();
return;
}
remove_action( 'woocommerce_single_variation', 'woocommerce_single_variation_add_to_cart_button', 20 );
add_action( 'woocommerce_single_variation', 'iconic_loop_variation_add_to_cart_button', 20 );
woocommerce_template_single_add_to_cart();
}
/**
* Customise variable add to cart button for loop.
*
* Remove qty selector and simplify.
*/
function iconic_loop_variation_add_to_cart_button()
{
global $product;
?>
<div class="woocommerce-variation-add-to-cart variations_button">
<button type="submit" class="custom_add_to_cart single_add_to_cart_button button"><?php echo esc_html($product->single_add_to_cart_text()); ?></button>
<input type="hidden" name="add-to-cart" value="<?php echo absint($product->get_id()); ?>" />
<input type="hidden" name="product_id" value="<?php echo absint($product->get_id()); ?>" />
<input type="hidden" name="variation_id" class="variation_id" value="0" />
</div>
<?php
}
function iconic_add_to_cart_form_action( $redirect ) {
if ( ! is_archive() ) {
return $redirect;
}
return '';
}
add_filter( 'woocommerce_add_to_cart_form_action', 'iconic_add_to_cart_form_action' );
add_action('wp_footer', 'myScript');
function myScript()
{
?>
<script>
jQuery(document).ready(function ($) {
"use strict";
$('.custom_add_to_cart').click(function (e) {
e.preventDefault();
var id = $(this).next().next().next().attr('value');
var data = {
product_id: id,
quantity: 1
};
$(this).parent().addClass('loading');
$.post(wc_add_to_cart_params.wc_ajax_url.toString().replace('%%endpoint%%', 'add_to_cart'), data, function (response) {
if (!response) {
return;
}
if (response.error) {
alert("Custom Massage ");
$('.custom_add_to_cart').parent().removeClass('loading');
return;
}
if (response) {
var url = woocommerce_params.wc_ajax_url;
url = url.replace("%%endpoint%%", "get_refreshed_fragments");
$.post(url, function (data, status) {
$(".woocommerce.widget_shopping_cart").html(data.fragments["div.widget_shopping_cart_content"]);
if (data.fragments) {
jQuery.each(data.fragments, function (key, value) {
jQuery(key).replaceWith(value);
});
}
jQuery("body").trigger("wc_fragments_refreshed");
});
$('.custom_add_to_cart').parent().removeClass('loading');
}
});
});
});
</script>
<?php
}

Related

Use Woocommerce session variable whitout reload

I'm having a problem, a need to apply a filter when user changes the selection of an input radio, I did this code, but it only works if I reload the page, what can I do to avoid reload and the page charge the filter whithout reloading?
`
add_action( 'wp_footer', 'wpmc_set_session_on_button_click' );
function wpmc_set_session_on_button_click() {
session_start();
$array_selectores = $_SESSION['array_selectores'];
$json = json_encode($array_selectores);
?>
<script>
document.querySelectorAll('input[name="horario-liga"]').forEach(function(input) {
input.addEventListener("change", function(e) {
var jsArray = <?php echo $json; ?>;
var horarioLigaValue = document.querySelector('input[name="horario-liga"]:checked').value;
var data = {
action: 'wpmc_set_session',
dto_manana: 'dto'
};
var data2 = {
action: 'wpmc_set_session',
dto_manana: 'no'
};
if (jsArray.includes(horarioLigaValue)) {
jQuery.post(
'<?php echo admin_url('admin-ajax.php'); ?>',
data,
function(response) {
console.log(response);
//console.log('dto');
}
);
}
else {
jQuery.post(
'<?php echo admin_url('admin-ajax.php'); ?>',
data2,
function(response) {
console.log(response);
//console.log('no');
}
);
}
});
});
</script>
<?php
}
// Manejador de petición AJAX para establecer la variable de sesión
add_action( 'wp_ajax_wpmc_set_session', 'wpmc_ajax_set_session' );
add_action( 'wp_ajax_nopriv_wpmc_set_session', 'wpmc_ajax_set_session' );
function wpmc_ajax_set_session() {
error_log(print_r($_POST, true));
echo $_POST['dto_manana'];
WC()->session->set( 'dto_manana', $_POST['dto_manana'] );
wp_die();
}
add_action( 'woocommerce_review_order_before_payment', 'detectar_radio_button_seleccionado' );
function detectar_radio_button_seleccionado() {
$dto_manana = WC()->session->get('dto_manana');
if (isset($dto_manana)) {
echo $dto_manana;
}
}
add_filter('woocommerce_cart_calculate_fees', 'add_recurring_postage_fees',10,1);
function add_recurring_postage_fees( $cart ) {
$dto_manana = WC()->session->get('dto_manana');
if ( (! empty( $cart->recurring_cart_key )) && ($dto_manana == 'dto') ) {
$cart->add_fee( 'Postage', 5 );
}
}`
If I go to checkout page I get the value 'dto' or 'no' but in order review only show the value of the last session, not the actual. I need to apply add_filter('woocommerce_cart_calculate_fees', 'add_recurring_postage_fees',10,1); when I select in horario-liga any value include in the array

Dynamic discount using AJAX and Fee API in Woocommerce checkout page

I have put a select box in the checkout page like this.
function rx_wc_reward_points_check() {
$reward_points = '<select class="rx-rewad-points" id="rx-redemption-points">
<option value="1250">$25.00 Off (1250 Points) </option>
<option value="2500">$50.00 Off (2500 Points) </option>
<option value="5000">$100.00 Off (5000 Points) </option>
<option value="7000">$150.00 Off (7000 Points) </option>
</select>';
$reward_points .= '<a class="button alt" name="rx_reward_points_btn" id="rx_reward_points" value="Apply" data-value="Reward Points">Apply Now</a>';
echo $reward_points;
}
add_action( 'woocommerce_checkout_after_customer_details', 'rx_wc_reward_points_check', 10, 0 );
After that i have added this to the function file for
function rx_wc_deduct_reward() {
global $woocommerce;
$reward_value = $_POST['rewardpoints'];
WC()->cart->add_fee( 'Fee', -$reward_value );
echo 'success';
exit;
}
add_action( 'wp_ajax_rx_wc_deduct_reward', 'rx_wc_deduct_reward' );
add_action( 'wp_ajax_nopriv_rx_wc_deduct_reward', 'rx_wc_deduct_reward' );
This is using for the ajax part
jQuery(document).ready( function() {
jQuery('#rx_reward_points').on('click', function() {
var selectedrewad = jQuery( "#rx-redemption-points option:selected" ).val();
jQuery.ajax({
type : "post",
url : ajax_var.ajaxurl,
data : { action: "rx_wc_deduct_reward", rewardpoints : selectedrewad },
success: function(response) {
console.log(response)
if(response == "success") {
console.log('done');
}
else {
console.log("Your vote could not be added")
}
}
});
})
})
But it is not working. I have done some mistake in the "rx_wc_deduct_reward" function. I cant figure out how to do this.
Any help is appreciated.
You need to make it slight different to get it work as you get some errors and missing parts:
// Displaying a select field and a submit button in checkout page
add_action( 'woocommerce_checkout_after_customer_details', 'rx_wc_reward_points_check', 10, 0 );
function rx_wc_reward_points_check() {
echo '<select class="rx-rewad-points" id="rx-redemption-points">
<option value="25">' . __("$25.00 Off (1250 Points)", "woocommerce" ) . '</option>
<option value="50">' . __("$50.00 Off (2500 Points)", "woocommerce" ) . '</option>
<option value="100">' . __("$100.00 Off (5000 Points)", "woocommerce" ) . '</option>
<option value="150">' . __("$150.00 Off (7000 Points)", "woocommerce" ) . '</option>
</select>
<a class="button alt" name="rx_reward_points_btn" id="rx_reward_points" value="Apply" data-value="Reward Points">Apply Now</a>';
}
// jQuery - Ajax script
add_action( 'wp_footer', 'rx_wc_reward_points_script' );
function rx_wc_reward_points_script() {
// Only checkout page
if ( ! is_checkout() ) return;
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
$('#rx_reward_points').on('click', function() {
$.ajax({
type: "post",
url: wc_checkout_params.ajax_url,
data: {
'action' : 'rx_wc_deduct_reward',
'rewardpoints' : $("#rx-redemption-points").val()
},
success: function(response) {
$('body').trigger('update_checkout');
console.log('response: '+response); // just for testing | TO BE REMOVED
},
error: function(error){
console.log('error: '+error); // just for testing | TO BE REMOVED
}
});
})
})
</script>
<?php
}
// Wordpress Ajax code (set ajax data in Woocommerce session)
add_action( 'wp_ajax_rx_wc_deduct_reward', 'rx_wc_deduct_reward' );
add_action( 'wp_ajax_nopriv_rx_wc_deduct_reward', 'rx_wc_deduct_reward' );
function rx_wc_deduct_reward() {
if( isset($_POST['rewardpoints']) ){
WC()->session->set( 'custom_fee', esc_attr( $_POST['rewardpoints'] ) );
echo true;
}
exit();
}
// Add a custom dynamic discount based on reward points
add_action( 'woocommerce_cart_calculate_fees', 'rx_rewardpoints_discount', 20, 1 );
function rx_rewardpoints_discount( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Only for targeted shipping method
if ( WC()->session->__isset( 'custom_fee' ) )
$discount = (float) WC()->session->get( 'custom_fee' );
if( isset($discount) && $discount > 0 )
$cart->add_fee( __( 'Reward discount', 'woocommerce' ), -$discount );
}
Code goes in function.php file of your active child theme (or active theme). Tested and works

Replace "add to cart" with custom quantity input fields in WooCommerce

I am using WooCommerce with Storefront theme to build an eCommerce website that will be used on smartphones mostly. So I am trying to reduce the number of clicks and buttons to make it as simple as possible.
I would like to replace "add to cart" button with a quantity selector :
I found a way to add a quantity selector next to "add to cart" button (e.g. with plugin WooCommerce Advanced Product Quantities) but I would like to get rid of "add to cart" button.
So, when a customer click on "+", it should add 1 element to the cart and the number should display the quantity in the cart.
Also (no idea if this is possible...), I'd like an animation to notify the customer that the product was well added to the cart. For instance, show a "+1" for a few seconds near the cart icon,
here you go it's going to be long one :
First Let's Remove the Add To Cart Button:
// Remove Add To cart Button
remove_action('woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart', 10);
Now Lets Create our Input and add it to shop page
// Add our Quanity Input
add_action('woocommerce_after_shop_loop_item', 'QTY');
function QTY()
{
global $product;
?>
<div class="shopAddToCart">
<button value="-" class="minus" >-</button>
<input type="text"
disabled="disabled"
size="2"
value="<?php echo (Check_if_product_in_cart($product->get_id())) ? Check_if_product_in_cart($product->get_id())['QTY'] : 0;
?>"
id="count"
data-product-id= "<?php echo $product->get_id() ?>"
data-in-cart="<?php echo (Check_if_product_in_cart($product->get_id())) ? Check_if_product_in_cart($product->get_id())['in_cart'] : 0;
?>"
data-in-cart-qty="<?php echo (Check_if_product_in_cart($product->get_id())) ? Check_if_product_in_cart($product->get_id())['QTY'] : 0;
?>"
class="quantity qty"
max_value = <?php echo ($product->get_max_purchase_quantity() == -1) ? 1000 : $product->get_max_purchase_quantity(); ?>
min_value = <?php echo $product->get_min_purchase_quantity(); ?>
>
<button type="button" value="+" class="plus" >+</button>
</div>
<?php
}
we need to have function to check if the products is already in cart or not so can modify the quantity:
//Check if Product in Cart Already
function Check_if_product_in_cart($product_ids)
{
foreach (WC()->cart->get_cart() as $cart_item):
$items_id = $cart_item['product_id'];
$QTY = $cart_item['quantity'];
// for a unique product ID (integer or string value)
if ($product_ids == $items_id):
return ['in_cart' => true, 'QTY' => $QTY];
endif;
endforeach;
}
we need to add custom event in order to reduce the quantity:
//Add Event Handler To update QTY
add_action('wc_ajax_update_qty', 'update_qty');
function update_qty()
{
ob_start();
$product_id = absint($_POST['product_id']);
$product = wc_get_product($product_id);
$quantity = $_POST['quantity'];
foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item):
if ($cart_item['product_id'] == $product_id) {
WC()->cart->set_quantity($cart_item_key, $quantity, true);
}
endforeach;
wp_send_json('done');
}
Finally We need Javascript to handle the event actions :
jQuery(document).ready(function ($) {
"use strict";
// Add Event Listner on the Plush button
$('.plus').click(function () {
if (parseInt($(this).prev().val()) < parseInt($(this).prev().attr('max_value'))) {
$(this).prev().val(+$(this).prev().val() + 1);
var currentqty = parseInt($(this).prev().attr('data-in-cart-qty')) + 1;
var id = $(this).prev().attr('data-product-id');
var data = {
product_id: id,
quantity: 1
};
$(this).prev().attr('data-in-cart-qty', currentqty);
$(this).parent().addClass('loading');
$.post(wc_add_to_cart_params.wc_ajax_url.toString().replace('%%endpoint%%', 'add_to_cart'), data, function (response) {
if (!response) {
return;
}
if (response) {
var url = woocommerce_params.wc_ajax_url;
url = url.replace("%%endpoint%%", "get_refreshed_fragments");
$.post(url, function (data, status) {
$(".woocommerce.widget_shopping_cart").html(data.fragments["div.widget_shopping_cart_content"]);
if (data.fragments) {
jQuery.each(data.fragments, function (key, value) {
jQuery(key).replaceWith(value);
});
}
jQuery("body").trigger("wc_fragments_refreshed");
});
$('.plus').parent().removeClass('loading');
}
});
}
});
$('.minus').click(function () {
$(this).next().val(+$(this).next().val() - 1);
var currentqty = parseInt($(this).next().val());
var id = $(this).next().attr('data-product-id');
var data = {
product_id: id,
quantity: currentqty
};
$(this).parent().addClass('loading');
$.post(wc_add_to_cart_params.wc_ajax_url.toString().replace('%%endpoint%%', 'update_qty'), data, function (response) {
if (!response) {
return;
}
if (response) {
var url = woocommerce_params.wc_ajax_url;
url = url.replace("%%endpoint%%", "get_refreshed_fragments");
$.post(url, function (data, status) {
$(".woocommerce.widget_shopping_cart").html(data.fragments["div.widget_shopping_cart_content"]);
if (data.fragments) {
jQuery.each(data.fragments, function (key, value) {
jQuery(key).replaceWith(value);
});
}
jQuery("body").trigger("wc_fragments_refreshed");
});
$('.plus').parent().removeClass('loading');
}
});
});
});
Note: This code is tested and working you can check it at
http://dev-ak.com/woocommerce-dev/shop/
You can download the whole files from :
https://github.com/kashalo/wc_qty_ajax_stroefront_child.git
Regarding the Animation part in footer cart that of course can be done, and if i have some free time i will do it too.

WooCommerce - change QTY triggers AJAX call in cart

I would like to update and then reload my cart via AJAX when the quantity of an item in the cart is changed.
I can already successfully load in my cart via AJAX.
To load in my cart my php function looks like this. (in my functions.php)
function enqueue_cart_show_ajax() {
wp_register_script( 'cart-show-ajax-js', get_template_directory_uri() . '/js/cart-show-ajax.js', array( 'jquery' ), '', true );
wp_localize_script( 'cart-show-ajax-js', 'cart_show_ajax', array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
wp_enqueue_script( 'cart-show-ajax-js' );
}
add_action('wp_enqueue_scripts', 'enqueue_cart_show_ajax');
function ajax_show_cart() {
echo do_shortcode( '[woocommerce_cart]' );
die();
}
add_action('wp_ajax_show_cart', 'ajax_show_cart');
add_action('wp_ajax_nopriv_show_cart', 'ajax_show_cart');
My Jquery code looks like this (in cart-show-ajax.js)
jQuery(function($) {
//If view-cart is clicked, fill the view-cart-popup window with the cart
$( '.view-cart' ).on('click', function(){
show_cart();
});
//Main ajax function
function show_cart() {
$.ajax({
type: 'GET',
url: cart_show_ajax.ajax_url,
data: {
action: 'show_cart',
},
beforeSend: function ()
{
//You could show a loader here
},
success: function(data)
{
//Hide loader here
$( '.view-cart-popup' ).html(data);
activateReturnToShop();
},
error: function()
{
//If an ajax error has occured, do something here...
$(".product-container").html('<p>There has been an error</p>');
}
});
}
});
The HTML for the cart is as follows
<td class="product-quantity">
<div class="quantity">
<input type="number" step="1" min="0"
name="cart[1e334311e1ef4cf849abff19e4237358][qty]"
value="4" title="Qty" class="input-text qty text" size="4">
</div>
</td>
My best guess is that I can achieve this if when the input is changed I run a function that updates the cart, then simply runs the existing show_cart() function.
I'm not sure about how to make a function that will detect the change to input, grab the new quantity of the product and update the amount in the cart...
It could looks something like:
$( 'input.qty' ).on("change", function(){
// Grab the new product quantity
// Update the cart
show_cart();
});
Anyone know how to get the new quantity update the cart with it?
Thank you for all your help!
Okay so I figured it out!
I can now update cart item's quantities without refreshing via AJAX (:
my functions.php looks like this
//Enqueue Ajax Scripts
function enqueue_cart_qty_ajax() {
wp_register_script( 'cart-qty-ajax-js', get_template_directory_uri() . '/js/cart-qty-ajax.js', array( 'jquery' ), '', true );
wp_localize_script( 'cart-qty-ajax-js', 'cart_qty_ajax', array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
wp_enqueue_script( 'cart-qty-ajax-js' );
}
add_action('wp_enqueue_scripts', 'enqueue_cart_qty_ajax');
function ajax_qty_cart() {
// Set item key as the hash found in input.qty's name
$cart_item_key = $_POST['hash'];
// Get the array of values owned by the product we're updating
$threeball_product_values = WC()->cart->get_cart_item( $cart_item_key );
// Get the quantity of the item in the cart
$threeball_product_quantity = apply_filters( 'woocommerce_stock_amount_cart_item', apply_filters( 'woocommerce_stock_amount', preg_replace( "/[^0-9\.]/", '', filter_var($_POST['quantity'], FILTER_SANITIZE_NUMBER_INT)) ), $cart_item_key );
// Update cart validation
$passed_validation = apply_filters( 'woocommerce_update_cart_validation', true, $cart_item_key, $threeball_product_values, $threeball_product_quantity );
// Update the quantity of the item in the cart
if ( $passed_validation ) {
WC()->cart->set_quantity( $cart_item_key, $threeball_product_quantity, true );
}
// Refresh the page
echo do_shortcode( '[woocommerce_cart]' );
die();
}
add_action('wp_ajax_qty_cart', 'ajax_qty_cart');
add_action('wp_ajax_nopriv_qty_cart', 'ajax_qty_cart');
My cart-qty-ajax.js looks like this.
jQuery( function( $ ) {
$( document ).on( 'change', 'input.qty', function() {
var item_hash = $( this ).attr( 'name' ).replace(/cart\[([\w]+)\]\[qty\]/g, "$1");
var item_quantity = $( this ).val();
var currentVal = parseFloat(item_quantity);
function qty_cart() {
$.ajax({
type: 'POST',
url: cart_qty_ajax.ajax_url,
data: {
action: 'qty_cart',
hash: item_hash,
quantity: currentVal
},
success: function(data) {
$( '.view-cart-popup' ).html(data);
}
});
}
qty_cart();
});
});
Works beautifully, though I'm not sure if this is 'good practice'.
Thanks all!
This is a easy ways to resolve this if your are doing the scripting your selves instead of any plugin. Below code will help you to update the cart on quantity dropdown change in customize pop up window where mini cart is displaying:
javascript:
$(document).on('click', '.qty', function (e)
{
e.preventDefault();
var qty = $(this).val();
var cart_item_key = $(this).attr("id");
$.ajax({
type: 'POST',
dataType: 'json',
url: '<?php echo SITE_URL; ?>/wp-admin/admin-ajax.php',
data: {action : 'update_item_from_cart', 'cart_item_key' : cart_item_key, 'qty' : qty, },
success: function (data) {
alert('Updated successfully.');
if (data) {
alert('You missed something');
}else{
alert('Updated Successfully');
}
}
});
});
*In above script .qty is class of the number dropdown.
*Pass two values only i.e cart_item_key and quantity.
*SITE_URL is domain name
*pass two values i.e. qty and cart item key
in functions.php place the below script
function update_item_from_cart() {
$cart_item_key = $_POST['cart_item_key'];
$quantity = $_POST['qty'];
// Get mini cart
ob_start();
foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item)
{
if( $cart_item_key == $_POST['cart_item_key'] )
{
WC()->cart->set_quantity( $cart_item_key, $quantity, $refresh_totals = true );
}
}
WC()->cart->calculate_totals();
WC()->cart->maybe_set_cart_cookies();
return true;
}
add_action('wp_ajax_update_item_from_cart', 'update_item_from_cart');
add_action('wp_ajax_nopriv_update_item_from_cart', 'update_item_from_cart');

Woocommerce - Product Page - How to create AJAX on "Add To Cart" button?

I want to make an "Add To Cart" button on a product page that would work with AJAX. How can I do it? When I add to cart on a product page - it refreshes the page, how can I make it work by AJAX?
The "Add to cart" button on "Quick View" on archive works by ajax - and it's great, but how can I do the same on product page?
I want to click on "Take me Home" on the product page which would then
add the product with the selected attributes to my cart by ajax and will open that cart (like when you hover onto the bag image on menu) and shakes the bag image.
Just add the following attributes to the Add to Cart button to enable the Ajax button.
<a href="<?php echo $product->add_to_cart_url() ?>" value="<?php echo esc_attr( $product->get_id() ); ?>" class="ajax_add_to_cart add_to_cart_button" data-product_id="<?php echo get_the_ID(); ?>" data-product_sku="<?php echo esc_attr($sku) ?>" aria-label="Add “<?php the_title_attribute() ?>” to your cart">
Add to Cart
</a>
The ajax_add_to_cart add_to_cart_button classes, and the data-product_id="<?php echo get_the_ID(); ?>" data-product_sku="<?php echo esc_attr($sku) ?>" attributes are required.
No need to apply any action or filter.
We can use ajax from archive page. it's easy -
Remove old button which submiting form:
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
Add ajax-link from archive page to single product page:
add_action( 'woocommerce_single_product_summary', 'woocommerce_template_loop_add_to_cart', 30 );
P.S. JS Callback. For example you can show popup with links "Back to shop" and "Cart" or "Checkout"
$('body').on('added_to_cart',function(){
// Callback -> product added
//$('.popup').show();
});
Please start by reading this page:
http://codex.wordpress.org/Plugin_API/Action_Reference/wp_ajax_(action)
First you need to add some code to your functions.php for example:
add_action( 'wp_ajax_add_foobar', 'prefix_ajax_add_foobar' );
add_action( 'wp_ajax_nopriv_add_foobar', 'prefix_ajax_add_foobar' );
function prefix_ajax_add_foobar() {
$product_id = intval( $_POST['product_id'] );
// add code the add the product to your cart
die();
}
Then you have to add some javascript code that triggers the add to cart and makes a call to the function:
jQuery( ".add-to-cart" ).each(function()
{
var product_id = jQuery(this).attr('rel');
var el = jQuery(this);
el.click(function() {
var data = {
action: 'add_foobar',
product_id: product_id
};
jQuery.post('/wp-admin/admin-ajax.php' , data, function(response) {
if(response != 0) {
// do something
} else {
// do something else
}
});
return false;
});
});
This is just an example of how it can be done. Although its very basic. This javascript checks for links with the classname .add-to-cart and checks the rel attribute for the corresponding product. It then sends the product id to the php class. There you need to add code to add the corresponding product to the cart.
I suggest you search some more about the topic to make it suit your needs. Good luck.
Woocommerce has come along way. I think the solution is quite easy now. In case I am missing something, all that is required it checking the "Enable AJAX add to cart buttons on archives" and using the woocommerce_template_loop_add_to_cart() function.
The checkbox option is under Woocommerce > Settings > Products > General.
Then simply use woocommerce_template_loop_add_to_cart() wherever you wish to output the button.
If you are using a custom loop like I was, you need to be sure to make the product global in order for the woocommerce_template_loop_add_to_cart() to work.
Below is a small example of using the function:
add_shortcode( 'buy_again' , 'msp_buy_again_shortcode' );
function msp_buy_again_shortcode(){
$order_items = msp_get_customer_unique_order_items( get_current_user_id() );
echo '<div class="owl-carousel owl-theme">';
foreach( $order_items as $id ){
$product = wc_get_product( $id );
global $product;
if( ! empty( $product ) ){
?>
<div class="card buy-again-product">
<a class="link-normal" href="<?php echo $product->get_permalink(); ?>">
<?php echo $product->get_image( 'woocommerce_thumbnail', array( 'class' => 'card-img-top' ) ) ?>
<div class="card-body">
<?php echo wc_get_rating_html( $product->get_average_rating(), $product->get_review_count() ) ?>
<h5><?php echo $product->get_name(); ?></h5>
<p><?php echo $product->get_price_html() ?></p>
<?php woocommerce_template_loop_add_to_cart(); ?>
</div>
</a>
</div>
<?php
}
}
// loop and display buy again.
// try to use the official woocommerce loop.
echo '</div>';
}
Copy this code into your file. For example: my-theme-wc-single-ajax-add-cart.js.
function myThemeWc_SingleProductAddToCart(thisObj) {
if (typeof($) === 'undefined') {
var $ = jQuery.noConflict();
}
var thisForm = thisObj.closest('form');
var button = thisForm.find('.button');
var formUrl = thisForm.attr('action');
var formMethod = thisForm.attr('method');
if (typeof(formMethod) === 'undefined' || formMethod == '') {
formMethod = 'POST';
}
var formData = new FormData(thisForm[0]);
formData.append(button.attr('name'), button.val());
button.removeClass('added');
button.addClass('loading');
myThemeWc_SingleProductCartAjaxTask = $.ajax({
url: formUrl,
method: formMethod,
data: formData,
cache: false,
contentType: false,
processData: false
})
.done(function(data, textStatus, jqXHR) {
$(document.body).trigger('wc_fragment_refresh');
$.when(myThemeWc_SingleProductCartAjaxTask)
.then(myThemeWc_SingleProductUpdateCartWidget)
.done(function() {
button.removeClass('loading');
button.addClass('added');
setTimeout(function() {
button.removeClass('added');
}, 2000);
});
})
.fail(function(jqXHR, textStatus, errorThrown) {
button.removeClass('loading');
})
.always(function(jqXHR, textStatus, errorThrown) {
$('.cart').off('submit');
myThemeWc_SingleProductListenAddToCart();
});
}// myThemeWc_SingleProductAddToCart
function myThemeWc_SingleProductListenAddToCart() {
if (typeof($) === 'undefined') {
var $ = jQuery.noConflict();
}
$('.cart').on('submit', function(e) {
e.preventDefault();
myThemeWc_SingleProductAddToCart($(this));
});
}// myThemeWc_SingleProductListenAddToCart
/**
* Update WooCommerce cart widget by called the trigger and listen to the event.
*
* #returns {undefined}
*/
function myThemeWc_SingleProductUpdateCartWidget() {
if (typeof($) === 'undefined') {
var $ = jQuery.noConflict();
}
var deferred = $.Deferred();
$(document.body).on('wc_fragments_refreshed', function() {
deferred.resolve();
});
return deferred.promise();
}// myThemeWc_SingleProductUpdateCartWidget
var myThemeWc_SingleProductCartAjaxTask;
// on page load --------------------------------------------
jQuery(function($) {
$(document.body).on('wc_fragments_refreshed', function() {
console.log('woocommerce event fired: wc_fragments_refreshed');
});
myThemeWc_SingleProductListenAddToCart();
});
You may need to replace function, variable prefix myThemeWc_ to what you want.
This code use the original WooCommerce single product page add to cart button but stop its functional and then use ajax instead by remain all the values in the form.
Then enqueue this js file.
add_action('wp_enqueue_scripts', 'mythemewc_enqueue_scripts');
function mythemewc_enqueue_scripts() {
if (class_exists('\\WooCommerce') && is_product()) {
wp_enqueue_script('mythemewc-single-product', trailingslashit(get_stylesheet_directory_uri()) . 'assets/js/my-theme-wc-single-ajax-add-cart.js', ['jquery'], false, true);
}
}
You may have to code your css button to make it show the loading, added icon.
Here is css.
.woocommerce #respond input#submit.added::after,
.woocommerce a.btn.added::after,
.woocommerce button.btn.added::after,
.woocommerce input.btn.added::after,
.woocommerce .single_add_to_cart_button.added::after {
font-family: WooCommerce;
content: '\e017';
margin-left: .53em;
vertical-align: bottom;
}
.woocommerce #respond input#submit.loading,
.woocommerce a.btn.loading,
.woocommerce button.btn.loading,
.woocommerce input.btn.loading,
.woocommerce .single_add_to_cart_button.loading {
opacity: .25;
padding-right: 2.618em;
position: relative;
}
.woocommerce #respond input#submit.loading::after,
.woocommerce a.btn.loading::after,
.woocommerce button.btn.loading::after,
.woocommerce input.btn.loading::after,
.woocommerce .single_add_to_cart_button.loading::after {
font-family: WooCommerce;
content: '\e01c';
vertical-align: top;
font-weight: 400;
position: absolute;
right: 1em;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
You can replicate the behavour of the archives button in your single products
add_action('wp_ajax_woocommerce_ajax_add_to_cart', 'woocommerce_ajax_add_to_cart');
add_action('wp_ajax_nopriv_woocommerce_ajax_add_to_cart', 'woocommerce_ajax_add_to_cart'); function woocommerce_ajax_add_to_cart() {
$product_id = apply_filters('woocommerce_add_to_cart_product_id', absint($_POST['product_id']));
$quantity = empty($_POST['quantity']) ? 1 : wc_stock_amount($_POST['quantity']);
$variation_id = absint($_POST['variation_id']);
$passed_validation = apply_filters('woocommerce_add_to_cart_validation', true, $product_id, $quantity);
$product_status = get_post_status($product_id);
if ($passed_validation && WC()->cart->add_to_cart($product_id, $quantity, $variation_id) && 'publish' === $product_status) {
do_action('woocommerce_ajax_added_to_cart', $product_id);
if ('yes' === get_option('woocommerce_cart_redirect_after_add')) {
wc_add_to_cart_message(array($product_id => $quantity), true);
}
WC_AJAX :: get_refreshed_fragments();
} else {
$data = array(
'error' => true,
'product_url' => apply_filters('woocommerce_cart_redirect_after_error', get_permalink($product_id), $product_id));
echo wp_send_json($data);
}
wp_die();
}
add_action('wp_ajax_woocommerce_ajax_add_to_cart', 'woocommerce_ajax_add_to_cart');
add_action('wp_ajax_nopriv_woocommerce_ajax_add_to_cart', 'woocommerce_ajax_add_to_cart');
function woocommerce_ajax_add_to_cart() {
$product_id = apply_filters('woocommerce_add_to_cart_product_id', absint($_POST['product_id']));
$quantity = empty($_POST['quantity']) ? 1 : wc_stock_amount($_POST['quantity']);
$variation_id = absint($_POST['variation_id']);
$passed_validation = apply_filters('woocommerce_add_to_cart_validation', true, $product_id, $quantity);
$product_status = get_post_status($product_id);
if ($passed_validation && WC()->cart->add_to_cart($product_id, $quantity, $variation_id) && 'publish' === $product_status) {
do_action('woocommerce_ajax_added_to_cart', $product_id);
if ('yes' === get_option('woocommerce_cart_redirect_after_add')) {
wc_add_to_cart_message(array($product_id => $quantity), true);
}
WC_AJAX :: get_refreshed_fragments();
} else {
$data = array(
'error' => true,
'product_url' => apply_filters('woocommerce_cart_redirect_after_error', get_permalink($product_id), $product_id));
echo wp_send_json($data);
}
wp_die();
}
you can see the full tutorial here
https://quadmenu.com/add-to-cart-with-woocommerce-and-ajax-step-by-step/
I used this plugin for the backend part https://wordpress.org/plugins/woo-ajax-add-to-cart/
I'm not using the product page, so I modified the script to work with any button:
(function($) {
$(document).on('click', '.btn', function(e) {
var $thisbutton = $(this);
try {
var href = $thisbutton.prop('href').split('?')[1];
if (href.indexOf('add-to-cart') === -1) return;
} catch (err) {
return;
}
e.preventDefault();
var product_id = href.split('=')[1];
var data = {
product_id: product_id
};
$(document.body).trigger('adding_to_cart', [$thisbutton, data]);
$.ajax({
type: 'post',
url: wc_add_to_cart_params.wc_ajax_url.replace(
'%%endpoint%%',
'add_to_cart'
),
data: data,
beforeSend: function(response) {
$thisbutton.removeClass('added').addClass('loading');
},
complete: function(response) {
$thisbutton.addClass('added').removeClass('loading');
},
success: function(response) {
if (response.error & response.product_url) {
window.location = response.product_url;
return;
} else {
$(document.body).trigger('added_to_cart', [
response.fragments,
response.cart_hash
]);
$('a[data-notification-link="cart-overview"]').click();
}
}
});
return false;
});
})(jQuery);
info: Tested with WooCommerce 2.4.10.
Hmm, well I did it in another way, used the woocommerce loop from add to cart (woocommerce/templates/loop/add-to-cart.php)
global $product;
echo apply_filters( 'woocommerce_loop_add_to_cart_link',
sprintf( '%s',
esc_url( $product->add_to_cart_url() ),
esc_attr( $product->id ),
esc_attr( $product->get_sku() ),
esc_attr( isset( $quantity ) ? $quantity : 1 ),
$product->is_purchasable() && $product->is_in_stock() ? 'add_to_cart_button' : '',
esc_attr( $product->product_type ),
esc_html( $product->add_to_cart_text() )
),
$product );
BUT the problem was that it was adding just 1 quantity, in fact, you can see in the code that is listed quantity : 1, so I had problems, until I bumped into this guys who saved me
ps. leaving the 1st part where it adds just 1 product for people who don't need more than 1 product in the basket, but I added a solution for those who need more than just 1 product added to the cart.
add-to-cart.js
jQuery( document ).on( 'click', '.product_type_simple', function() {
var post_id = jQuery(this).data('product_id');//store product id in post id variable
var qty = jQuery(this).data('quantity');//store quantity in qty variable
jQuery.ajax({
url : addtocart.ajax_url, //ajax object of localization
type : 'post', //post method to access data
data :
{
action : 'prefix_ajax_add_foobar', //action on prefix_ajax_add_foobar function
post_id : post_id,
quantity: qty
},
success : function(response){
jQuery('.site-header .quantity').html(response.qty);//get quantity
jQuery('.site-header .total').html(response.total);//get total
//loaderContainer.remove();
alert("Product Added successfully..");
}
});
return false;
});
To make ajax woocomerce work on another page you will need.
goes in functions.php
paste this:
remove_action ('woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30);
add_action ('woocommerce_single_product_summary', 'woocommerce_template_loop_add_to_cart', 30);
in footer.php in the end paste this:
<script>
$ ('body'). on ('add_to_cart', function () {
     // Callback -> product added
     // $ ('. popup'). show ();
});
</script>
For me working exelent. I think this is the simplest solution with Ajax.
+ Add to cart
I used Eh Jewel's answer but then added some custom JS for once the product was added to the cart. This completes the final AJAX process of being able to update the page however you want.
For completeness, here is the HTML code I used (same as Eh Jewel's):
Add to Cart
Then for the custom JS bit:
$(window).on('load', function() {
$('body').on( 'added_to_cart', function( added_to_cart, cart, cart_hash, button ){
// Put the functionality here. Debugging shows you what you have to work with:
console.log('added_to_cart object');
console.log(added_to_cart);
console.log('cart object');
console.log(cart);
console.log('cart_hash object');
console.log(cart_hash);
console.log('button object');
console.log(button);
});
});

Categories