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 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 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 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 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 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.