Adding multiple items to WooCommerce cart at once

前端 未结 6 1662
情话喂你
情话喂你 2020-12-05 05:47

I have 3 IDs of the different items that I want to add to my shopping cart. I could use https://url.com/shop/cart/?add-to-cart=3001 but when I want to add 3 ite

相关标签:
6条回答
  • 2020-12-05 06:25

    I took a different approach to this. Instead of killing the WC_Form_Handler, I use it! I have it run for each product. This seems simpler to me.

    You can use this alone, or also with the regular add-to-cart.

    http://example.com?add-more-to-cart=1000,10001,10002

    http://example.com?add-to-cart=1000&add-more-to-cart=10001,10002

    class add_more_to_cart {
    
        private $prevent_redirect = false; //used to prevent WC from redirecting if we have more to process
    
        function __construct() {
            if ( ! isset( $_REQUEST[ 'add-more-to-cart' ] ) ) return; //don't load if we don't have to
            $this->prevent_redirect = 'no'; //prevent WC from redirecting so we can process additional items
            add_action( 'wp_loaded', [ $this, 'add_more_to_cart' ], 21 ); //fire after WC does, so we just process extra ones
            add_action( 'pre_option_woocommerce_cart_redirect_after_add', [ $this, 'intercept_option' ], 9000 ); //intercept the WC option to force no redirect
        }
    
        function intercept_option() {
            return $this->prevent_redirect;
        }
    
        function add_more_to_cart() {
            $product_ids = explode( ',', $_REQUEST['add-more-to-cart'] );
            $count       = count( $product_ids );
            $number      = 0;
    
            foreach ( $product_ids as $product_id ) {
                if ( ++$number === $count ) $this->prevent_redirect = false; //this is the last one, so let WC redirect if it wants to.
                $_REQUEST['add-to-cart'] = $product_id; //set the next product id
                WC_Form_Handler::add_to_cart_action(); //let WC run its own code
            }
        }
    }
    new add_more_to_cart;
    
    0 讨论(0)
  • 2020-12-05 06:27

    Thanks to @thatgerhard and dsgnwrks
    I found a solution for support variations:

    function woocommerce_maybe_add_multiple_products_to_cart() {
      // 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_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 $product_id ) {
          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();
          }
    
          $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;
          }
    
          if ( $adding_to_cart->is_type( 'simple' ) ) {
    
              // quantity applies to all products atm
              $quantity          = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
              $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
    
              if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity ) ) {
                  wc_add_to_cart_message( array( $product_id => $quantity ), true );
              }
    
          } else {
    
              $variation_id       = empty( $_REQUEST['variation_id'] ) ? '' : absint( wp_unslash( $_REQUEST['variation_id'] ) );
              $quantity           = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( wp_unslash( $_REQUEST['quantity'] ) ); // WPCS: sanitization ok.
              $missing_attributes = array();
              $variations         = array();
              $adding_to_cart     = wc_get_product( $product_id );
    
              if ( ! $adding_to_cart ) {
                continue;
              }
    
              // If the $product_id was in fact a variation ID, update the variables.
              if ( $adding_to_cart->is_type( 'variation' ) ) {
                $variation_id   = $product_id;
                $product_id     = $adding_to_cart->get_parent_id();
                $adding_to_cart = wc_get_product( $product_id );
    
                if ( ! $adding_to_cart ) {
                  continue;
                }
              }
    
              // Gather posted attributes.
              $posted_attributes = array();
    
              foreach ( $adding_to_cart->get_attributes() as $attribute ) {
                if ( ! $attribute['is_variation'] ) {
                  continue;
                }
                $attribute_key = 'attribute_' . sanitize_title( $attribute['name'] );
    
                if ( isset( $_REQUEST[ $attribute_key ] ) ) {
                  if ( $attribute['is_taxonomy'] ) {
                    // Don't use wc_clean as it destroys sanitized characters.
                    $value = sanitize_title( wp_unslash( $_REQUEST[ $attribute_key ] ) );
                  } else {
                    $value = html_entity_decode( wc_clean( wp_unslash( $_REQUEST[ $attribute_key ] ) ), ENT_QUOTES, get_bloginfo( 'charset' ) ); // WPCS: sanitization ok.
                  }
    
                  $posted_attributes[ $attribute_key ] = $value;
                }
              }
    
              // If no variation ID is set, attempt to get a variation ID from posted attributes.
              if ( empty( $variation_id ) ) {
                $data_store   = WC_Data_Store::load( 'product' );
                $variation_id = $data_store->find_matching_product_variation( $adding_to_cart, $posted_attributes );
              }
    
              // Do we have a variation ID?
              if ( empty( $variation_id ) ) {
                throw new Exception( __( 'Please choose product options…', 'woocommerce' ) );
              }
    
              // Check the data we have is valid.
              $variation_data = wc_get_product_variation_attributes( $variation_id );
    
              foreach ( $adding_to_cart->get_attributes() as $attribute ) {
                if ( ! $attribute['is_variation'] ) {
                  continue;
                }
    
                // Get valid value from variation data.
                $attribute_key = 'attribute_' . sanitize_title( $attribute['name'] );
                $valid_value   = isset( $variation_data[ $attribute_key ] ) ? $variation_data[ $attribute_key ]: '';
    
                /**
                 * If the attribute value was posted, check if it's valid.
                 *
                 * If no attribute was posted, only error if the variation has an 'any' attribute which requires a value.
                 */
                if ( isset( $posted_attributes[ $attribute_key ] ) ) {
                  $value = $posted_attributes[ $attribute_key ];
    
                  // Allow if valid or show error.
                  if ( $valid_value === $value ) {
                    $variations[ $attribute_key ] = $value;
                  } elseif ( '' === $valid_value && in_array( $value, $attribute->get_slugs() ) ) {
                    // If valid values are empty, this is an 'any' variation so get all possible values.
                    $variations[ $attribute_key ] = $value;
                  } else {
                    throw new Exception( sprintf( __( 'Invalid value posted for %s', 'woocommerce' ), wc_attribute_label( $attribute['name'] ) ) );
                  }
                } elseif ( '' === $valid_value ) {
                  $missing_attributes[] = wc_attribute_label( $attribute['name'] );
                }
              }
              if ( ! empty( $missing_attributes ) ) {
                throw new Exception( sprintf( _n( '%s is a required field', '%s are required fields', count( $missing_attributes ), 'woocommerce' ), wc_format_list_of_items( $missing_attributes ) ) );
              }
    
            $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations );
    
            if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations ) ) {
              wc_add_to_cart_message( array( $product_id => $quantity ), true );
            }
          }
      }
    }
    add_action( 'wp_loaded', 'woocommerce_maybe_add_multiple_products_to_cart', 15 );
    
    0 讨论(0)
  • 2020-12-05 06:28

    Here I had forced $_REQUEST[ 'add-to-cart' ] to take the intended product id. Overwriting global variable doesn't sound good approach but it keeps DRY approach and also make all native function available to user.

    add_action( 'wp_loaded', 'add_multiple_to_cart_action', 20 );
    
    function add_multiple_to_cart_action() {
        if ( ! isset( $_REQUEST['multiple-item-to-cart'] ) || false === strpos( wp_unslash( $_REQUEST['multiple-item-to-cart'] ), '|' ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
                return;
            }
    
        wc_nocache_headers();
    
        $product_ids        = apply_filters( 'woocommerce_add_to_cart_product_id', wp_unslash( $_REQUEST['multiple-item-to-cart'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
        $product_ids = explode( '|', $product_ids );
        if( ! is_array( $product_ids ) ) return;
    
        $product_ids = array_map( 'absint', $product_ids );
        $was_added_to_cart = false;
        $last_product_id = end($product_ids);
        //stop re-direction
        add_filter( 'woocommerce_add_to_cart_redirect', '__return_false' );
        foreach ($product_ids as $index => $product_id ) {
            $product_id = absint(  $product_id  );
            if( empty( $product_id ) ) continue;
            $_REQUEST['add-to-cart'] = $product_id;
            if( $product_id === $last_product_id ) {
    
                add_filter( 'option_woocommerce_cart_redirect_after_add', function() { 
                    return 'yes'; 
                } );
            } else {
                add_filter( 'option_woocommerce_cart_redirect_after_add', function() { 
                    return 'no'; 
                } );
            }
    
            WC_Form_Handler::add_to_cart_action();
        }
    }
    

    Example:

    https://your-domain/cart?multiple-item-to-cart=68|69 Thanks

    0 讨论(0)
  • 2020-12-05 06:31

    In case anyone else comes by looking for this function like I did. I updated the top comment's code allowing it to work with woocommerce 3.5.3

        // adds support for multi add to cart for 3rd party cart plugin
    function woocommerce_maybe_add_multiple_products_to_cart() {
        // 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 $product_id ) {
            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();
            }
    
            $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;
            }
    
            // only works for simple atm
            if ( $adding_to_cart->is_type( 'simple' ) ) {
    
                // quantity applies to all products atm
                $quantity          = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
                $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
    
                if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity ) ) {
                    wc_add_to_cart_message( array( $product_id => $quantity ), true );
                }
    
            }
        }
    }
    add_action( 'wp_loaded', 'woocommerce_maybe_add_multiple_products_to_cart', 15 );
    
    0 讨论(0)
  • 2020-12-05 06:33

    I found the answer!

    Simply add the following script to your theme's functions.php:

    function woocommerce_maybe_add_multiple_products_to_cart() {
    // 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 $product_id ) {
        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();
        }
    
        $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->product_type, $adding_to_cart );
    
        /*
         * Sorry.. if you want non-simple products, you're on your own.
         *
         * Related: WooCommerce has set the following methods as private:
         * WC_Form_Handler::add_to_cart_handler_variable(),
         * WC_Form_Handler::add_to_cart_handler_grouped(),
         * WC_Form_Handler::add_to_cart_handler_simple()
         *
         * Why you gotta be like that WooCommerce?
         */
        if ( 'simple' !== $add_to_cart_handler ) {
            continue;
        }
    
        // For now, quantity applies to all products.. This could be changed easily enough, but I didn't need this feature.
        $quantity          = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
        $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
    
        if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity ) ) {
            wc_add_to_cart_message( array( $product_id => $quantity ), true );
        }
    }
    }
    
     // Fire before the WC_Form_Handler::add_to_cart_action callback.
     add_action( 'wp_loaded',        'woocommerce_maybe_add_multiple_products_to_cart', 15 );
    

    And then you can simply use http://shop.com/shop/cart/?add-to-cart=3001,3282 to add multiple items at once. Put a comma between different IDs.

    Thanks to dsgnwrks for the solution.

    0 讨论(0)
  • 2020-12-05 06:39

    Same answer as others, with support for multiple quantities.

    Example url: http://store.amitbend.com/cart/?add-to-cart=188,187,189&quantities=3,2,1

    
    function woocommerce_maybe_add_multiple_products_to_cart() {
    // 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'] );
    $quantities = explode( ',', $_REQUEST['quantities'] );
    
    $count       = count( $product_ids );
    $number      = 0;
    
    foreach ( $product_ids as $product_id ) {
        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();
        }
    
        $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->product_type, $adding_to_cart );
    
        /*
         * Sorry.. if you want non-simple products, you're on your own.
         *
         * Related: WooCommerce has set the following methods as private:
         * WC_Form_Handler::add_to_cart_handler_variable(),
         * WC_Form_Handler::add_to_cart_handler_grouped(),
         * WC_Form_Handler::add_to_cart_handler_simple()
         *
         * Why you gotta be like that WooCommerce?
         */
        if ( 'simple' !== $add_to_cart_handler ) {
            continue;
        }
    //         $_REQUEST['quantity'] = ! empty( $id_and_quantity[1] ) ? absint( $id_and_quantity[1] ) : 1;
    $_REQUEST['quantity'] = ! empty( $quantities[$number] ) ? absint( $quantities[$number] ) : 1;
        $quantity          = empty( $quantities[$number - 1] ) ? 1 : wc_stock_amount(  $quantities[$number - 1] );
    //     $quantity          = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
        $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
    
        if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity ) ) {
            wc_add_to_cart_message( array( $product_id => $quantity ), true );
        }
    }
    }
    
     // Fire before the WC_Form_Handler::add_to_cart_action callback.
     add_action( 'wp_loaded',        'woocommerce_maybe_add_multiple_products_to_cart', 15 );
    // remove "added to cart" notice
    add_filter( 'wc_add_to_cart_message_html', '__return_false' );
    
    
    0 讨论(0)
提交回复
热议问题