Hide shipping methods for specific shipping class in WooCommerce - php

Essentially I'm trying to make the flat rate method Id flat_rate:7 disabled when there is cart items that have the shipping class "Roller" (ID 92).
This is the code I tried:
add_filter('woocommerce_package_rates', 'wf_hide_shipping_method_based_on_shipping_class', 10, 2);
function wf_hide_shipping_method_based_on_shipping_class($available_shipping_methods, $package)
{
$hide_when_shipping_class_exist = array(
92 => array(
'flat_rate:7'
)
);
$shipping_class_in_cart = array();
foreach(WC()->cart->cart_contents as $key => $values) {
$shipping_class_in_cart[] = $values['data']->get_shipping_class_id();
}
foreach($hide_when_shipping_class_exist as $class_id => $methods) {
if(in_array($class_id, $shipping_class_in_cart)){
foreach($methods as & $current_method) {
unset($available_shipping_methods[$current_method]);
}
}
}
return $available_shipping_methods;
}
Shipping class ID 92 is the shipping class and I want to hide flat_rate:7 for it.
My Site is this: http://www.minimoto.me/
WordPress: 4.8.4
WooCommerce: 3.1.1
Any help will be greatly appreciated.

Update 2019: You should try instead this shorter, compact and effective way:
add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_shipping_class', 10, 2 );
function hide_shipping_method_based_on_shipping_class( $rates, $package )
{
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// HERE define your shipping class to find
$class = 92;
// HERE define the shipping method to hide
$method_key_id = 'flat_rate:7';
// Checking in cart items
foreach( $package['contents'] as $item ){
// If we find the shipping class
if( $item['data']->get_shipping_class_id() == $class ){
unset($rates[$method_key_id]); // Remove the targeted method
break; // Stop the loop
}
}
return $rates;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and works.
Sometimes, you should may be need to refresh shipping methods going to shipping areas, then disable / save and re-enable / save your "flat rates" shipping methods.
Related: Hide shipping methods for specific shipping classes in WooCommerce
To find the shipping methods IDs and the shipping classes IDs see below…
Update for many different shipping methods (related to your comments):
add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_shipping_class', 10, 2 );
function hide_shipping_method_based_on_shipping_class( $rates, $package )
{
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// HERE define your shipping class to find
$class = 92;
// HERE define the shipping methods you want to hide
$method_key_ids = array('flat_rate:7', 'local_pickup:3');
// Checking in cart items
foreach( $package['contents'] as $item ) {
// If we find the shipping class
if( $item['data']->get_shipping_class_id() == $class ){
foreach( $method_key_ids as $method_key_id ){
unset($rates[$method_key_id]); // Remove the targeted methods
}
break; // Stop the loop
}
}
return $rates;
}
Tested and works…
Finding the shipping class ID.
In the database under wp_terms table:
Search for a term name or a term slug and you will get the term ID (the shipping class ID).
On Woocommerce shipping settings editing a "Flat rate", with your browser html inspector tool, inspect a shipping Class rate field like:
In the imput name attribute you have woocommerce_flat_rate_class_cost_64. So 64 is the ID for the shipping class.
Get the shipping method rate ID:
To get the related shipping methods rate IDs, something like flat_rate:12, inspect with your browser code inspector each related radio button attribute value like:

By tweaking LoicTheAztec's code (cheers), I was able to unset a shipping method for each package based on the shipping class of its contents, rather than the cart as a whole. Perhaps it will help someone else too:
// UNSET A SHIPPING METHOD FOR PACKAGE BASED ON THE SHIPPING CLASS(es) OF ITS CONTENTS
add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_shipping_class', 10, 2 );
function hide_shipping_method_based_on_shipping_class( $rates, $package )
{
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
foreach( $package['contents'] as $package_item ){ // Look at the shipping class of each item in package
$product_id = $package_item['product_id']; // Grab product_id
$_product = wc_get_product( $product_id ); // Get product info using that id
if( $_product->get_shipping_class_id() != 371 ){ // If we DON'T find this shipping class ID
unset($rates['wbs:9:dae98e94_free_ups_ground']); // Then remove this shipping method
break; // Stop the loop, since we've already removed the shipping method from this package
}
}
return $rates;
}
This code allows me to unset my 'Free UPS Ground' shipping if the package contains anything but 'Standard' items (shipping_class_id 371 in my case).
The scenario from the original post (disable method x if shipping class y) would work like this:
// UNSET A SHIPPING METHOD FOR PACKAGE BASED ON THE SHIPPING CLASS(es) OF ITS CONTENTS
add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_shipping_class', 10, 2 );
function hide_shipping_method_based_on_shipping_class( $rates, $package )
{
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
foreach( $package['contents'] as $package_item ){ // Look at the shipping class of each item in package
$product_id = $package_item['product_id']; // Grab product_id
$_product = wc_get_product( $product_id ); // Get product info using that id
if( $_product->get_shipping_class_id() == 92 ){ // If we DO find this shipping class ID
unset($rates['flat_rate:7']); // Then remove this shipping method
break; // Stop the loop, since we've already removed the shipping method from this package
}
}
return $rates;
}

Related

Disable shipping methods having a specific word and based on a shipping class in WooCommerce

I've used a Business Bloomer snippet and tweaked it a bit to unset some shipping methods depending on a shipping class of items in the cart.
It works fine with the 4 shipping methods I have tested with but in order to fully work on my website, I have to list all shipping methods values manually and I have A LOT ( 86 to unset in if and 60 in else.)
Therefore, I would like to edit the snipped so I could unset all shipping methods that contains the same term all at once rather than look for each value individually, but don't really know how to.
I have prints for sale and so I’ve set some shipping methods for orders including prints and some for orders whitout. Therefore all my shipping methods for prints have a value ending with “_print” when the others have a value ending with “_classique”, as you can see in the code bellow.
My goal is to disable all shipping methods ending with “_classique” when a product with the “print” shipping class in the cart and vice versa.
So far my code looks like this :
add_filter( 'woocommerce_package_rates', 'businessbloomer_hide_regular_shipping_method', 10, 2 );
function businessbloomer_hide_regular_shipping_method( $rates, $package ) {
$shipping_class_target = 35; // shipping class ID
$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 ) { // shipping method with value
unset( $rates['wbs:2:d6f790a0_colissimo_sans_signature_classique'] );
unset( $rates['wbs:2:d748dcd4_lettre_suivie_classique'] );
unset( $rates['wbs:2:f1058bc8_colissimo_avec_signature_classique'] );
}
else{
unset( $rates['wbs:2:1cdf4913_colissimo_sans_signature_print'] );
unset( $rates['wbs:2:fghla482_lettre_suivie_print'] );
unset( $rates['wbs:2:g27a1f56_colissimo_avec_signature_print'] );
}
return $rates;
}
Any help on how to achieve this would be very appreciated.
Thank you to anyone who'll take time to read this !
Updated
Using PHP strpos() will allow you to check if a word is contained in a string. Then you will need to make some changes in your code to make it work:
add_filter( 'woocommerce_package_rates', 'show_hide_shipping_methods', 10, 2 );
function show_hide_shipping_methods( $rates, $package ) {
$shipping_class_id = 35; // Targeted shipping class ID
$found = false;
// Loop through cart items for the current package
foreach ( $package['contents'] as $cart_item ) {
if( $cart_item['data']->get_shipping_class_id() == $shipping_class_id ) {
$found = true;
break;
}
}
// Loop through shipping rates
foreach ( $rates as $rate_key => $rate ) {
if ( $found && strpos($rate_key, '_classique') !== false ) {
unset($rates[$rate_key]);
}
elseif (! $found && strpos($rate_key, '_print') !== false ) {
unset($rates[$rate_key]);
}
}
return $rates;
}
Code goes in functions.php file of the active child theme (or active theme). It should works.
Clearing shipping caches:
You will need to empty your cart, to clear cached shipping data
Or In shipping settings, you can disable / save any shipping method, then enable back / save.
Related:
How can I check if a word is contained in another string using PHP?
Hide shipping methods for specific shipping class in WooCommerce
Filter Shipping method based on shipping class in Woocommerce 3

