wysiwyg
wysiwyg

Reputation: 33

WooCommerce: If specific product is the only item in cart, clear cart

If users purchase a product on my site, I give them the option of adding a discounted product to their cart at checkout. However, users are able to remove the original product from cart and the discounted product still remains within the cart.

Is it possible to have it such that if the discounted product is the only one in the cart, then the cart should be empty? I haven't found a way to do this.

What I have tried

Currently, I use the following code from bekarice found on Github:

/**
 * Renders a notice and prevents checkout if the cart
 * only contains products in a specific category
 */
function sv_wc_prevent_checkout_for_category() {
    
    // set the slug of the category for which we disallow checkout
    $category = 'clothing';
    
    // get the product category
    $product_cat = get_term_by( 'slug', $category, 'product_cat' );
    
    // sanity check to prevent fatals if the term doesn't exist
    if ( is_wp_error( $product_cat ) ) {
        return;
    }
    
    $category_name = '<a href="' . get_term_link( $category, 'product_cat' ) . '">' . $product_cat->name . '</a>';
    
    // check if this category is the only thing in the cart
    if ( sv_wc_is_category_alone_in_cart( $category ) ) {
        
        // render a notice to explain why checkout is blocked
        wc_add_notice( sprintf( 'Hi there! Looks like your cart only contains products from the %1$s category &ndash; you must purchase a product from another category to check out.', $category_name ), 'error' );
    }
}
add_action( 'woocommerce_check_cart_items', 'sv_wc_prevent_checkout_for_category' );


/**
 * Checks if a cart contains exclusively products in a given category
 * 
 * @param string $category the slug of the product category
 * @return bool - true if the cart only contains the given category
 */
function sv_wc_is_category_alone_in_cart( $category ) {
        
    // check each cart item for our category
    foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
        
        // if a product is not in our category, bail out since we know the category is not alone
        if ( ! has_term( $category, 'product_cat', $cart_item['data']->id ) ) {
            return false;
        }
    }
        
    // if we're here, all items in the cart are in our category
    return true;
}

But I don't think it as good a method. Basically, it doesn't allow users to checkout if cart only contains items from a certain category.

Upvotes: 2

Views: 1423

Answers (1)

LoicTheAztec
LoicTheAztec

Reputation: 254162

You can use the following code that will check on adding to cart your specific discounted product that cart is not empty and that it's not alone in cart, removing it from cart:

// Add to cart validation for the discounted product
add_filter( 'woocommerce_add_to_cart_validation', 'check_specific_discounted_product', 10, 3 );
function check_specific_discounted_product( $passed, $product_id, $quantity ) {
    // Settings
    $discounted_product_id = 53;

    if( WC()->cart->is_empty() && $discounted_product_id == $product_id ) {
        wc_add_notice( __("This product can't be purchased alone."), 'notice' );
        return false;
    }

    return $passed;
}

// Removing the discounted product if it's alone in cart
add_action( 'woocommerce_before_calculate_totals', 'conditionally_remove_a_discounted_product' );
function conditionally_remove_a_discounted_product( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    // Settings
    $discounted_product_id = 53;

    // Initializing variables
    $discounted_item_key = false;

    // Loop through cart items (first loop)
    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ){
        // When free productis is cart
        if ( in_array( $discounted_product_id, array($cart_item['product_id'], $cart_item['variation_id']) ) ) {
            $discounted_item_key = $cart_item_key;
        }
        // if any other product is in cart: EXIT
        else {
           return;
        }
    }
    // When the discounted product is alone in cart, remove it
    if( $discounted_item_key ) {
        // display notice on removal (optional)
        wc_clear_notices();
        wc_add_notice( __("The discounted product can't be purchased alone and has been removed."), 'notice' );

        $cart->remove_cart_item( $discounted_item_key ); // Remove
    }
}

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

Upvotes: 3

Related Questions