2

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;
}
Nico Haase
  • 11,420
  • 35
  • 43
  • 69

2 Answers2

0

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;
    }
}
Ashendale
  • 136
  • 9
  • was throwing an error but fixed it with code posted below, let me know if that is the best solution? Thanks again for your help – user15284871 Jan 03 '23 at 04:11
  • Okey I've done some digging and it seems the code is being executed in the backend where there is no cart. Maybe a better soloution would be to only execute the code on the cart page and checkout page? In that case you could use "if ( is_cart() || is_checkout() ) {" I'll edit my answer again and you can let me know how it works :) – Ashendale Jan 04 '23 at 08:36
0

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;
}
}