Woocommerce ajax add to cart tutorial on single/archive pages

What is AJAX?

Ajax is a client-side script that communicates to and from a server/database without the need for the page to reload.

Ajax is fun and a great asset to a developer because it allows us to:
Update a web page without reloading the page
Send data to the server in the background

I will explain how to add AJAX add to cart on your Woocommerce site.

Below is a gif of what ajax add to cart does.

Enqueuing the Javascript

The first step is to add a javascript script to your site, to do this add the following to your functions.php

[php]
function bodycommerce_ajax_add_to_cart_script() {
wp_enqueue_script( 'bodycommerce-add-to-cart-ajax', get_stylesheet_directory() . '/js/add-to-cart-ajax.js', array('jquery'), '', true );
}
add_action( 'wp_enqueue_scripts', 'bodycommerce_ajax_add_to_cart_script',99 );
[/php]

After this create a new folder in your child theme called “js” and in that add a new javascript script called “add-to-cart-ajax.js”.

Javascript side of the AJAX add to cart

The main asset to ajax is that you dont need to reload the page to send data to the database, so the first step in the js creation is to prevent the page to reload.

[javascript]
jQuery( function( $ ) {

$( document ).on( ‘click’, ‘.single_add_to_cart_button’, function(e) {
e.preventDefault();

});
});
[/javascript]

The above code prevents the button to send the information to the database and reload the page.

So now I have disabled the ability to send information to the database, how do we add a product to the cart? Well, we use jQuery to gather information from the site.

The information we need are as follows:
Product ID
Quantity
Variation ID (if variable product)
Variation Item (if variable product)

So how do we get this? Well with a variable product it is quite straightforward as there are hidden inputs with all this information for example

[html]<input name="variation_id" class="variation_id" value="0" type="hidden">[/html]

would give the value for the Variation ID

So to get all the information we need for a variable product we use:

[javascript]
$variation_form = $( this ).closest( ‘.variations_form’ );
var product_id = $variation_form.find( ‘input[name=product_id]’ ).val();
var quantity = $variation_form.find( ‘input[name=quantity]’ ).val();
var var_id = $variation_form.find( ‘input[name=variation_id]’ ).val();
[/javascript]

Variation Item is a bit more complicated but will get there in the bulk code.

To get the information for a single product is not that easy as there are no hidden inputs to help us out 🙁 So i have created a hack that works just fine. What we are doing is creating the hidden inputs and using jquery to fill the values with the product ID and quantity as that all we need for a single product.

To do this create a new folder in your child theme called “woocommerce” in that folder copy the “content-single-product.php” file from the woocommerce plugin and paste it in this folder. This will now overwrite the default Woocommerce product page without causing issues when Woocommerce updates. Add the following html for the two hidden inputs.

[php]
<!–?php $id = $product—>get_id(); ?>
<input type="hidden" value="<?php echo $id ?>" class="product_id">
<input type="hidden" value="1" class="product_quantity">
[/php]

The above code will automatically add the product ID in as the value, but for the quantity we need to be a bit more clever as the customer might change the quantity, so how do we find this out? Well… jQuery to the rescue yet again.

[javascript]
$(".input-text.qty.text").bind(‘keyup mouseup’, function () {
var value = $(this).val();
$(".product_quantity").val(value)
});
[/javascript]

The above code looks for if the user changes the quantity and then updates the hidden quantity input we have created with the amount they choose.

Now we have our hidden values, how do we get this in and send it to the database?

I am not going to run through exactly what every line of code means on the full code snipet but the key part where it gathers the information – this is:

[javascript]
var data = {
action: ‘bodycommerce_ajax_add_to_cart_woo’,
product_id: product_id,
quantity: quantity,
variation_id: var_id,
variation: item
};
[/javascript]

As you can see it is getting the varibles we created earlier and adds them into the variable called “data”. The key part here to understand is the action ”bodycommerce_ajax_add_to_cart_woo’ – this basically calls a php function which I will go into more detail below.

The full javascript code you need to add is:

[javascript]
jQuery( function( $ ) {

$(".single_add_to_cart_button").addClass("ajax_add_to_cart");

$( ".post-type-archive-product" ).on( "click", ".quantity input", function() {
return false;
});

$( ".archive" ).on( "change input", ".quantity .qty", function() {
var add_to_cart_button = $( this ).parents( ".product" ).find( ".add_to_cart_button" );
// For AJAX add-to-cart actions
add_to_cart_button.data( "quantity", $( this ).val() );
// For non-AJAX add-to-cart actions
add_to_cart_button.attr( "href", "?add-to-cart=" + add_to_cart_button.attr( "data-product_id" ) + "&quantity=" + $( this ).val() );
});

$(".input-text.qty.text").bind(‘keyup mouseup’, function () {
var value = $(this).val();
$(".product_quantity").val(value)
});

if ( typeof wc_add_to_cart_params === ‘undefined’ )
return false;

$( document ).on( ‘click’, ‘.ajax_add_to_cart’, function(e) {
e.preventDefault();
var $thisbutton = $(this);
var $variation_form = $( this ).closest( ‘.variations_form’ );
var var_id = $variation_form.find( ‘input[name=variation_id]’ ).val();
$( ‘.ajaxerrors’ ).remove();
var item = {},
check = true;
variations = $variation_form.find( ‘select[name^=attribute]’ );
if ( !variations.length) {
variations = $variation_form.find( ‘[name^=attribute]:checked’ );
}
if ( !variations.length) {
variations = $variation_form.find( ‘input[name^=attribute]’ );
}
variations.each( function() {
var $this = $( this ),
attributeName = $this.attr( ‘name’ ),
attributevalue = $this.val(),
index,
attributeTaxName;
$this.removeClass( ‘error’ );
if ( attributevalue.length === 0 ) {
index = attributeName.lastIndexOf( ‘_’ );
attributeTaxName = attributeName.substring( index + 1 );
$this
.addClass( ‘required error’ )
.before( ‘<div class="ajaxerrors"><p>Please select ‘ + attributeTaxName + ‘</p></div>’ )
check = false;
} else {
item[attributeName] = attributevalue;
}
} );
if ( !check ) {
return false;
}

if ( $thisbutton.is( ‘.ajax_add_to_cart’ ) ) {
$thisbutton.removeClass( ‘added’ );
$thisbutton.addClass( ‘loading’ );
if ($( this ).parents(".variations_form")[0]){
var product_id = $variation_form.find(‘input[name=product_id]’).val();
var quantity = $variation_form.find( ‘input[name=quantity]’ ).val();
var data = {
action: ‘bodycommerce_ajax_add_to_cart_woo’,
product_id: product_id,
quantity: quantity,
variation_id: var_id,
variation: item
};
}
else {
var product_id = $(this).parent().find(".product_id").val();
var quantity = $(this).parent().find(".qty").val();
var data = {
action: ‘bodycommerce_ajax_add_to_cart_woo_single’,
product_id: product_id,
quantity: quantity
};
}

$( ‘body’ ).trigger( ‘adding_to_cart’, [ $thisbutton, data ] );
$.post( wc_add_to_cart_params.ajax_url, data, function( response ) {
if ( ! response )
return;
var this_page = window.location.toString();
this_page = this_page.replace( ‘add-to-cart’, ‘added-to-cart’ );
if ( response.error && response.product_url ) {
window.location = response.product_url;
return;
}
if ( wc_add_to_cart_params.cart_redirect_after_add === ‘yes’ ) {
window.location = wc_add_to_cart_params.cart_url;
return;
} else {
$thisbutton.removeClass( ‘loading’ );
var fragments = response.fragments;
var cart_hash = response.cart_hash;
if ( fragments ) {
$.each( fragments, function( key ) {
$( key ).addClass( ‘updating’ );
});
}
$( ‘.shop_table.cart, .updating, .cart_totals’ ).fadeTo( ‘400’, ‘0.6’ ).block({
message: null,
overlayCSS: {
opacity: 0.6
}
});
$thisbutton.addClass( ‘added’ );
if ( fragments ) {
$.each( fragments, function( key, value ) {
$( key ).replaceWith( value );
});
}
$( ‘.widget_shopping_cart, .updating’ ).stop( true ).css( ‘opacity’, ‘1’ ).unblock();
$( ‘.shop_table.cart’ ).load( this_page + ‘ .shop_table.cart:eq(0) > *’, function() {
$( ‘.shop_table.cart’ ).stop( true ).css( ‘opacity’, ‘1’ ).unblock();
$( document.body ).trigger( ‘cart_page_refreshed’ );
});
$( ‘.cart_totals’ ).load( this_page + ‘ .cart_totals:eq(0) > *’, function() {
$( ‘.cart_totals’ ).stop( true ).css( ‘opacity’, ‘1’ ).unblock();
});
}
});
return false;
} else {
return true;
}
});
});

[/javascript]

As you can see above we have two seperate functions being called depening on if it is a single or a variable product – so we need to add two functions.

PHP side of AJAX add to cart

Go back to your functions.php file and add the following (which will update the cart with the information recieved by the jQuery file)

[php]
// VARIATION CALLBACK
add_action( ‘wp_ajax_bodycommerce_ajax_add_to_cart_woo’, ‘bodycommerce_ajax_add_to_cart_woo_callback’ );
add_action( ‘wp_ajax_nopriv_bodycommerce_ajax_add_to_cart_woo’, ‘bodycommerce_ajax_add_to_cart_woo_callback’ );

function bodycommerce_ajax_add_to_cart_woo_callback() {

ob_start();

$product_id = apply_filters( ‘woocommerce_add_to_cart_product_id’, absint( $_POST[‘product_id’] ) );
$quantity = empty( $_POST[‘quantity’] ) ? 1 : apply_filters( ‘woocommerce_stock_amount’, $_POST[‘quantity’] );
// $product_quantity = $_POST[‘product_quantity’];
$variation_id = $_POST[‘variation_id’];
$variation = $_POST[‘variation’];

error_log("Variation Product", 0);
$passed_validation = apply_filters( ‘woocommerce_add_to_cart_validation’, true, $product_id, $quantity, $variation_id, $variation );

if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation ) ) {
do_action( ‘woocommerce_ajax_added_to_cart’, $product_id );
if ( get_option( ‘woocommerce_cart_redirect_after_add’ ) == ‘yes’ ) {
wc_add_to_cart_message( $product_id );
}

// Return fragments
WC_AJAX::get_refreshed_fragments();
} else {
// $this->json_headers(); // REMOVED AS WAS THROWING AN ERROR

// If there was an error adding to the cart, redirect to the product page to show any errors
$data = array(
‘error’ => true,
‘product_url’ => apply_filters( ‘woocommerce_cart_redirect_after_error’, get_permalink( $product_id ), $product_id )
);
echo json_encode( $data );
}

die();
}

add_action( ‘wp_ajax_bodycommerce_ajax_add_to_cart_woo_single’, ‘bodycommerce_ajax_add_to_cart_woo_single_callback’ );
add_action( ‘wp_ajax_nopriv_bodycommerce_ajax_add_to_cart_woo_single’, ‘bodycommerce_ajax_add_to_cart_woo_single_callback’ );
function bodycommerce_ajax_add_to_cart_woo_single_callback() {
ob_start();
$product_id = apply_filters( ‘woocommerce_add_to_cart_product_id’, absint( $_POST[‘product_id’] ) );
$quantity = empty( $_POST[‘quantity’] ) ? 1 : apply_filters( ‘woocommerce_stock_amount’, $_POST[‘quantity’] );
error_log("Simple Product", 0);
$passed_validation = apply_filters( ‘woocommerce_add_to_cart_validation’, true, $product_id, $quantity );

if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity ) ) {
do_action( ‘woocommerce_ajax_added_to_cart’, $product_id );
if ( get_option( ‘woocommerce_cart_redirect_after_add’ ) == ‘yes’ ) {
wc_add_to_cart_message( $product_id );
}

// Return fragments
WC_AJAX::get_refreshed_fragments();
} else {
$this->json_headers();

// If there was an error adding to the cart, redirect to the product page to show any errors
$data = array(
‘error’ => true,
‘product_url’ => apply_filters( ‘woocommerce_cart_redirect_after_error’, get_permalink( $product_id ), $product_id )
);
echo json_encode( $data );
}

