I'm currently setting up a woocommerce driven shop.

I use the fedex shipping calc. extension to get the shipping costs calculated.

I wanna ship all items that are under 200$ for free. never mind if the cart total is above the 200$. Means you can add 4 or 6 or never mind how much items to the cart if each of the items is below the 200$ the shipping is free.

So what I did is I have set all that (below 200$)items up as "virtual" items. That way they skip the fedex shipping calc.

The problem is that I also wanna offer LOCAL PICKUP as a shipping option. But customers are not able to select that option if they have virtual items only in their cart.

Is there a way to enable the local pickup option anyway?

Or is there a smarter solution to get that idea done?


i have also tried to the following:

  1. I have created a special shipping class named it "free shipping".

  2. I have disabled the "virtual" option for one of the items wich has a price below the 200$. And i added that "special class "free shipping" to that item.

  3. I have then activated the FLAT RATE shipping method and set the shipping cost on that to 0.00

  4. I told that FLAT RATE shipping option to be active for my previously generated class (free shipping) only.

  5. I renamed the option from FLAT RATE to FREE SHIPPING so that it is listed as FREE SHIPPING on the checkout page

  6. So far so good, now if i add that item to the basket i see both options the FREE SHIPPING (the original flat rate i have renamed) and the "LOCAL PICKUP" option.

so far so good. that works fine ...

the problem is as soon as i add an another item to the cart with an price over 200$ fedex take affect and will calculate the shipping cost and a few fedex options are displayed.

i also see the local pickup BUT AND THAT IS THE PROBLEM I ALSO SEE THE FREE SHIPPING OPTION CUZ THE the item i have given the special class is still in the basket.

means people are able to select free shipping and that is not what i am looking for. As soon as a item with a price of over 200$ is in the basket the free shipping should be gone.


Here's a snippet colleted from some Gists out of a GitHub issue discussion linked by @Ewout in another answer. I added a var_dump(), so you can uncomment and check what exactly you want to remove.

$available_methods is an array of:

$available_methods as $method_id => $method
Compare against $method_id if you need more specific checks.

// Hide standard shipping option when free shipping is available
add_filter( 'woocommerce_available_shipping_methods',         'wpse90835_hide_standard_shipping_when_free_is_available' );
 *  Hide Standard Shipping option when free shipping is available
 * @param array $available_methods
function  wpse90835_hide_standard_shipping_when_free_is_available($available_methods )
// Developers!: Dump this to see what you can unset
# var_dump( $available_methods );

// remove standard shipping option
if ( 
    isset( $available_methods['free_shipping'] ) 
    AND isset( $available_methods['flat_rate'] )
    unset( $available_methods['flat_rate'] );

return $available_methods;

can somebody tell me how to use the "Compare against $method_id if you need more specific checks."

  • I'm not an expert on shipping, but couldn't you create a special shipping class? Once you set the items as virtual, you're telling WooCommerce that they don't need to be shipped. Commented Nov 13, 2013 at 11:58
  • The thing is as soon as you are set a item to "virtual" the option to assign it to a shipping class is not available anymore. i have also tried to the following:
    – Shorty05
    Commented Nov 13, 2013 at 15:45
  • Right, so don't set the item as virtual. I just looked into it though and I can't (quickly) find a way to exclude items from the the API shipping calculation. I'm sure it is possible, but I can't think of anything off-hand. Commented Nov 13, 2013 at 16:14

1 Answer 1


Well I dug a little deeper and found that in the abstract WC_Product class, there is the needs_shipping() method:

 * Checks if a product needs shipping.
 * @access public
 * @return bool
public function needs_shipping() {
    return apply_filters( 'woocommerce_product_needs_shipping', $this->is_virtual() ? false : true, $this );

and it is filterable, which means we can override the need for shipping costs on any product we like. Assuming you have a shipping class with the slug: shipping-class you can set any item with that class to not need shipping:

function wpa_123136_no_shipping( $needs_shipping, $product ){
  if( $product->get_shipping_class() == 'free-shipping' ){
    $needs_shipping = false;
  return $needs_shipping;
add_filter('woocommerce_product_needs_shipping','wpa_123136_no_shipping', 10, 2 );

or if you have a price-point and don't want to bother with the free shipping class:

function wpa_123136_no_shipping( $needs_shipping, $product ){
  if( $product->get_price() < 200 ){
    $needs_shipping = false;
  return $needs_shipping;
add_filter('woocommerce_product_needs_shipping','wpa_123136_no_shipping', 10, 2 );
  • thanks for looking into that ;) i will test it now and let you know if that works.
    – Shorty05
    Commented Nov 13, 2013 at 18:04
  • it doesn't work. as soon as i unstick the "virtual" option i see the shipping tab and if i don't fill in any dimensions or weights i get an error at the cart: Product # is missing dimensions. Aborting. (it comes from the fedex plugin) which means the code gets ignored cuz fedex still tries to calculate shipping.
    – Shorty05
    Commented Nov 14, 2013 at 13:46
  • Sorry. The solution must be in the shipping methods files (maybe in calculate_shipping()?) but I'm not familiar enough with the shipping classes and don't have the Fedex plugin to even look at. Commented Nov 14, 2013 at 15:27
  • no problem helga, thanks for looking into it anyway! i am very thankful for all your infos.
    – Shorty05
    Commented Nov 14, 2013 at 17:13

Not the answer you're looking for? Browse other questions tagged or ask your own question.