Avoid physical products purchases outside specific country in WooCommerce

103 views Asked by At

I sell both tangible and virtual products in my WooCommerce store, and am I having a hard time figuring out what to do when someone from outside the US tries to order a tangible product. I've looked around, and most solutions tend to be all or nothing. I'll sell my virtual products to anyone and anywhere, but I need to prevent people from outside the US from checking out if they have a tangible product in their cart.

Right now, if someone from outside the US tries to checkout with a tangible product, they just get a message in the shipping section that says "There are no shipping options available. Please ensure that your address has been entered correctly, or contact us if you need any help." but otherwise they are able to checkout. Anyone have any ideas or suggestions?

1

There are 1 answers

0
LoicTheAztec On

Based on Disable shipping for specific products based on country in Woocommerce, the following code will avoid add to cart for physical products or will remove physical cart items if customer shipping address is outside a specific country (USA here):

// Avoid Add to cart for non virtual products on countries outside USA
add_filter( 'woocommerce_add_to_cart_validation', 'check_physical_products_for_country', 10, 4 );
function check_physical_products_for_country( $passed, $product_id, $quantity, $variation_id = null ) {
    $product = wc_get_product( $variation_id > 0 ? $variation_id : $product_id );
    if ( WC()->customer->get_shipping_country() !== 'US' && ! $product->is_virtual() ) {
        wc_add_notice( __( "Only virtual products are purchasable outside United States of America.", "woocommerce" ), "error" );
        return false;
    }
    return $passed;
}

// Remove non virtual products from cart for countries outside USA (to be sure)
add_action('woocommerce_before_calculate_totals', 'check_physical_cart_items_for_country');
function check_physical_cart_items_for_country( $cart ) {
    if ((is_admin() && !defined('DOING_AJAX')))
        return;

    if (did_action('woocommerce_before_calculate_totals') >= 2)
        return;

    if ( ! ( is_cart() || is_checkout() ) )
        return;

    $country     = WC()->customer->get_shipping_country();
    $found_items = []; // initializing
    
    // Loop through cart items checking for non virtual products outside USA
    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        $product = $cart_item['data']; // Get the product object

        if ( $country !== 'US' && ! $product->is_virtual() ) {
            $found_items[$cart_item_key] = $product->get_name();
        }
    }

    if( count($found_items) > 0 ) {
        // Removing non virtual items found for customer outside USA
        foreach ( $found_items as $key => $name ) {
            $cart->remove_cart_item($key);
        }
        wc_clear_notices();
        wc_add_notice( sprintf( 
            __( 'Item(s) "%s" have been removed from cart as they are not shippable outside USA.', "woocommerce" ),  
        '<strong>' . implode(', ', $found_items) ) . '</strong>', "error" );
    }
}

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

enter image description here