die();
}
[/php]

Wrapping it up

If you have added it all correctly it will work well for you and your site will now have ajax add to cart.

If you not that code-savy or prefer using a plugin for this we have created a plugin called Divi BodyCommerce which does all this for you as well as many other changes such as customising your email templates and using a mini cart with your Divi website.

Try BodyCommerce for Free

We specilise in the Divi theme, however this code will work on all themes

Please give us a shout if you have any questions.

34 Comments

  1. Getting an error Parse error: syntax error, unexpected ‘&’ in

    on line:

    error_log("Variation Product", 0);

    Nobody else had that?

  2. I have a problem. Some products add double. I can’t find a solution to this rpboelm. I need help

    • Not sure – might be conflict with WooCommerce ajax add to cart. The code works for us

  3. Easy to do and it works like a charm! Thank you!

  4. Hello, I added everything you are talking about to my theme, but it doesn’t work…

    • Not sure, maybe there is JS conflict or something else. Sorry

  5. I don’t know if it’s just me or if perhaps everybody else encountering issues with your website. It appears like some of the written text in your content are running off the screen. Can somebody else please provide feedback and let me know if this is happening to them too? This could be a problem with my internet browser because I’ve had this happen before. Cheers

    • Thanks for the comment, there was an issue ages ago with this post but I sorted it.

      Where can you see the text going off the screen?

  6. I have implemented my website with this code, but there seems to be an error. The products are not added to the cart with the new wordpress update. Can help us?

    • What error are you getting?

      • no type of error appears, only that the load wheel continues infinitely without adding the product to the cart.

        • Ya I am not sure – if there are no errors then I am not sure. You may need to contact your host and ask for the error log file (or you can find it on your server) – this might tell you what the problem is.

          Not trying to sell our plugin but know it works with this so if you use Divi and can utilise the other features I would suggest using this as you know it will work.

          • I think the problem is that we do not know very well where to locate this section or that this section is not doing its job.

            $variation_form = $( this ).closest( ‘.variations_form’ );
            var product_id = $variation_form.find( ‘input[name=product_id]’ ).val();
            var quantity = $variation_form.find( ‘input[name=quantity]’ ).val();
            var var_id = $variation_form.find( ‘input[name=variation_id]’ ).val();

            Can you say where we should exactly locate it to know if we are implementing it correctly?

  7. It all works now with no issues, thanks!

    With my setup (https://www.mediatics-desa.com/desa/mako/delivery/) I’m getting a bad 404 request when I open a product in a modal and click the button. On variable products it works just fine, weirdly enough (like with the tee, “camiseta”).

    I know this is beyond the scope of this very helpful post but if it doesn’t take more than a minute would you be so kind to check it out? I think this code snippet would be even more useful if it worked with shortcodes.

    Thanks and sorry to bother you.

    PS: Sorry for not replying to other messages… it doesn’t let me, for some reason.

    • Hi Angel

      Taken a quick look and seems the issue is here:

      [javascript]
      var product_id = $(this).parent().find(".product_id").val();
      var quantity = $(this).parent().find(".qty").val();
      [/javascript]

      The issue is that it is looking for a input with the calss product_id and qty inside the parent div. This is not in the modal.

      Try adding the html inputs inside the add to cart template inside WooCommerce.

      Sorry I cannot be more helpful, this is beyond as you mention but this might help you along your way.

      Thanks
      Pete

  8. Sorry but replying isn’t working for me (the whole comments system is doing weird things). Anyway, it’s almost fixed now, only a couple of tings on lines 14 and 92.

    By the way, is there any way to make this work with the product shortcode? I’m opening the products in a modal using that but AJAX doesn’t work there (this is the main reason I’m looking to “ajaxify” WooCommerce).

    Thanks!

    • Thanks, Angel, fixed those syntax errors – sorry – it is not copying across properly.

      I am not sure how to get it to work with your setup, it should work as long as the HTML structure is similar which I would imagine it would be. Make sure the button has the class ajax_add_to_cart and you have the right HTML structure so that it can find the quantity and product ID.

      Thanks!

  9. Hi,

    So there’s some stuff polluted with & and other html encoded artifacts, plus, I’m getting a not defined in the console for $thisbutton (and it’s true, it’s not declared anywhere).

    Thanks!

    • Hi Angel, thanks for letting me know – I have sorted this.

      I realised I missed out the $thisbutton declaration – I have added it in the code now, please confirm 😀

      • Hey,

        there are still some formatting errors in your .js file.

        Do I just need to copy the .js file into my assets folder and add your php markup into my functions.php?

        Or is there anything else I am missing?

  10. Hi Divi engine, Hope you well and thank you for this post. I am using divi and tryng to avoid plugins. This is then exactly what I need to display an add to cart button under all shown products.
    QUestions:
    Is this posts still up to date?
    I have been all the process and it doesn’t seems to work for me. Any suggestion?
    Thanks in advance.
    ps: I am not a pro nor a coder, just a lot of interest 🙂

    • Hi André.

      I have taken a look and there are a few errors in the code due to the formatting. We are about to launch our new website this week and part of this is we are improving the way we show code snippets, I have updated the code there and is working.

      Are you able to wait for the new site this week?

      • Still formatting errors on this page. Please fix them. Thank you,

        • Hi Fabian, thanks for letting us know – can you check now?

    • Thanks for this. I am not sure how to get him to remove it. I have messaged him but don’t really know where I stand legally 😀

      Appreciate the support!
      Pete

  11. just a minor bug – the second function should called bodycommerce_ajax_add_to_cart_woo_single_callback and not bodycommerce_ajax_add_to_cart_woo_callback

    And there’s a problem if the product is out of stock

    • Thanks for this, I will check this out! I have changed the code a bit on the plugin so will double check this all.

      What do you mean there is a problem if the product is out of stock? Surely if it is out of stock you cant add it to cart?

      Thanks for the comment!

  12. Hi – excellent “plugin” i think, but I do believe there is a whole range of errors in the code and a major problem: when adding a variation to the cart it’s only adding the first variation from the dropdown, even if others are picked. As an example: if there are 2 variations, e.g. varying in color, called “red” and “blue” with price of $10 and $30, respectively, it will only add the first option ($10 “red”), even if blue is chosen.

    Furthermore I seem to have found following errors:

    When enqueuing script, you should use “.get_stylesheer_directory_uri() rather than simply get_stylesheet_directory() as this returns a 404 error (in my case at least).
    Further, when inserting the hidden inputs you’ve written “$id = $product-<get_id();" which returned an error in my case, and replacing the "-” solved it. Not sure if that’s correct though as i’m not good at php.

    In the js file I also got an error at line 36 since copying the JavaScript directly results in two line breaks, splitting it up after the “+ attributeTaxName + ‘” part.

    In the PHP part i also got an error as the functions have the same name (2 times “bodycommerce_ajax_add_to_cart_woo_callback”)

    • Thanks for the comment. I realised that I left out bits of code on here. I have updated it now.

      1) Variation not adding properly – I forgot to add the following:
      – the two variables in the js code below line 13 ( I have added line 14 + 15 now)
      – Getting the variation values from the post (I have added line 8 + 9) which looks for the variation ID and variation when they add it to cart (post)

      2) I have had this issue on localhost before – are you using localhost to test?

      3) I am not getting any errors – is it adding but producing an error or is it not working at all?

      You can see the code working on our demo site – https://demo-bodycommerce.diviengine.com/product/beach-wear

      Thanks again!

      • Hi,

        Can you post again the full javascript code? I mean the final version.

        • What do you mean, we have added this on the page – see under the title “The full javascript code you need to add is:”

          • I see,
            Thanks

Submit a Comment

Explore more from Divi Engine