6

I'm trying to hide all but one shipping method based on the shipping class, essentially forcing the FedEx overnight method when a product belonging to a specific class is selected.

I'm starting with this code, and modifying it as indicated below:

add_filter( 'woocommerce_available_shipping_methods', 'hide_shipping_based_on_class' ,    10, 1 );

function check_cart_for_share() {

// load the contents of the cart into an array.
global $woocommerce;
$cart = $woocommerce->cart->cart_contents;

$found = false;

// loop through the array looking for the tag you set. Switch to true if the tag is     found.
foreach ($cart as $array_item) {
$term_list = wp_get_post_terms( $array_item['product_id'], 'product_shipping_class', array( "fields" => "names" ) );

if (in_array("Frozen",$term_list)) {

      $found = true;
      break;
    }
}

return $found;

}

function hide_shipping_based_on_class( $available_methods ) {

// use the function above to check the cart for the tag.
if ( check_cart_for_share() ) {

// remove the rate you want
unset( $available_methods['canada_post,purolator,fedex:FEDEX_GROUND,fedex:GOUND_HOME_DELIVERY'] ); 
}

// return the available methods without the one you unset.
return $available_methods;

}

It doesn't seem to be hiding any shipping methods though. Not sure what I'm missing...

It's a multi-site installation, I'm testing it on the Canadian side at http://stjeans.harbourcitydevelopment.com

I'm running the Table Rate shipping module, as well as the FedEx, Purolator and Canada Post modules.

dbc
  • 104,963
  • 20
  • 228
  • 340
SeanEnns
  • 145
  • 1
  • 1
  • 12

3 Answers3

11

I had same issue and modyfing your code helped. One problem is that "woocommerce_available_shipping_methods" filter is deprecated from WooCommerce 2.1. So you have to use the new one: "woocommerce_package_rates". There is WooCommerce tutorial for similar task, too.

So, I changed filter hook, and when the condition is true, I iterate all shipping methods/rates, find the one I want to display to customer, create new array from it and return this array (with only one item).

I think your problem was (beside deprecated hook) mainly in wrong unset($available_methods[...]) line. It could not work like that.

So here is my code:

add_filter( 'woocommerce_package_rates', 'hide_shipping_based_on_class' ,    10, 2 );
function hide_shipping_based_on_class( $available_methods ) {
    if ( check_cart_for_share() ) {
        foreach($available_methods as $key=>$method) {
            if( strpos($key,'YOUR_METHOD_KEY') !== FALSE ) {
                $new_rates = array();
                $new_rates[$key] = $method;
                return $new_rates;
            }
        }
    }
    return $available_methods;
}

Warning! I found out that woocommerce_package_rates hook is not fired everytime, but only when you change items or quantity of items in your cart. Or it looks like that for me. Maybe those available rates are cached somehow for cart content.

Marek
  • 588
  • 5
  • 12
  • 8
    You can get woocommerce_package_rates to fire every time by turning on shipping debug mode. Go to WooCommerce > Shipping > Shipping Options > Enable Debug Mode. – Ryan Hertz Mar 24 '18 at 17:51
  • 9
    +1 for the warning about the hook not firing every time unless you update the items in your cart. I had no idea why the hook seemed to not be working at all. – jwinn Apr 04 '18 at 21:35
  • 3
    Thank you both for these comments. This thing not firing was making me go insane. – Eolis Apr 09 '18 at 16:43
  • 2
    Well, well, well, if @Ryan ain't a life saver... 3 years later, some poor dude was going insane too *`y u not fire????`* – brasofilo May 29 '21 at 20:25
1

If someone stumbles here wondering why woocommerce_package_rates is not running. You can clear the cache using the following snippet:

/**
 * This implementation will disable the shipping rate cache.
 * To conditionally disable the cache, replace `wp_rand()` with a conditional value. 
 * Changing the conditional value will invalidate the cache.
 * Example: A hidden form field or a query string parameter.
 */
function wc_shipping_rate_cache_invalidation( $packages ) {
    foreach ( $packages as &$package ) {
        $package['rate_cache'] = wp_rand();
    }
    unset($package);

    return $packages;
}
add_filter( 'woocommerce_cart_shipping_packages', 'wc_shipping_rate_cache_invalidation', 100 );

There was a comment on the woocommerce_package_rates hook that pointed to a github gist for this snippet of code.

Uriahs Victor
  • 1,049
  • 14
  • 32
0

The bellow code snippet allows you hide the shipping methods based on shipping class. Detailed description is available here

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(
    42 => array(
        'free_shipping'
    )
);

$hide_when_shipping_class_not_exist = array(
    42 => array(
        'wf_shipping_ups:03',
        'wf_shipping_ups:02',
         'wf_shipping_ups:01'
    ),
    43 => array(
        'free_shipping'
    )
);


$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]);
        }
    }
}
foreach($hide_when_shipping_class_not_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;
}
Samuel Liew
  • 76,741
  • 107
  • 159
  • 260
Nishad Up
  • 3,457
  • 1
  • 28
  • 32