WooCommerce

AJAX Add to Cart on the Single Product Page

AJAX Add to Cart on the Single Product Page

The next post on improving your store that is being built using WooCommerce will be ajax add to cart button on the single product page.

A few weeks ago, one of my customers wrote me a help request in the support for my theme. He wanted to add on the product page, the ability to add products to the cart using AJAX. It was a good idea for new WooCommerce tutorial post.

First we need to add a click event to the add to cart button in the WooCommerce product page

$('.entry-summary form.cart').on('submit', function (e)
{
    e.preventDefault();

    $('.entry-summary').block({
        message: null,
        overlayCSS: {
            cursor: 'none'
        }
    });

    var product_url = window.location,
        form = $(this);

    $.post(product_url, form.serialize() + '&_wp_http_referer=' + product_url, function (result)
    {
        var cart_dropdown = $('.widget_shopping_cart', result)

        // update dropdown cart
        $('.widget_shopping_cart').replaceWith(cart_dropdown);

        // update fragments
        $.ajax($warp_fragment_refresh);

        $('.entry-summary').unblock();

    });
});

To avoid an errors with refreshing the card fragment, will be better to create a new function for this.


// Ajax add to cart on the product page
var $warp_fragment_refresh = {
    url: wc_cart_fragments_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'get_refreshed_fragments' ),
    type: 'POST',
    success: function( data ) {
        if ( data && data.fragments ) {

            $.each( data.fragments, function( key, value ) {
                $( key ).replaceWith( value );
            });

            $( document.body ).trigger( 'wc_fragments_refreshed' );
        }
    }
};

It should be something like this:


// Ajax add to cart on the product page
var $warp_fragment_refresh = {
    url: wc_cart_fragments_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'get_refreshed_fragments' ),
    type: 'POST',
    success: function( data ) {
        if ( data && data.fragments ) {

            $.each( data.fragments, function( key, value ) {
                $( key ).replaceWith( value );
            });

            $( document.body ).trigger( 'wc_fragments_refreshed' );
        }
    }
};

$('.entry-summary form.cart').on('submit', function (e)
{
    e.preventDefault();

    $('.entry-summary').block({
        message: null,
        overlayCSS: {
            cursor: 'none'
        }
    });

    var product_url = window.location,
        form = $(this);

    $.post(product_url, form.serialize() + '&_wp_http_referer=' + product_url, function (result)
    {
        var cart_dropdown = $('.widget_shopping_cart', result)

        // update dropdown cart
        $('.widget_shopping_cart').replaceWith(cart_dropdown);

        // update fragments
        $.ajax($warp_fragment_refresh);

        $('.entry-summary').unblock();

    });
});

Next, we need to change the template of the add to cart button for simple products

Please copy the template file ( plugins/woocommerce/templates/single-product/add-to-cart/simple.php ) into your theme ( themes/your theme name/woocommerce/single-product/add-to-cart/simple.php ) and replace the line:


<button type="submit" name="add-to-cart" value="<?php echo esc_attr( $product->get_id() ); ?>" class="single_add_to_cart_button button alt"><?php echo esc_html( $product->single_add_to_cart_text() ); ?></button>

with this line:


<input type="hidden" name="add-to-cart" value="<?php echo esc_attr( $product->get_id() ); ?>" />

<button type="submit" class="single_add_to_cart_button button alt"><?php echo esc_html( $product->single_add_to_cart_text() ); ?></button>
For grouped and variable products, we don’t need to do it. I meant that you donโ€™t need to edit the add-to-cart template file for grouped and variable products. Everything will work without additional code.

Do you want to see how it works?

Demo

Comments (51)

  • Avatar

    Anil

    |

    Hi,

    Woocommerce single product page add to cart button code is good and ajax proper call in my localsite but one issue in ajax function. Successfully Product added to cart and then after woocommerce mesage not display. Please immediately solved my issue.

    Thanks

    Reply

    • Avatar

      Alex Podolyan

      |

      Hello,

      Just replace this code snippet

      
      $('.entry-summary form.cart').on('submit', function (e)
      {
          e.preventDefault();
      
          $('.entry-summary').block({
              message: null,
              overlayCSS: {
                  cursor: 'none'
              }
          });
      
          var product_url = window.location,
              form = $(this);
      
          $.post(product_url, form.serialize() + '&_wp_http_referer=' + product_url, function (result)
          {
              var cart_dropdown = $('.widget_shopping_cart', result),
                  woocommerce_message = $('.woocommerce-message', result);
      
              // update dropdown cart
              $('.widget_shopping_cart').replaceWith(cart_dropdown);
      
              // Show message
              $('.type-product').eq(0).before(woocommerce_message);
      
              // update fragments
              $.ajax($warp_fragment_refresh);
      
              $('.entry-summary').unblock();
      
          });
      });
      

      Reply

      • Avatar

        Anil

        |

        Hi alexnet,
        Thank you very much for your help. The code you gave worked perfectly as I wanted.
        Thanks againโ€ฆ

        Reply

  • Avatar

    dinesh

    |

    great article and code working fine .. ๐Ÿ™‚

    Reply

  • Avatar

    irv

    |

    Hey you mentioned that “For grouped and variable products, we donโ€™t need to do it”, what do you mean by that?

    is there additional codes we need to add to achieve this effect for variable products?

    Reply

    • Avatar

      Alex Podolyan

      |

      I meant that you don’t need to edit the add-to-cart template file for variable products. Everything will work without additional code.

      Reply

  • Avatar

    Fabio

    |

    Nice tutorial, thanks!

    Reply

  • Avatar

    Karthick K

    |

    In which file we have to add all these snippets

    Reply

    • Avatar

      Alex Podolyan

      |

      Hello,

      If your theme has a field for custom JS code, use it. You can also add this code to the main JS file of your theme via FTP.

      Best, Elartica Team

      Reply

  • Avatar

    Denis

    |

    Alexs you speak Russian?

    Reply

    • Avatar

      Alex Podolyan

      |

      Hello Denis,
      Yes, I speak Russian. If you have any questions please write to this e-mail elartica.hub@gmail.com
      Best Regards, Elartica Team

      Reply

  • Avatar

    Russell

    |

    I tried your code, and I’m getting an error in my console: TypeError: $ is not a function – Where have I gone wrong? I pasted your code into a JS snippets plugin for WordPress. Here’s my dev site: http://p1l3str3d3t.denflyvendetallerken.no

    Reply

    • Avatar

      Russell

      |

      Okay, I moved the js from the footer to the header, and now I get the error: ReferenceError: wc_cart_fragments_params is not defined

      Reply

    • Avatar

      Alex Podolyan

      |

      Hello Russell,
      You need to read how to use jQuery correctly ๐Ÿ™‚

      jQuery(function($){
      /*insert my code*/
      });

      Reply

    • Avatar

      Alex Podolyan

      |

      And what about wc_cart_fragments_params…
      First you need to add the code to update the cart fragments in the functions.php file.
      Here is an example of how I did it.

      
      // Ajax update cart info
      add_filter( 'woocommerce_add_to_cart_fragments', function($fragments)
      {
          $fragments['.tm_cart_widget .tm_cart_label .cart_ajax_data .total_products'] = '' . WC()->cart->get_cart_contents_count() . '';
          $fragments['.tm_cart_widget .tm_cart_label .cart_ajax_data .subtotal'] = '' . WC()->cart->get_cart_subtotal() . '';
          return $fragments;
      });
      

      Reply

  • Avatar

    Stoil Kostadinov

    |

    Thank you for your good article. I have just tried the code with latest WordPress version (4.9.5) and Woocommerce version (3.3.4) as of this moment and the code seems to be working fine. In my case I had to do some other modifications because I am using this for a Product quick view custom functionality and not for the single product page but still your snippet works just fine.

    Keep up the good work!

    Reply

    • Avatar

      Alex Podolyan

      |

      Thank you so much for your kind words.

      Reply

  • Avatar

    Jason

    |

    Alex, nice write-up. I tried to use the code on a client site where I’m using WooCommerce Product Addons. In this case, its tickets for adults and children. When I view my mini cart (also Ajax) the quantity of tickets is correct, but not the price.

    Any suggestions?

    Thank you again, I will be using this code in the future.

    Reply

    • Avatar

      Alex Podolyan

      |

      Thanks! ๐Ÿ™‚

      Please, read this post, maybe one of your extensions that you use on the site changes the cart meta data (I mean the price)

      Reply

      • Avatar

        Jason

        |

        Alex, my apologies. I am stupid. I was using the wrong product addon type. I used custom field “number” instead of “additional price multiplier.” It works great. A few CSS issues to work out, and I will be implementing this solution on my current project.

        Thank you very much.

        PS – It is worth noting that your solution DOES work with product addons, and is the only one I have found which does. Thank you again.
        Jason

        Reply

        • Avatar

          Alex Podolyan

          |

          Well, I’m glad I was helpful.

          Reply

  • Avatar

    Ilchy

    |

    Great article, help solve my issue. Latest version of WP and WOO, with twentysixteen theme. Howver, I have to change your function to from this:

    $.post(product_url, form.serialize() + '&_wp_http_referer=' + product_url, function (result)

    TO

    $.post(product_url + '?' + form.serialize() + '&_wp_http_referer=' + product_url, function (result)

    Added the “?” part Looks like it’s working now, keep it up!

    Reply

  • Avatar

    Ilchy

    |

    Spoke too soon. Just trying to get it to work with WP twentysixteen theme – fresh installs of WOO and WP. And I just can’t get it to update the products ๐Ÿ™ Any ideas?

    Reply

    • Avatar

      Alex Podolyan

      |

      Do you mean that adding to the cart works well but the products in the mini cart widget aren’t updated? I didn’t quite understand your question

      Reply

  • Avatar

    Mayur

    |

    Hi add to cart ajax is working on single page but it is not updating mini cart
    please assist in this

    Reply

    • Avatar

      Alex Podolyan

      |

      Hello,

      If you use custom mini cart widget, you need to add cart fragments for updates using ajax. Here’s how I did it in my themes.

      // Ajax update cart info
      add_filter( 'woocommerce_add_to_cart_fragments', function($fragments)
      {
          $fragments['.tm_cart_widget .tm_cart_label .cart_ajax_data .total_products'] = '' . WC()->cart->get_cart_contents_count() . '';
          $fragments['.tm_cart_widget .tm_cart_label .cart_ajax_data .subtotal'] = '' . WC()->cart->get_cart_subtotal() . '';
          return $fragments;
      });
      

      Reply

  • Avatar

    Deepa

    |

    I want to add ajax add to cart button on individual product page. I have gone through your code and add it into my theme but nothing happens. Could you please guide where to add your code as i am helpless and any help would be appreciated.

    Reply

    • Avatar

      Alex Podolyan

      |

      Hello Deepa,
      Can you send me link to the page, FTP and admin access on the my e-mail elartica.hub@gmail.com
      I’ll try to help you do this.
      Best, Alex

      Reply

  • Avatar

    Mityay

    |

    Hello, thanks for the article. Help me with woocommerce error message, how it get, please

    Reply

    • Avatar

      Alex Podolyan

      |

      Hello,
      Do you mean the message that the product have been added to the cart?

      Reply

  • Avatar

    Liam

    |

    You don’t need to modify the add to cart template (PHP) if you make this the javascript

    $('.single_add_to_cart_button').on('click', function (e)
            {
                    e.preventDefault();
                    var button = $(e.target);
                    var result = button.parents('form').serialize()
                    + '&'
                    + encodeURI(button.attr('name'))
                    + '='
                    + encodeURI(button.attr('value'))
                    ;
    
                    $('.entry-summary').block({
                            message: null,
                            overlayCSS: {
                            cursor: 'none'
                            }
                    });
    
                    var product_url = window.location.href.replace("?"+window.location.search,""),
                            form = $(this);
    
                    $.post(form.attr('action'), result + '&_wp_http_referer=' + form.attr('action'), function (result)
                    {
                            var cart_dropdown = $('.widget_shopping_cart', result)
    
                            // update dropdown cart
                            $('.widget_shopping_cart').replaceWith(cart_dropdown);
    
                            // update fragments
                            $.ajax($warp_fragment_refresh);
    
                            $('.entry-summary').unblock();
    
                    })
    
            });
    

    It adds the name and value of the submit button to the request payload which makes it work without changing the template file.

    Reply

    • Avatar

      Alex Podolyan

      |

      Thank you, your solution works fine for me. I optimized your code a little.

      $('.single_add_to_cart_button').on('click', function (e)
      {
          e.preventDefault();
      
          $('.entry-summary').block({
              message: null,
              overlayCSS: {
                  cursor: 'none'
              }
          });
      
          var form = $(this),
              button = $(e.target),
              request = form.serialize() + '&' + encodeURI(button.attr('name')) + '=' + encodeURI(button.attr('value'));
      
          $.post(form.attr('action'), request + '&_wp_http_referer=' + form.attr('action'), function (result)
          {
              var cart_dropdown = $('.widget_shopping_cart', result)
      
              // update dropdown cart
              $('.widget_shopping_cart').replaceWith(cart_dropdown);
      
              // update fragments
              $.ajax($warp_fragment_refresh);
      
              $('.entry-summary').unblock();
      
          })
      
      });
      

      Reply

  • Avatar

    Guntur

    |

    i couldnt find where to input / edit this code. any help please? thanks

    Reply

    • Avatar

      Alex Podolyan

      |

      Hello,

      This JS code you can add to the main JS file of your theme. If you use Divi, you can add this code in the custom JS code field on the Divi settings page.
      Depending on what framework you use it can be done in different ways.

      Reply

  • Avatar

    Pinank shah

    |

    Hi,
    I inserted the code in the Footer Javascript Code Section. But it still ain’t working. Can you pls. help. The product type is Grouped. Thank you in anticipation

    Reply

    • Avatar

      Alex Podolyan

      |

      If you want all jQuery methods to work correctly, you need to add their inside a document ready event or function. You can find more information on this page https://www.w3schools.com/jquery/jquery_syntax.asp but I like to do something like that

      jQuery(function($) {
      insert my code here
      });

      Reply

  • Avatar

    Alexandros Skafas

    |

    Hey Alex,

    I am trying to make it work on my theme but i cant is it possible to give me a hand?

    Reply

    • Avatar

      Alex Podolyan

      |

      Hi,

      Can you send me a link to the site or test page and FTP access on the my e-mail elartica.hub@gmail.com
      Iโ€™ll try to help you.

      Best, Alex

      Reply

  • Avatar

    Michael Chamberlain

    |

    Scratch that request, of course …deep soul Ha!

    Reply

    • Avatar

      Alex Podolyan

      |

      This is the premium WordPress theme that we sell on themeforest. I’m very glad that you like.

      Reply

  • Avatar

    Pavel

    |

    Thank you very much for this easy-to-go article. It is simple and very helpfull!

    Reply

    • Avatar

      Alex Podolyan

      |

      Thank you for the nice words. I’m always glad to help

      Reply

  • Avatar

    Subraa

    |

    Great information!!
    I have use this code in my website and it is working fine without any error.

    Reply

  • Avatar

    Charidimos Tzedakis

    |

    The code works perfectly! Thanks a lot for posting this valuable help! ๐Ÿ™‚

    Reply

  • Avatar

    Samuel Bassah

    |

    That’s an amazing write-up and the codes you have there. It works for me on a single page. Thanks. However, I want to know if it’s possible to edit the javascript to also allow the same feature to work on the archive page. Enabling ajax add to cart on the archive page with custom add to cart button. Below is my code for the custom button. Can you help with that please?

    `/**
    * Override loop template and show quantities next to add to cart buttons
    */
    add_filter( ‘woocommerce_loop_add_to_cart_link’, ‘quantity_inputs_for_woocommerce_loop_add_to_cart_link’, 10, 2 );
    function quantity_inputs_for_woocommerce_loop_add_to_cart_link( $html, $product ) {
    if ( $product && $product->is_type( ‘simple’ ) && $product->is_purchasable() && $product->is_in_stock() && ! $product->is_sold_individually() ) {
    $html = ‘add_to_cart_url() ) . ‘” class=”cart” method=”post” enctype=”multipart/form-data”>’;
    $html .= woocommerce_quantity_input( array(), $product, false );
    $html .= ‘get_id() ).'” />’;

    $html .= ” . esc_html( $product->add_to_cart_text() ) . ”;
    $html .= ”;
    }
    return $html;
    }`

    Reply

    • Avatar

      Alex Podolyan

      |

      Hi Samuel,

      Sorry for the late reply.
      I have another solution for this task ๐Ÿ™‚

      If you want to add a quantity field on the products list pages, that’s what I did in your place.

      
      // add quantity field before add to cart button
      add_action( 'woocommerce_after_shop_loop_item', function()
      {
          global $product;
      
          if( $product->is_type( 'simple' ) && $product->is_purchasable() && $product->is_in_stock() && ! $product->is_sold_individually() ) :
              woocommerce_quantity_input( array(
                  'input_name'  => 'quantity',
                  'input_value' => apply_filters( 'woocommerce_quantity_input_min', 1, $product ),
                  'min_value'   => apply_filters( 'woocommerce_quantity_input_min', 1, $product ),
                  'max_value'   => apply_filters( 'woocommerce_quantity_input_max', $product->get_max_purchase_quantity(), $product ),
              ) );
          endif;
      },9 );
      

      And after this add the JS code for changing the quantity parameter on the add to the cart button. It looks like this to me, but you can have other selectors, so be vigilant.

      
      // Change quantity
      var change_quantity = function(qty_operator, qty_object)
      {
          var step = parseInt(qty_object.attr('step'), 10),
              max = parseInt(qty_object.attr('max'), 10),
              Qtt = 1;
      
          if(isNaN(step)){ step = 1; }
      
          if(isNaN(max)){ max = 100000; }
      
          if(qty_operator == "plus")
          {
              Qtt = parseInt(qty_object.val(), 10);
              if (!isNaN(Qtt) && Qtt < max) {
                  qty_object.val(Qtt + step);
              }
          }
      
          if(qty_operator == "minus")
          {
              Qtt = parseInt(qty_object.val(), 10);
              if (!isNaN(Qtt) && Qtt > step)
              {
                  qty_object.val(Qtt - step);
              } else qty_object.val(step);
          }
      
          if(qty_operator == "blur")
          {
              Qtt = parseInt(qty_object.val(), 10);
              if (!isNaN(Qtt) && Qtt > max)
              {
                  qty_object.val(max);
              }
          }
      
          if( qty_object.closest('ul.products').length )
          {
              qty_object.closest('li.product').find('.ajax_add_to_cart').attr('data-quantity',  qty_object.val() );
          }
      
          $( 'form.woocommerce-cart-form button[name="update_cart"]' ).prop( 'disabled', false );
      };
      
      $(document).on('click', '.quantity .plus', function()
      {
          change_quantity('plus', $(this).parent().find('.qty'));
      });
      
      $(document).on('click', '.quantity .minus', function()
      {
          change_quantity('minus', $(this).parent().find('.qty'));
      });
      
      $(document).on('blur', '.quantity .qty', function()
      {
          change_quantity('blur', $(this));
      });
      
      $(document).on('change keyup', 'ul.products .quantity .qty', function()
      {
          change_quantity('blur', $(this));
      });
      

      Reply

  • Avatar

    Peter

    |

    Hi Alex,

    excellent tutorial and it worked perfect, it was what I was looking for.

    I’m just asking a question, I would like this solution to work in the pop up of the quick view. What changes should I make?

    a big hug!

    Reply

    • Avatar

      Alex Podolyan

      |

      Hello Peter,

      If the add to cart form in the modal window has a parent with a class ‘.entry-summary’, then everything should work. So, you need to check all the parent elements of the add to cart form in the modal window, one of them must have this class ‘.entry-summary’

      Best Regards, Alex

      Reply

Leave a comment

Subscribe to our Newsletter

Something BIG is coming, you'll be the first to know about it.