Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
WordPress WooCommerce: Force local pickup as the only shipping option when products in the cart require it.
<?php
// Force pickup as a shipping option if one or more products in the catalog is marked as pickup only.
// To do this, add a shipping class with the slug 'pickup-only' then set products with that class as required.
// Add this script to your theme's functions.php or similar.
function hideShippingWhenPickupRequired($rates, $package)
{
foreach ($package['contents'] as $item) {
$product = $item['data'];
$shippingClass = $product->get_shipping_class();
if ('pickup-only' === $shippingClass) {
// The cart requires pickup
return array(
'local_pickup' => $rates['local_pickup'],
);
}
}
return $rates;
}
add_filter('woocommerce_package_rates', 'hideShippingWhenPickupRequired', 10, 2);
@ianulpindo

This comment has been minimized.

Copy link

ianulpindo commented Jan 13, 2017

Hi Kane, thank you for this. Would it be possible for you to update this to the latest Woocommerce version?

@mistahgreek

This comment has been minimized.

Copy link

mistahgreek commented Jan 19, 2018

This no longer works. It doesn't even allow me to pickup.

@dexter-adams

This comment has been minimized.

Copy link

dexter-adams commented Aug 16, 2018

Here is the updated function. Works in WooCommerce v3.4.4.

function hide_shipping_on_local_pickup_required( $rates, $package )
{
    $local = [];

    foreach( $package['contents'] as $item )
    {
        $product = $item['data'];
        $shipping_class = $product->get_shipping_class();

        if( $shipping_class == 'local-pickup' )
        {
            foreach( $rates as $rate_id => $rate )
            {
                if( 'local_pickup' === $rate->method_id )
                {
                    $local[ $rate_id ] = $rate;
                    break;
                }
            }
        }
    }

    return !empty( $local ) ? $local : $rates;
}

add_filter( 'woocommerce_package_rates', 'hide_shipping_on_local_pickup_required', 10, 2 );
@rbrenton

This comment has been minimized.

Copy link

rbrenton commented Dec 4, 2018

Works with WooCommerce v3.4.5 with a shipping plugin where local_pickup has been modified to legacy_local_pickup.

function hide_shipping_on_local_pickup_required( $rates, $package )
{
    $local = [];

    foreach( $package['contents'] as $item )
    {
        $product = $item['data'];
        $shipping_class = $product->get_shipping_class();

        if( $shipping_class == 'local-pickup' )
        {
            foreach( $rates as $rate_id => $rate )
            {
                if( in_array( $rate->method_id, array( 'local_pickup', 'legacy_local_pickup' ) ) )
                {
                    $local[ $rate_id ] = $rate;
                    break;
                }
            }
        }
    }

    return !empty( $local ) ? $local : $rates;
}

add_filter( 'woocommerce_package_rates', 'hide_shipping_on_local_pickup_required', 10, 2 );
@PierreNodles

This comment has been minimized.

Copy link

PierreNodles commented Feb 24, 2019

Hi there,

Couldn't make it work on Wordpress 4.9.9, Woocommerce 3.5.4 but here's what's been working out just fine for me :

function my_hide_shipping_when_local_is_available( $rates ) {
  
  $local= array();
  
  foreach ( $rates as $rate_id => $rate ) {
    if ('local_pickup' === $rate->method_id ) {
      $local[ $rate_id ] = $rate;
    }
  }
  
  return !empty( $local ) ? $local : $rates;
}

add_filter( 'woocommerce_package_rates', 'my_hide_shipping_when_local_is_available', 100 );

Furthermore, I wanted to force the local pickup on my customer only when products with a specific shipping class were on the the cart.
Here's the final result :

// Replace 'shipping-class' with the specific shipping class you want to force the local pick up upon
// To make it more readable, replace $shippingClass with your class name, eg : $hugeProducts

function my_hide_shipping_when_local_is_available( $rates ) {
    $cart_items = WC()->cart->get_cart();
    $shippingClass = false;
    
    foreach ( $cart_items as $cart_item ) {
		$product = $cart_item['data'];
		$class   = $product->get_shipping_class();
		
		if ( 'shipping-class' == $class ) {
			$shippingClass = true;
		}
	}
    
	$local = array();
	foreach ( $rates as $rate_id => $rate ) {
		if ('local_pickup' === $rate->method_id ) {
            $local[ $rate_id ] = $rate;
        }
	}
    
    if ( !empty($local) && ($shippingClass == true) ) {
        return $local;
    } else {
        return $rates;
    }

}

add_filter( 'woocommerce_package_rates', 'my_hide_shipping_when_local_is_available', 100 );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.