Disable specific shipping method just for a cart item uses a specific shipping class ID

From Disable specific shipping method if a cart item uses a specific shipping class ID answer code, how if there is another item in cart which does not have that shipping class ID and want to show flat_rate:2 again according to product shipping class?
You will use the following instead:
add_filter( 'woocommerce_package_rates', 'custom_hide_shipping_methods', 10, 2 );
function custom_hide_shipping_methods( $rates, $package ) {
$found = $others = false; // Initializing
$shipping_class_id = 513; // <== ID OF YOUR SHIPPING_CLASS
$shipping_rate_id = 'flat_rate:2'; // <== Targeted shipping rate ID
// Checking cart items for current package
foreach( $package['contents'] as $key => $cart_item ) {
$product = $cart_item['data']; // The WC_Product Object
if( $product->get_shipping_class_id() == $shipping_class_id ) {
$found = true;
} else {
$others = true;
}
}
if( $found && ! $others && isset($rates[$shipping_rate_id]) ) {
unset($rates[$shipping_rate_id]); // Removing specific shipping method
}
return $rates;
}
Code goes in functions.php file of your active child theme (or active theme). It should works.
Refresh the shipping caches:
This code is already saved on your functions.php file.
In a shipping zone settings, disable / save any shipping method, then enable back / save.
You are done and you can test it.

Disable a shipping method for a specific payment method in Woocommerce

On Woocommerce, I have enabled 2 shipping methods: Free shipping or Flat rate. I have enabled 2 payment methods: Bank transfer (bacs) and PayPal (paypal).
What I want to achieve:
If a customer selects PayPal as payment type he should be forced to select "Flat rate" as shipping method. "Free shipping" should be either hidden or greyed out or something like that.
If bank transfer is chosen then both shipping methods should be available.
Any help is appreciated.
If anyone is interested, I found a solution:
function alter_payment_gateways( $list ){
// Retrieve chosen shipping options from all possible packages
$chosen_rates = ( isset( WC()->session ) ) ? WC()->session->get( 'chosen_shipping_methods' ) : array();
if( in_array( 'free_shipping:1', $chosen_rates ) ) {
$array_diff = array('WC_Gateway_Paypal');
$list = array_diff( $list, $array_diff );
}
return $list;
}
add_action('woocommerce_payment_gateways', 'alter_payment_gateways');
This code will deactivate PayPal if a customer selects free shipping.
Update 2: The following code will disable "free_shipping" shipping method (method ID) when "paypal" is the chosen payment method:
add_filter( 'woocommerce_package_rates', 'shipping_methods_based_on_chosen_payment', 100, 2 );
function shipping_methods_based_on_chosen_payment( $rates, $package ) {
// Checking if "paypal" is the chosen payment method
if ( WC()->session->get( 'chosen_payment_method' ) === 'paypal' ) {
// Loop through shipping methods rates
foreach( $rates as $rate_key => $rate ){
if ( 'free_shipping' === $rate->method_id ) {
unset($rates[$rate_key]); // Remove 'Free shipping'shipping method
}
}
}
return $rates;
}
// Enabling, disabling and refreshing session shipping methods data
add_action( 'woocommerce_checkout_update_order_review', 'refresh_shipping_methods', 10, 1 );
function refresh_shipping_methods( $post_data ){
$bool = true;
if ( WC()->session->get('chosen_payment_method' ) ) $bool = false;
// Mandatory to make it work with shipping methods
foreach ( WC()->cart->get_shipping_packages() as $package_key => $package ){
WC()->session->set( 'shipping_for_package_' . $package_key, $bool );
}
WC()->cart->calculate_shipping();
}
// Jquery script for checkout page
add_action('wp_footer', 'refresh_checkout_on_payment_method_change' );
function refresh_checkout_on_payment_method_change() {
// Only checkout page
if( is_checkout() && ! is_wc_endpoint_url() ):
?>
<script type="text/javascript">
jQuery(function($){
// On shipping method change
$('form.checkout').on( 'change', 'input[name^="payment_method"]', function(){
$('body').trigger('update_checkout'); // Trigger Ajax checkout refresh
});
})
</script>
<?php
endif;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
To get the related shipping methods rate IDs, something like flat_rate:12, inspect with your browser code inspector each related radio button attribute name like:
Note: Since WooCommerce new versions changes, sorry, the code doesn't work anymore.

Filter Shipping method based on shipping class in Woocommerce 3

I have been searching for code to filter out any shipping methods other than local pick up, on checkout, when a product that has a specific shipping class selected (Only pickup, ex.) is in the cart (among other products).
I only found code that was outdated and that doesn't work on WC3+.
Here is the way to filter out any shipping methods other than local pick up, when a product that has a specific shipping class enabled:
add_filter( 'woocommerce_package_rates', 'custom_shipping_rates', 100, 2 );
function custom_shipping_rates( $rates, $package ) {
$shipping_class = 64; // HERE set the shipping class ID
$found = false;
// Loop through cart items Checking for the defined shipping method
foreach( $package['contents'] as $cart_item ) {
if ( $cart_item['data']->get_shipping_class_id() == $shipping_class ){
$found = true;
break;
}
}
if ( ! $found ) return $rates; // If not found we exit
// Loop through shipping methods
foreach( $rates as $rate_key => $rate ) {
// all other shipping methods other than "Local Pickup"
if ( 'local_pickup' !== $rate->method_id && $found ){
// Your code here
}
}
return $rates;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works
Then in StackOverFlow searching for recent answer with woocommerce_package_rates will allow you to finish your code.

Disable Free Shipping based on shipping classes in Woocommerce

I'm trying to write a function for WooCommerce that will disable free shipping if a product with a certain shipping class is present in the cart.
Here is what I have which is not working. e-packet is the shipping class that should disable free shipping if it is present in the cart.
function hide_shipping_when_class_is_in_cart( $rates, $package ) {
$shipping_classes = array('e-packet');
$if_exists = false;
foreach( $package['contents'] as $key => $values ) {
if( in_array( $values[ 'data' ]->get_shipping_class(), $shipping_classes ) )
$if_exists = true;
}
if( $if_exists ) unset( $rates['free_shipping:9'] );
return $rates;
}
add_filter( 'woocommerce_package_rates', 'hide_shipping_when_class_is_in_cart', 10, 2 );
Based on similar: Unsetting WooCommerce shipping method based on cart items shipping classes
I have make very small changes. This code is tested and works (see the note at the end):
add_filter( 'woocommerce_package_rates', 'hide_shipping_when_class_is_in_cart', 100, 2 );
function hide_shipping_when_class_is_in_cart( $rates, $package ) {
// Initialisation
$free_shipping_method = 'free_shipping:9';
$shipping_classes = array('e-packet');
$class_exists = false;
foreach( $package['contents'] as $cart_item )
if( in_array( $cart_item['data']->get_shipping_class(), $shipping_classes ) ) {
$class_exists = true;
break; // Stop the loop
}
if( $class_exists )
unset( $rates[$free_shipping_method] );
return $rates;
}
Code goes in function.php file of your active child theme (or active theme).
You should need to refresh the shipping caches:
1) First this code is already saved on your function.php file.
2) In Shipping settings, enter in a Shipping Zone and disable a Shipping Method and "save". Then re-enable that Shipping Method and "save". You are done.

Categories