Hide shipping methods if a virtual product is in the cart

491 Views Asked by At

If a woocommerce cart has a virtual item only it does not show shipping methods.

I have a unique situation where I'd like this to be the case also if the cart contains physical products but at least one virtual product (ie any virtual product in the cart, regardless of whatever else is in the cart, hide shipping methods). Whereas if no virtual products are in the cart then show shipping methods as normal.

I've tried the code below but it doesn't seem to work:

Thanks for your help

 add_filter( 'woocommerce_cart_needs_shipping_address', 'filter_cart_needs_shipping_address_callback' );
function filter_cart_needs_shipping_address_callback( $needs_shipping_address ){
    // Loop through cart items
    foreach ( WC()->cart->get_cart() as $item ) {
        if ( $item['data']->is_virtual() ) {
            $needs_shipping_address = false;
            break; // Stop the loop
        }
    }
    return $needs_shipping_address;
}
2

There are 2 best solutions below

2
On

I think I figured out how to do it for you. The Hook you're using in your example is not the right one since it's just filtering the shipping address callback.

What I think you need to do is use the woocommerce cart needs shipping hook.

Since it was throwing an error you could try to only run the code on the cart and checkout page. You can do that by using if ( is_cart() || is_checkout() ) {

Try the edited code below and let me know how it works.

Have a wonderful day!

add_filter( 'woocommerce_cart_needs_shipping', 'remove_virtual_product_shipping_methods' );
function remove_virtual_product_shipping_methods( $needs_shipping ){
    //Only execute code on cart and checkout page.
     if ( is_cart() || is_checkout() ) {
        //Loop trough cart items
        foreach ( WC()->cart->get_cart() as $item ) {
            //If a product in cart is a vritual product remove all shipping
            if ( $item['data']->is_virtual() ) {
                $needs_shipping = false;
                break;
            }
        }
        return $needs_shipping;
    }
}
0
On

Thanks, it was throwing the error "Uncaught Error: Call to a member function get_cart() on null" but have managed to fix it with this:

if ( is_null( WC()->cart ) ) {
                wc_load_cart();        
        } else 

Let me know if there is a better way to do it? Thanks

add_filter( 'woocommerce_cart_needs_shipping', 'filter_cart_needs_shipping_address_callback' );
function filter_cart_needs_shipping_address_callback( $needs_shipping ){
    // Loop through cart items
    if ( is_null( WC()->cart ) ) {
                wc_load_cart();        
        } else {
    foreach ( WC()->cart->get_cart() as $item ) {
        if ( $item['data']->is_virtual() ) {
            $needs_shipping = false;
            break; // Stop the loop
        }
    }
    return $needs_shipping;
}
}