WooCommerce: Allow adding multiple products to the cart via the add-to-cart query string

If you’re not familiar, WooCommerce offers a way to link to the checkout/cart page and automatically add a product to the cart (h/t Justin). You can create a link like so:

$product_id = 55;
$url = esc_url_raw( add_query_arg( 'add-to-cart', $product_id, wc_get_checkout_url() ) );

I recently (somewhat annoyingly) discovered that while that works fairly well, there was no way to do this for multiple products. So I’ve created a snippet that will allow you to do so by adding a comma-separated list of products ids:

function woocommerce_maybe_add_multiple_products_to_cart( $url = false ) {
    // Make sure WC is installed, and add-to-cart qauery arg exists, and contains at least one comma.
    if ( ! class_exists( 'WC_Form_Handler' ) || empty( $_REQUEST['add-to-cart'] ) || false === strpos( $_REQUEST['add-to-cart'], ',' ) ) {
        return;
    }

    // Remove WooCommerce's hook, as it's useless (doesn't handle multiple products).
    remove_action( 'wp_loaded', array( 'WC_Form_Handler', 'add_to_cart_action' ), 20 );

    $product_ids = explode( ',', $_REQUEST['add-to-cart'] );
    $count       = count( $product_ids );
    $number      = 0;

    foreach ( $product_ids as $id_and_quantity ) {
        // Check for quantities defined in curie notation (<product_id>:<product_quantity>)
        // https://dsgnwrks.pro/snippets/woocommerce-allow-adding-multiple-products-to-the-cart-via-the-add-to-cart-query-string/#comment-12236
        $id_and_quantity = explode( ':', $id_and_quantity );
        $product_id = $id_and_quantity[0];

        $_REQUEST['quantity'] = ! empty( $id_and_quantity[1] ) ? absint( $id_and_quantity[1] ) : 1;

        if ( ++$number === $count ) {
            // Ok, final item, let's send it back to woocommerce's add_to_cart_action method for handling.
            $_REQUEST['add-to-cart'] = $product_id;

            return WC_Form_Handler::add_to_cart_action( $url );
        }

        $product_id        = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $product_id ) );
        $was_added_to_cart = false;
        $adding_to_cart    = wc_get_product( $product_id );

        if ( ! $adding_to_cart ) {
            continue;
        }

        $add_to_cart_handler = apply_filters( 'woocommerce_add_to_cart_handler', $adding_to_cart->get_type(), $adding_to_cart );

        // Variable product handling
        if ( 'variable' === $add_to_cart_handler ) {
            woo_hack_invoke_private_method( 'WC_Form_Handler', 'add_to_cart_handler_variable', $product_id );

        // Grouped Products
        } elseif ( 'grouped' === $add_to_cart_handler ) {
            woo_hack_invoke_private_method( 'WC_Form_Handler', 'add_to_cart_handler_grouped', $product_id );

        // Custom Handler
        } elseif ( has_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler ) ){
            do_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler, $url );

        // Simple Products
        } else {
            woo_hack_invoke_private_method( 'WC_Form_Handler', 'add_to_cart_handler_simple', $product_id );
        }
    }
}

// Fire before the WC_Form_Handler::add_to_cart_action callback.
add_action( 'wp_loaded', 'woocommerce_maybe_add_multiple_products_to_cart', 15 );


/**
 * Invoke class private method
 *
 * @since   0.1.0
 *
 * @param   string $class_name
 * @param   string $methodName
 *
 * @return  mixed
 */
function woo_hack_invoke_private_method( $class_name, $methodName ) {
    if ( version_compare( phpversion(), '5.3', '<' ) ) {
        throw new Exception( 'PHP version does not support ReflectionClass::setAccessible()', __LINE__ );
    }

    $args = func_get_args();
    unset( $args[0], $args[1] );
    $reflection = new ReflectionClass( $class_name );
    $method = $reflection->getMethod( $methodName );
    $method->setAccessible( true );

    $args = array_merge( array( $class_name ), $args );
    return call_user_func_array( array( $method, 'invoke' ), $args );
}

Now you can add items to the cart via the following URLs:

// Multiple products, multiple quantities per product.
$product_ids = '63833:2,221916:4';
$add_to_cart_url = esc_url_raw( add_query_arg( 'add-to-cart', $product_ids, wc_get_checkout_url() ) );

// Multiple products (default quantity of 1)
$product_ids = '63833,221916';
$add_to_cart_url = esc_url_raw( add_query_arg( 'add-to-cart', $product_ids, wc_get_checkout_url() ) );

// Normal add-to-cart URL
$product_ids = '63833';
$add_to_cart_url = esc_url_raw( add_query_arg( 'add-to-cart', $product_ids, wc_get_checkout_url() ) );
UPDATE 04-21-17: I have updated the snippet to work with non-simple product types. (See the MARKDOWN_HASHd8969cc70401fc7e3d75a74096dbd31dMARKDOWN_HASH function). As indicated by the function name, this is a hack to get access to WooCommerce protected/private methods. Your milage may vary when using this snippet.
UPDATE 07-08-17: Thanks to Peder in the comments, I have updated the snippet to allow specifying different quantities per-product.

50 Comments on “WooCommerce: Allow adding multiple products to the cart via the add-to-cart query string

  1. Hi, Thanks for the code. Can you please share a code for variable products also? Thanks

  2. Like this: 3072&variation_id=3083&attribute_pa_yuzukolcusu=09&quantity=3,3072&variation_id=3082&attribute_pa_yuzukolcusu=11&quantity=3

  3. I didn’t get where to put this piece of code:
    $product_ids = implode( ‘,’, array( 1, 2, 55 ) );
    $url = esc_url_raw( add_query_arg( ‘add-to-cart’, $product_ids, wc_get_checkout_url() ) );
    Within the snippet?

    • That is highly contextual to your project. You would use it wherever you need to output a url that adds multiple products to the cart. (where 1, 2, 55 equals the product ids you want to be added)

  4. Ok, but… should I put that piece of code within your snippet? Outside?

  5. Thanks JT for your reply! I assumed it was so… An example, please?

  6. What good code, but how do I for the quantity of several products?

    • Hi Wladimick Diaz,
      Did you find a way to achieve this (multiple products with quantities for each)? I’m struggling with this :-/
      Thanks!!

      • I found a solution, see further down the thread.

  7. Thanks for updating the snippet to handle multiple variable products! Legendary!

    Have you considered making an Admin facing UI to allow creating these URLs by selecting products? This would make a nice plugin.

    Cheers,
    Jason

  8. Hi,

    When i use your code it adds two of each product i want to add to the cart.

    Can you explain why?

    • I already figured it out.

      I am using jQuery to create the add-to-cart link, and i was redirecting to the wrong page.

  9. Thanks! I needed to be able to add more than one item of each product.

    To fix this I added this code as the first thing after:
    foreach ( $product_ids as $product_id ) { //line 14

    $id_and_quantity = explode( ':', $product_id );
    $product_id = $id_and_quantity[0];
    if ( count( $id_and_quantity ) > 1 ) {
    $_REQUEST['quantity'] = $id_and_quantity[1];
    } else {
    $_REQUEST['quantity'] = 1;
    }

    Then I can add products with optional amounts using this structure (product_id:quantity):
    $product_ids = implode( ',', array( '1:2', '2:5', '55:3' ) );

    Note: The quantity is not needed. E.g. $product_ids = implode( ',', array( '1:2', '2', '55:3' ) ); will only add one item to the cart for product id 2 (second array element).

      • Hey there, this is really awesome. I’ve just built my own quote form in JS and was wondering how I could create a single URL to add in up to 3 products each with its own quantity.
        I have a question, I’m a bit of a novice at the moment and I’m learning through trial and error!!
        When I copied and pasted the code into my functions.php it does allow me to add multiple products with one URL but I don’t understand how you’re meant to specify the quantity for the product. Is it along the lines of ‘.com/?add-to-cart=77:3,103:6’ or ‘.com/?add-to-cart=77,103&quantity=3,6’?
        Neither works. Would love some help. I’ve opened a question on StackEx as well to try and get some help. The URL is stackexchange /questions/45224362/add-multiple-products-to-cart-woocommerce where I’ve linked this awesome post!!

    • Hi, I’m new to the scene and was wondering if I could get some help. The code works really well, but for some reason it will always add at least one of the products, even if i put the quantity to 0. So ?add-to-cart=2001:0,2018:0,2020,1 will still add one of each product to the cart. Is there a way to fix that?

  10. Pingback: Add multiple products to cart - WooCommerce - Das Web Developer

  11. This is great code, but I have a question, how can i add all the products in my wishlist (Im using YITH plugin for this) to the cart with one click of a button.

  12. Hi There,

    I would like to know if I can use your code to add multiple products to a cart from within a product page.

    I sell flowers online and am looking for a solution to the following:

    I have a product page where customers can pick the size of the bouquet. I would like to add a selection box ‘add a vase to cart’ so customers can add a vase along with the bouquet.

    When the customer pushes the add to cart button on the product page and the ‘add a vase’ checkbox is checked, two items are added to the cart.

    Would this be possible with your query string?

  13. Hi guys, before i have done and success using this code for my shop. Now I have trouble after updating woocommerce and change my theme.

    When i’m trying to run com/cart/?add-to-cart=70:3,80:2:90:1 the result is only “90:1” on my page cart. I need “70:3,80:2:90:1” added also on my page cart.

    Can someone help me with this? Thank you before.

  14. Hi,

    This is very helpful article. Can you please help me to add multiple variation product.

    Thanks

  15. Thanks a lot for this perfect article.
    Just a small question: Is it possible to use it with Woocommerce Subscription Plugin? To add multiple Variable Subscription Products? I’m going crazy with this problem…
    Thanks and cheers
    jonas

  16. Thanks for that script – very helpful.

    I had an error and needed to fix the woo_hack_invoke_private_method function.

    This is what I ended up with:


    /**
    * Invoke class private method
    *
    * @since 0.1.0
    *
    * @param string $class_name
    * @param string $methodName
    *
    * @return mixed
    */
    function woo_hack_invoke_private_method( $class_name, $methodName ) {
    if ( version_compare( phpversion(), '5.3', '<' ) ) {
    throw new Exception( 'PHP version does not support ReflectionClass::setAccessible()' );
    }
    $args = func_get_args();
    unset( $args[0], $args[1] );
    $reflection = new ReflectionClass( $class_name );
    $method = $reflection->getMethod( $methodName );
    $method->setAccessible( true );
    $args = array_merge( array( $reflection ), $args );
    return call_user_func_array( array( $method, 'invoke' ), $args );
    }

    I needed to change $class_name to $reflection in the last line before ‘return’.
    My error message said: ‘PHP Warning: ReflectionMethod::invoke() expects parameter 1 to be object, string given in …’

    After some research I thought the first parameter needs to be an real Class, not just the name of a class.
    That did the trick – but I don’t know much about the Reflection things. Please let me know if I have bad things worse …

    I am running on PHP 7.0

    Thanks a lot for share your code!

    • Works well! Though if anyone is copy/pasting the above please note this blog/site changes quotes to curly/special quotes int he code so you’ll have to change them back to code standard quotes (” ‘ etc).

      • If you hover over the snippet, there is a code copy button at the top right which should copy the snippet with proper quotes.

        • Oh, I realize you’re talking about the quote in the comment. Yah, that’s another matter. :)

  17. It looks like the woocommerce 3.2 update broke something so this snippet doesn’t work with adding multiple variable products now

    • the second products attribute doesn’t seem to pass in.

      I get the following error: “(product attribute) is a required field”

      The first variable product add correctly. Anything after that doesn’t.

  18. I’ve been following this thread since months.
    Not only it became awesome, not only I did not understand how to use it, but I also think that it should become a plugin. :)

    Now, is there anyone who can give an example of how to use it, please?

    Thanks!

  19. This code worked great. The only problem I have is that its listing the product prices including tax. I have WC set up to not include taxes per item, but to add it in at the bottom with shipping charges instead. I checked your code and don’t see where the tax inclusive parm is being set. Any ideas?

    Thanks for this excellent code.
    Roger

  20. I don’t think this codesnippet works any longer since woocommerce updated. Even though I add several variable products with quantity, only one product is added to the cart.

    I tested to change $class_name to $reflection as Sebastian Gärtner wrote earlier and then I got some parts to work. Now all the products I choose are added, but it seems like it’s an instance of the product. If I re-enter one of the products in the cart and add additional one of the same product, a new row will be created in the shopping cart. It should only increase the amount of that product.

    Does this make any sense?

    Anyone who has a solution to this?

    Thank you for a wonderful code.

  21. When I add click on the link url /? Add-to-cart = 1250,1260 or url /? Add-to-cart = 1250: 90,1260: 90 always double the amount. In the first case I get 2 as quantity ‘for each product and in the second case I get out 180.
    How could I solve.Thank you so much

  22. Hello.
    Thank you for your help.
    But is ti possible somehow to use your code with Variable Products and with its Attributes and Variations?

  23. Has anyone had any luck with this script NOT forwarding to another page? I would love to get this working via AJAX like a traditional “Add to Cart” button (staying on the same page without refreshing page). Yes, my AJAX setting is enabled.

  24. Great bit of code.

    One thing to note, if you’re building your URL’s from hand note that this script won’t work for a individual item added to cart if your string doesn’t and in an ‘,’ (comma).

    The PHP script explodes the string based on the comma, and if you’re just doing:
    /?add-to-cart=8:1
    it will not work, it instead has to be:
    /?add-to-cart=8:1,

  25. Great code!
    Can you maybe tell me a way, how to check the url for ?clear-cart also and to clear the cart, if the string is found, before adding the items?

    I have tried

    add_action( ‘init’, ‘woocommerce_clear_cart_url’ );
    function woocommerce_clear_cart_url() {
    if ( isset( $_GET[‘clear-cart’] ) ) {
    global $woocommerce;
    $woocommerce->cart->empty_cart();
    }
    }

    but it is not compatible with your code.

    Regards Dominik

  26. Same here, only one product added to cart.
    Changed the last part and now works

    // Simple Products
    } else {
    // woo_hack_invoke_private_method( 'WC_Form_Handler', 'add_to_cart_handler_simple', $product_id );
    WC()->cart->add_to_cart($product_id, $_REQUEST['quantity']);
    }

Comment

Fast, secure WordPress hosting is provided by WP Engine.
%d bloggers like this: