2

In Woocommerce, when I add a bundled product A I want to remove products B, C, D (single products that are already inside that bundle) and if product A (bundle) is in the cart, do not allow to add B, C or D products.

The answer Woocomerce Remove a specific cart items when adding to cart another specific items is very close of what I would like.

How can I do it backwards?

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399

2 Answers2

2

For the first condition you can indeed use the woocommerce_add_to_cart hook, for the 2nd condition you better use the woocommerce_add_to_cart_validation hook.

So we apply both conditions together and we get

function filter_woocommerce_add_to_cart_validation( $passed, $product_id, $quantity, $variation_id = null, $variations = null ) {
    // Set ID's
    $product_a = 30;
    $product_b_c_d = array ( 813, 815, 817 );
    
    // Get current product id
    $product_id = $variation_id > 0 ? $variation_id : $product_id;
    
    // Product A is added
    if ( $product_a == $product_id ) {
        // Loop trough cart items
        foreach( WC()->cart->get_cart() as $key => $item ) {
            // Product ID is in array
            if ( in_array( $item['product_id'], $product_b_c_d ) ) {
                // Remove cart item(s)
                WC()->cart->remove_cart_item( $key );
            }       
        }
        
        // Optionaly displaying a notice
        wc_add_notice( __( 'Product A is added, Product B, C or D has been removed from cart.', 'woocommperce' ), 'notice' );
    }
    // Product B, C or D is added
    elseif ( in_array( $product_id, $product_b_c_d ) ) {
        // Generate card id
        $product_cart_id = WC()->cart->generate_cart_id( $product_a );
        
        // Check if product A in the cart
        $item_key = WC()->cart->find_product_in_cart( $product_cart_id );
        
        // if item_key true
        if ( $item_key ) {
            // Optionaly displaying a notice
            wc_add_notice( __( 'Product A is in cart, Product B, C or D are not allowed', 'woocommerce' ), 'error' );
            $passed = false;
        }

    }

    // Return
    return $passed;
}
add_filter( 'woocommerce_add_to_cart_validation', 'filter_woocommerce_add_to_cart_validation', 10, 5 );
7uc1f3r
  • 28,449
  • 17
  • 32
  • 50
  • If I have B C D in the cart it removes them and adds A (bundle) and then it works but if I have A (bundle) in the cart and I add B C D it doesn't work because it adds them to the cart although they are already in the bundle. why does it do this? (I'm using the official woocommerce product bundle plugin) – Simone Gatti Aug 04 '20 at 05:46
2

For a specific bundled product, the code below will:

  • remove any individual child products when bundle product is added to cart
  • avoid individual child products to be added to cart when the bundle product is already in cart.

So one hooked function for each case, will be a lighter process:

// When the bunddle product is added to cart remove single components from cart
add_action( 'woocommerce_add_to_cart', 'on_bundled_product_added_to_cart', 10, 4 );
function on_bundled_product_added_to_cart( $cart_item_key, $product_id, $quantity, $variation_id ) {

    // SETTINGS
    $bundled_product_id = 83; // Set HERE your bundled product ID
    $item_ids_to_remove = array(37, 53, 31); // Set HERE the  product ID(s) to remove(s)

    $removed_items = 0; // Initializing

    // When the bundled product is added to cart
    if( $bundled_product_id == $product_id ) {
        // Loop through cart items
        foreach( WC()->cart->get_cart() as $item_key => $cart_item ){
            // Get the cart item keys of the items to be removed
            if( array_intersect( array($cart_item['product_id'], $cart_item['variation_id']), $item_ids_to_remove ) ) {
                WC()->cart->remove_cart_item($item_key);
                $removed_items++;
            }
        }
    }

    // Optionaly displaying a notice for the removed items
    if( ! empty($removed_item_names) ){
        wc_add_notice( sprintf( __( 'Some products have been removed from cart as they are already bundled in your cart', 'woocommerce' ), $items_text ), 'notice' );
    }
}

// Add to cart validation for bundled components
add_filter( 'woocommerce_add_to_cart_validation', 'check_cart_items_for_bundle_product', 9999, 4 );
function check_cart_items_for_bundle_product( $passed, $product_id, $quantity, $variation_id = 0 ) {
    // SETTINGS
    $bundled_product_id = 83; // Set HERE your bundled product ID
    $bundled_items_ids  = array(37, 53, 31); // Set HERE the bundled items ID(s) from the bundled product
    $bundled_in_cart = false;

    if( ! WC()->cart->is_empty() ) {
        // Loop through cart items
        foreach( WC()->cart->get_cart() as $cart_item ){
            // check for bundled product
            if( $bundled_product_id == $cart_item['product_id'] ) {
                $bundled_in_cart = true;
                break;
            }
        }
        if( $bundled_in_cart && array_intersect(array($product_id, $variation_id), $bundled_items_ids) ) {
            // Add a custom notice
            wc_add_notice( __( 'This product is already a component of the bundled product in your cart', 'woocommerce' ), 'error' );
            return false;
        }
    }
    return $passed;
}

Code goes in functions.php file of your active child theme (or active theme). Tested and works.


The message error when trying to add to cart a component of a bundled product when it's in cart already:

enter image description here


The message when components of a bundled product are in cart and they are removed when adding the parent bundled product (in cart page):

enter image description here

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • Thank you! works well! There is only one problem: If the bundle (A) is already in the cart and I try to add B, C or D it reloads the page and displays nothing. Is there a way not to reload the page if the product is already in the cart as a bundle? Or more simply force the redirect at checkout and show "the error" ('This product is already a component of the bundled product in your cart)? If I do the opposite and add B, C or D to the cart and then add A (bundle) it works correctly because it adds it to the cart without reloading the page Thank you very much – Simone Gatti Jul 27 '20 at 15:10
  • 1
    @SimoneGatti I have updated my code lightly as there was a mistake. I have added some screenshots. Try it again. – LoicTheAztec Jul 27 '20 at 15:34
  • With "return false" when I have the bundle (A) in the cart and I add the single products (B, C, D), the page reloads. How can I avoid B C D products (if the bundle is in the cart) without reloading the page? If it is not possible, it would be enough for me to be able to send directly to the checkout rather than reloading the same page that is a bit annoying – Simone Gatti Aug 03 '20 at 17:41
  • Sorry I was trying to solve it for this reason I didn't answer anymore. I didn't want to disturb you unnecessarily. Today I decided to answer to solve your code so that it could also help other people. I apologize for disturbing you. Thanks anyway for the help! – Simone Gatti Aug 03 '20 at 18:18