简体   繁体   中英

Hide specific shipping options based on products or categories in WooCommerce

My WooCommerce website uses 3 different shipping types.

  1. Royal mail signed for (7 days)
  2. Next day guaranteed
  3. Recorded delivery

Some products can only be shipped using option 1. When this product is added to the cart, a shipping class i created helps to show option 1 in the cart but the other two options are still visible (customers are not allowed to choose these options for this product). By using jQuery i was able to hide the other two options because option 1 was the default selection. (So it was easy to hide the other two based on this).

The problem i am having is that the 2 hidden options still appear on the checkout page and I'm not sure why.

This is the code I am using to hide the other two options when the first option is selected in the cart:

jQuery(document.body).ready(function() {
    if(jQuery('#shipping_method_0_ced_pps').val() == 'ced_pps')
        jQuery('ul#shipping_method li:nth-child(2)').hide();
        jQuery('ul#shipping_method li:nth-child(3)').hide();
});

The strange thing is if I test to see if a value exists on the checkout page I can fire an alert but when I use the above code it does not work at all.

Can someone provide some help or an alternative method?

I've had a look on here and this is the closest I've got to a solution without using jQuery. The problem with this solution is that I need to manually enter the product id's into the functions.php file. Which is not ideal when there's over 100 products.

Updated There is multiple ways to do it without any need of jQuery:

1) If you have few products you can use the following code, where you will define:

  • An array of product IDs
  • Your shipping methods instance IDs to be removed

The code:

add_filter( 'woocommerce_package_rates', 'specific_products_shipping_methods', 10, 2 );
function specific_products_shipping_methods( $rates, $package ) {
    // HERE set the product IDs in the array
    $product_ids = array( 113, 115, 126 ); 
    // HERE set the shipping methods to be removed (like "fat_rate:5")
    $method_instances_ids = array('2846', '2851'); 

    $found = false;

    // Loop through cart items checking for defined product IDs
    foreach( $package['contents'] as $cart_item ) {
        if ( in_array( $cart_item['product_id'], $product_ids ) ){
            $found = true;
            break;
        }
    }

    if ( ! $found ) return $rates; // If not found we exit

    // Loop through your active shipping methods
    foreach( $rates as $rate_id => $rate ) {
        // Remove all other shipping methods other than your defined shipping method
        if ( in_array( $rate_id, $method_instances_ids ) ){
            unset( $rates[$rate_id] );
        }
    }    

    return $rates;
}

Code goes in function.php file of your active child theme (or active theme). Tested and work.


2) If you have a bunch of products , is better to target those products through a product category (or a product Tag) … You can bulk assign it.

In the code, you will define:

  • A product category (or a product tag which taxonomy is product_tag )
  • Your shipping methods instance IDs to be removed

The code:

add_filter( 'woocommerce_package_rates', 'specific_products_shipping_methods', 10, 2 );
function specific_products_shipping_methods( $rates, $package ) {
    // HERE set the product category in the array (ID, slug or name)
    $terms = array( 'my-category' ); 
    $taxonomy = 'product_cat'; 

    // HERE set the shipping methods to be removed (like "fat_rate:5")
    $method_instances_ids = array('2846', '2851');  

    $found = false;

    // Loop through cart items checking for defined product IDs
    foreach( $package['contents'] as $cart_item ) {
        if ( has_term( $terms, $taxonomy, $cart_item['product_id'] ) ){
            $found = true;
            break;
        }
    }

    if ( ! $found ) return $rates; // If not found we exit

    // Loop through your active shipping methods
    foreach( $rates as $rate_id => $rate ) {
        // Remove all other shipping methods other than your defined shipping method
        if ( in_array( $rate_id, $method_instances_ids ) ){
            unset( $rates[$rate_id] );
        }
    }    

    return $rates;
}

Code goes in function.php file of your active child theme (or active theme). Tested and work.

To make it work for Product Tags :
You will simply replace the taxonomy 'product_cat' by 'product_tag'


3) If you have a bunch of products , you can also create a shipping class and bulk assign it to your products. You will need to set the price for it in your related shipping methods…

Filter Shipping method based on shipping class in Woocommerce 3

You should need to refresh the shipping caches:
1) First this code is already saved on your function.php file and empty your cart…
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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM