Skip to content
Advertisement

Allow only Local Pickup for specific products outside specific Shipping Zone in WooCommerce

I have several products in the store, however one product (flammable) can only be shipped via a specific shipping company; Unfortunately that company can’t reach the whole country. So in case the customer buys the flammable product and it’s outside the coverage of the only company that can ship the product, he should not see any other shipping option except local pickup.

So far I have this code (courtesy of different StackOverFlow answers):

function filter_woocommerce_package_rates( $rates, $package ) {
    // Shipping zone
    //echo 'entrando';
    $shipping_zone = wc_get_shipping_zone( $package );

    $product_ids = array( 2267 ); // HERE set the product IDs in the array
    $method_id = 'weight_based_shipping:38'; // HERE set the shipping method ID that I want to hide
    $found = false;
    
    // Get zone ID
    $zone_id = $shipping_zone->get_id();
    
    //echo $shipping_zone;
    //echo $zone_id;
    
    // NOT equal
    if ( $zone_id != 8 ) {
        // Unset a single rate/method for a specific product
        foreach( $package['contents'] as $cart_item ) {
        if ( in_array( $cart_item['product_id'], $product_ids ) ){
            $found = true;
            break;
        }
        }
         if ( $found )
            unset( $rates[$method_id] );
    }

    return $rates;
}
add_filter( 'woocommerce_package_rates', 'filter_woocommerce_package_rates', 10, 2 );

however I don’t know why is not working. Even the ‘echo’ is not working.

Advertisement

Answer

Updated – Try following instead (code is commented):

// SETTINGS BELOW: Custom function that handle your settings
function custom_shipping_settings() {
    return array(
        'product_ids' => array(2267), // Define the products that need to be in a separated shipping package (local pickup)
        'allowed_zones_ids' => array(8), // Define the allowed zones IDs
    );
}


// Splitting cart items into 2 shipping packages
add_filter( 'woocommerce_cart_shipping_packages', 'split_shipping_packages' );
function split_shipping_packages( $packages ) {
    extract(custom_shipping_settings()); // Load and extract settings

    $customer       = WC()->customer;
    $destination    = array(
        'country'   => $customer->get_shipping_country(),
        'state'     => $customer->get_shipping_state(),
        'postcode'  => $customer->get_shipping_postcode(),
        'city'      => $customer->get_shipping_city(),
        'address'   => $customer->get_shipping_address(),
        'address_2' => $customer->get_shipping_address_2()
    );
    $package_dest   = array( 'destination' => $destination );
    $zone           = wc_get_shipping_zone( $package_dest );

    if ( ! in_array( $zone->get_id(), $allowed_zones_ids ) ) {

        // Reset packages and initialize variables
        $packages = $splitted_cart_items = array();

        // Loop through cart items
        foreach ( WC()->cart->get_cart() as $item_key => $item ) {
            if ( is_a($item['data'], 'WC_Product') && $item['data']->needs_shipping() ) {
                if ( ! array_intersect( array($item['product_id'], $item['variation_id']), $product_ids ) ) {
                    $splitted_cart_items[0][$item_key] = $item; // Regular items
                } else {
                    $splitted_cart_items[1][$item_key] = $item; // Special separated items
                }
            }
        }

        if ( count($splitted_cart_items) < 2 )
            return $packages;

        // Loop through spitted cart items
        foreach ( $splitted_cart_items as $key => $items ) {
            // Set each cart items group in a shipping package
            $packages[$key] = array(
                'contents'        => $items,
                'contents_cost'   => array_sum( wp_list_pluck( $items, 'line_total' ) ),
                'applied_coupons' => WC()->cart->get_applied_coupons(),
                'user'            => array( 'ID' => get_current_user_id() ),
                'destination'     => $destination,
            );
        }
    }
    return $packages;
}

// Force local pickup for specific splitted shipping package (for the defined products)
add_filter( 'woocommerce_package_rates', 'filter_wc_package_rates', 10, 2 );
function filter_wc_package_rates( $rates, $package ) {
    extract(custom_shipping_settings()); // Load and extract settings

    $zone  = wc_get_shipping_zone( $package ); // Get current shipping zone
    $found = false;

    // For all others shipping zones than allowed zones
    if ( ! in_array( $zone->get_id(), $allowed_zones_ids ) ) {
        // Loop through cart items for current shipping package
        foreach( $package['contents'] as $item ) {
            // Look for defined specific product Ids
            if ( array_intersect( array($item['product_id'], $item['variation_id']), $product_ids ) ) {
                $found = true; // Flag as found
                break; // Stop the loop
            }
        }

        // If any defined product is in cart
        if ( $found ) {
            // Loop through shipping rates
            foreach ( $rates as $rate_key => $rate ) {
                // Hide all shipping methods keeping "Local pickup"
                if ( 'local_pickup' !== $rate->method_id ) {
                    unset( $rates[$rate_key] );
                }
            }
        }
    }
    return $rates;
}

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

Refresh the shipping caches:

  1. This code is already saved on your functions.php file.
  2. In a shipping zone settings, disable / save any shipping method, then enable back / save.

    You are done and you can test it.
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement