All articles
2026-08-13 · Dreamfox Team

Hide Local Pickup for Specific Products

Hide local pickup for specific products in WooCommerce: why pickup-only and no-pickup rules matter, the package rates filter, and mixed-cart handling.

A disabled storefront pickup option next to an active delivery van option at WooCommerce checkout

Local pickup is the cheapest shipping method you will ever run, and it is exactly wrong for part of your catalogue. Made-to-order items that ship straight from a supplier cannot be collected from your counter. Bulky stock you keep off-site is not in the building. Perishables you would rather not have sitting on a shelf until someone remembers to collect them. So the practical requirement is narrow: hide local pickup for specific products while leaving it on everything else.

Two rules, opposite directions

Most stores end up needing both:

  • No pickup for these products. Dropshipped, supplier-shipped or off-site stock. Pickup must disappear when such an item is in the cart.
  • Pickup only for these products. Fragile, oversized, licensed or age-checked goods you refuse to hand to a courier. Every other method must disappear.

They are the same mechanism with the condition inverted, and both belong on WooCommerce's rate filter rather than in CSS or JavaScript. A method hidden in the browser is still selectable server-side, which produces orders you cannot fulfil.

The rule in code

```php add_filter( 'woocommerce_package_rates', function ( $rates, $package ) { $no_pickup_ids = [ 128, 341 ]; // products that cannot be collected

foreach ( $package['contents'] as $item ) { if ( in_array( $item['product_id'], $no_pickup_ids, true ) ) { foreach ( array_keys( $rates ) as $rate_id ) { if ( str_starts_with( $rate_id, 'local_pickup' ) ) { unset( $rates[ $rate_id ] ); } } break; } }

return $rates; }, 10, 2 ); ```

For the pickup-only case, keep the rates whose ID starts with `local_pickup` and unset everything else. In both variants, match on the rate ID prefix: WooCommerce appends the method instance, so the ID is `local_pickup:4`, not `local_pickup`.

If nothing changes when you reload, you have hit the session rate cache rather than a broken rule. Empty the cart and try again.

Managing it as data instead of code

Hardcoded product IDs age badly — the list lives in PHP, nobody remembers it, and a new supplier-shipped product silently becomes collectable. Our WooCommerce Shipping Gateway Per Product plugin keeps the same filter logic but takes the product and category selection from wp-admin, so the rule is visible next to the product it applies to and a shop manager can maintain it.

If the rule is really about a whole group of stock rather than individual items, treat it as a category rule instead — see setting the shipping method by product category.

Mixed carts and the empty-checkout trap

A cart holding one collectable item and one that must be shipped needs a decision:

  • Strictest wins — remove pickup for the whole cart. Simple, safe, and the customer gets one delivery.
  • Block the combination — a cart notice asking the customer to split the order. Necessary when a pickup-only item cannot legally be couriered.

The failure to avoid is a combination that removes every rate. A pickup-only product plus a no-pickup product does exactly that if you apply both rules blindly, and the customer sees a checkout with no shipping options and no explanation. Detect the collision and show a clear cart notice instead.

Geography belongs in zones, not product rules

"Pickup only for customers near the store" is not a product rule. Put local pickup in a shipping zone limited to your postcodes, region or country, and let the zone handle who sees it. Combine the two layers and the meaning stays clean: the zone decides *who* may collect, the product rule decides *what* may be collected.

The same split applies to local delivery: a zone of nearby postcodes with a delivery method, plus product rules for stock that cannot go on your own van.

Test checklist

  1. No-pickup product alone — pickup is gone.
  2. Normal product alone — pickup is back.
  3. Both together — matches the mixed-cart rule you chose.
  4. Pickup-only product alone — only pickup remains.
  5. Pickup-only plus no-pickup — a clear notice, never an empty rate list.
  6. An out-of-zone address — pickup absent because of the zone, not the rule.

Check the cart page and the checkout, in both the classic and block-based versions, and place one live order through pickup so the confirmation email and order status read the way you expect.

FAQ

How do I hide local pickup for one product in WooCommerce?
Filter woocommerce_package_rates, check whether the package contains that product, and unset the local_pickup rate when it does. A shipping rules plugin does the same from a setting instead of code.
How do I make some products local pickup only?
Invert the rule: when the flagged product is in the cart, remove every rate whose ID does not start with local_pickup. Keep a cart notice explaining why, or customers assume the checkout is broken.
Why is local pickup still showing after I hide it?
WooCommerce caches shipping rates for the session. Empty the cart, or add a version string to your rule so the cached rates are recalculated, then retest.
Can I offer local pickup only for customers near my store?
Yes, put local pickup in a shipping zone limited to your postcodes or region. Zone restrictions handle geography; product rules handle which stock may be collected.
Does hiding local pickup affect the WooCommerce checkout block?
No, it works in both. The block-based cart and checkout render the same calculated shipping rates, so a rate removed on the package rates filter is absent everywhere.

This article is part of our WooCommerce shipping topic hub, where the related plugins and guides live together.

Keep reading