-
-
Save kane-c/5e4d53601564ed667fb9 to your computer and use it in GitHub Desktop.
<?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); |
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 );
Hi
Snippets above doesn't work for me, but I found this working solution: WooCommerce: Hide Shipping Rate if Shipping Class @ Cart
Clear transients after implementation!
/**
* @snippet Disable Free Shipping if Cart has Shipping Class (WooCommerce 2.6+)
* @how-to Get CustomizeWoo.com FREE
* @author Rodolfo Melogli
* @testedwith WooCommerce 4.0
* @donate $9 https://businessbloomer.com/bloomer-armada/
*/
add_filter( 'woocommerce_package_rates', 'businessbloomer_hide_free_shipping_for_shipping_class', 10, 2 );
function businessbloomer_hide_free_shipping_for_shipping_class( $rates, $package ) {
$shipping_class_target = 59; // shipping class ID (to find it, see screenshot here: https://www.businessbloomer.com/woocommerce-disable-free-shipping-if-cart-has-shipping-class/ )
$in_cart = false;
foreach ( WC()->cart->get_cart_contents() as $key => $values ) {
if ( $values[ 'data' ]->get_shipping_class_id() == $shipping_class_target ) {
$in_cart = true;
break;
}
}
if ( $in_cart ) {
unset( $rates['flat_rate:1'] ); // shipping method with ID (to find it, see screenshot here: https://www.businessbloomer.com/woocommerce-disable-free-shipping-if-cart-has-shipping-class/)
}
return $rates;
}
I expanded the above snippets with an extra shipping class for products that are not delivered separately.
Tested with Wordpress 5.7.1 and WooCommerce 5.2.2
/**
* Hide all other methods if:
* - At least one item has shipping class 'local-pickup-only'
* OR
* - All items have shipping class 'no-individual-delivery'
**/
function check_local_pickup_only( $rates, $package ) {
$localPickupOnly = false;
$noIndividualDelivery = false;
$regularDelivery = false;
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
$class = $product->get_shipping_class();
switch ($class) {
case 'local-pickup-only':
$localPickupOnly = true;
break 2;
case 'no-individual-delivery':
$noIndividualDelivery = true;
break;
default:
$regularDelivery = true;
break;
}
}
if ( $noIndividualDelivery && !$regularDelivery ) {$localPickupOnly = true;}
$local = array();
foreach ( $rates as $rate_id => $rate ) {
if ('local_pickup' === $rate->method_id ) {
$local[ $rate_id ] = $rate;
}
}
if ( !empty($local) && ($localPickupOnly == true) ) {
return $local;
} else {
return $rates;
}
}
add_filter( 'woocommerce_package_rates', 'check_local_pickup_only', 10, 2 );
Here's my solution: for carts with one or more products belonging to the shipping class "Local Pickup Only" ($shipping_class_name = 'local-pickup-only'
), only the local pickup location(s) (from the Local Pickup in Blocks) will appear.
Tested with WordPress 6.5.2 and WooCommerce 8.7.0.
Important: "Clear customer sessions" after implementation (WooCommerce > Status > Tools > Clear customer sessions).
// WooCommerce display only "Local pickup" location(s) (from new "WooCommerce Blocks: Local Pickup" - Settings > Shipment > "Local Pickup" tab - https://woocommerce.com/document/woocommerce-blocks-local-pickup/) if one or more products added to the cart belong to the $shipping_class_name = 'local-pickup-only', dynamically unsets all shipping methods except those with values starting with "pickup_location:".
// Please note that the new "WooCommerce Blocks: Local Pickup" does not work with Elementor as it requires the Checkout block to enable it (as described here https://woocommerce.com/document/using-the-new-block-based-checkout/).
add_filter($hook_name='woocommerce_package_rates', $callback='woocommerce_shipping_method_local_pickup_only', $priority=10, $accepted_args=1);
function woocommerce_shipping_method_local_pickup_only( $rates ) {
if ( WC() ) {
// Setup
$shipping_class_name = 'local-pickup-only';
$in_cart = false;
foreach ( WC()->cart->get_cart_contents() as $key => $values ) {
if ( $values['data']->get_shipping_class() === $shipping_class_name ) {
$in_cart = true;
break;
}
}
if ( $in_cart ) {
// Unset all shipping methods except for the ones with value starting with "pickup_location:"
foreach ( $rates as $rate_key => $rate ) {
if ( strpos( $rate_key, 'pickup_location:' ) !== 0 ) {
unset( $rates[ $rate_key ] );
}
}
}
return $rates;
}
}
For those using the "legacy" local pickup, the code below accomplishes the same goal.
// WooCommerce display only chosen $local_pickup_ids if one or more products added to the cart belong to the $shipping_class_name = 'local-pickup-only', dynamically unsets all shipping methods except for chosen $local_pickup_ids.
add_filter($hook_name='woocommerce_package_rates', $callback='woocommerce_shipping_method_local_pickup_only', $priority=10, $accepted_args=1);
function woocommerce_shipping_method_local_pickup_only( $rates ) {
if ( WC() ) {
// Setup
$shipping_class_name = 'local-pickup-only';
$local_pickup_ids = array('local_pickup:38');
$in_cart = false;
foreach ( WC()->cart->get_cart_contents() as $key => $values ) {
if ( $values['data']->get_shipping_class() === $shipping_class_name ) {
$in_cart = true;
break;
}
}
if ( $in_cart ) {
// Unset all shipping methods except for $local_pickup_ids
foreach ( $rates as $rate_key => $rate ) {
if ( !in_array($rate_key, $local_pickup_ids) ) {
unset( $rates[$rate_key] );
}
}
}
return $rates;
}
}
Works with WooCommerce v3.4.5 with a shipping plugin where local_pickup has been modified to legacy_local_pickup.