Skip to content
WooCommerce

How to Apply Multiple Shipping Classes to Variable Products in WooCommerce

· · 11 min read
multiple shipping classes WooCommerce

Managing shipping costs accurately is one of the trickiest parts of running a WooCommerce store. Sell products with multiple variations, different sizes, weights, or materials, and you likely need different shipping rates for each variation. A phone case and a full-size backpack should never ship for the same price, even if they sit on the same product page under the same title. WooCommerce shipping classes let you make that distinction.

This guide walks through setting up multiple shipping classes for variable products in WooCommerce: per-variation shipping class assignment, flat rate configuration, the math behind calculation types, troubleshooting the mistakes that cause wrong charges at checkout, and code snippets for the cases the settings screen can’t handle.

What Are WooCommerce Shipping Classes?

Shipping classes in WooCommerce group products with similar shipping requirements. Each class can carry its own cost rules within a shipping method. You might create a “Lightweight” class for small items and a “Bulky” class for oversized products, each priced differently under the same flat rate method.

Applied to variable products, shipping classes let you charge different shipping rates for each variation of the same item. A small t-shirt and a heavy hoodie can be variations of one product listing while carrying completely different shipping costs at checkout. Without this, you’re stuck picking one shipping price for a product that might range from a few ounces to several pounds depending on which option the customer picks.

Step 1: Create Your Shipping Classes

Before you can assign shipping classes to variations, the classes themselves have to exist.

  1. Go to WooCommerce > Settings > Shipping > Shipping Classes.
  2. Click Add Shipping Class.
  3. Enter a name, “Lightweight,” “Standard,” “Heavyweight,” “Fragile,” whatever maps to how your products actually differ.
  4. Add a slug and a short description for each class.
  5. Click Save Shipping Classes.

Create as many classes as your catalog genuinely needs, not more. Weight-based tiers (under 1kg, 1 to 5kg, over 5kg) work for most physical goods. Handling-based tiers (standard, fragile, oversized) work better if the shipping cost is driven by packaging complexity rather than raw weight, think glassware or furniture versus paperback books.

Step 2: Configure Flat Rate Costs Per Shipping Class

Once the classes exist, you assign a cost to each one inside your shipping zones.

  1. Go to WooCommerce > Settings > Shipping > Shipping Zones.
  2. Edit the zone where the class-based rates should apply.
  3. Click Edit on your Flat Rate shipping method, or add one if you don’t have one yet.
  4. You’ll see a cost field for each shipping class you created: a “Lightweight” class cost (say, 3.00), a “Heavyweight” class cost (say, 12.00), and a “No shipping class cost” field that acts as a fallback for anything unassigned.
  5. Set the Calculation Type. Per class adds up the cost for every distinct shipping class represented in the cart. Per order charges only the single most expensive shipping class cost, regardless of how many classes are actually in the cart.
  6. Click Save Changes.

The calculation type choice matters more than it looks. Say a customer buys one Lightweight item ($3 shipping) and one Heavyweight item ($12 shipping). Under “per class,” WooCommerce charges $3 + $12 = $15. Under “per order,” it charges only $12, the highest single class cost in the cart, and ignores the rest. “Per class” is more accurate for mixed carts but can push shipping costs high enough to scare off a customer who only wanted one heavy item and one cheap add-on. “Per order” simplifies pricing but can undercharge you badly on orders packed with several heavy items, since it never adds those costs together.

There’s no universally correct answer here. A store selling mostly uniform products (all roughly the same weight class) can safely use “per order” without leaving money on the table. A store with a wide spread, say, jewelry alongside furniture, should lean toward “per class” even though it occasionally produces a higher shipping total than a customer expects.

Step 3: Assign Shipping Classes to Product Variations

Now assign the right shipping class to each variation of your variable product.

  1. Go to Products > All Products and edit your variable product.
  2. Scroll to Product Data and click the Variations tab.
  3. Expand each variation with the arrow.
  4. Find the Shipping Class dropdown inside the variation settings.
  5. Select the class for that specific variation.
  6. Click Save Changes, then Update the product.

Important: the parent product’s shipping class acts as the default. A variation left unassigned inherits whatever class sits on the parent product. That inheritance is the single most common source of wrong shipping charges on WooCommerce stores. Always set variation-level classes explicitly instead of relying on the fallback, even when the fallback happens to be correct for most variations. The one variation where it’s wrong is the one that generates the support ticket.

Step 4: Test Your Shipping Setup

Test before going live. Here’s a systematic way to do it rather than clicking around randomly.

  1. Add a lightweight variation to the cart and check the shipping cost at checkout.
  2. Remove it, add a heavyweight variation on its own, and confirm the cost actually changes.
  3. Put both in the same cart and verify the calculation type (per class vs. per order) behaves the way you configured it.
  4. Repeat the test for every shipping zone you have configured, rates that work in one zone sometimes silently fail in another.
  5. Check the edge cases: does a free shipping threshold still apply correctly when a heavyweight item is in the cart? Do coupons interact the way you expect?

Use WooCommerce’s built-in Shipping Calculator on the cart page to check rates without completing a purchase. It’s faster than running a full test order every time you tweak a setting.

Advanced: Per-Variation Shipping With Code

For control the settings screen doesn’t offer, you can programmatically adjust shipping costs based on variation attributes using the woocommerce_package_rates filter:

add_filter( 'woocommerce_package_rates', 'custom_variation_shipping_cost', 10, 2 );
function custom_variation_shipping_cost( $rates, $package ) {
    $has_heavy_item = false;

    foreach ( $package['contents'] as $item ) {
        if ( ! empty( $item['variation_id'] ) ) {
            $variation = wc_get_product( $item['variation_id'] );
            if ( $variation && $variation->get_shipping_class() === 'heavyweight' ) {
                $has_heavy_item = true;
                break;
            }
        }
    }

    if ( $has_heavy_item ) {
        foreach ( $rates as $rate_key => $rate ) {
            if ( 'flat_rate' === $rate->method_id ) {
                $rates[ $rate_key ]->cost += 5.00; // Add surcharge
            }
        }
    }

    return $rates;
}

Drop this into your theme’s functions.php (a child theme, ideally, so a future update doesn’t wipe it out) or a small site-specific plugin. This particular example adds a flat $5 surcharge any time a heavyweight variation lands in the cart, on top of whatever the shipping class already costs. You’d use this pattern for handling fees, oversized-item surcharges, or any rule the built-in settings screen doesn’t expose directly.

Troubleshooting Common Issues

Shipping class dropdown missing on variations

Confirm the product type is actually set to “Variable product” and that you’ve created real variations, not just attributes. Attributes alone don’t generate the variation rows; you need to click “Generate variations” first. The shipping class dropdown only shows up once a variation exists and has been saved at least once.

Wrong shipping cost at checkout

Work through this in order. First, confirm the shipping zone actually matches the customer’s address, a mismatched zone will silently apply the wrong rate table entirely. Second, check that the flat rate method has a cost configured for the specific shipping classes involved, an empty field defaults to zero rather than throwing an error, which is easy to miss. Third, double-check whether calculation type is set to “per class” or “per order,” since this single toggle explains most of the “why is this more expensive than I expected” tickets. Fourth, clear the WooCommerce transient cache under WooCommerce > Status > Tools > Clear transients, since stale shipping rate calculations can persist after a settings change.

Variation inheriting the parent’s shipping class

If a variation shows “Same as parent,” it’s using the parent product’s shipping class rather than one of its own. To override it, select a different class explicitly on that variation. As mentioned above, this inheritance behavior is the most common root cause of incorrect shipping charges on stores with mixed-weight product lines.

Rate not showing at all for a given zone

If a shipping method doesn’t appear at checkout for a zone you expect it to cover, check that the zone’s postal code or region rules actually match the address being tested, and confirm the shipping method itself is enabled (not just configured) within that zone. A method can be fully set up with correct costs and still be toggled off.

How Many Shipping Classes Is Too Many?

There’s a temptation to create a shipping class for every SKU variation you can imagine. Resist it. Every extra class is another cost field you have to fill in correctly across every shipping zone, and a class you forget to price in a new zone just falls back to the default cost, silently.

Three to five classes cover the overwhelming majority of stores. Small and Standard cover most catalogs, with Heavy or Fragile added as a fourth or fifth class only when the products genuinely need it. If you find yourself creating classes named after individual products rather than shipping characteristics, that’s usually a sign you should be adjusting the base shipping method’s cost instead, or switching that one product to its own dedicated shipping method rather than bolting another class onto a system that’s already handling everything else fine.

One mistake shows up constantly on stores that migrated from a different platform: importing dozens of legacy “shipping groups” as WooCommerce shipping classes without consolidating them first. The result is a Flat Rate settings screen with thirty cost fields, most of them zero, and nobody on the team remembers which ones actually matter. Audit your classes every few months. If a class has zero products assigned to it, or the same cost as another class, merge them.

Plugins for Advanced Shipping Class Management

Table Rate Shipping (from WooCommerce.com) lets you define complex rules that combine weight, item count, and shipping class in a single rate table, useful once flat rate per-class pricing stops being granular enough. Extra Flat Rate Shipping, a free WordPress.org plugin, adds multiple flat rate methods with per-class pricing without touching any code. WooCommerce Shipping brings in live carrier rates from USPS and DHL that work alongside your existing shipping classes rather than replacing them.

Pick a plugin based on what your rate structure actually needs, not on feature count. A store with three shipping classes and two zones rarely needs a full rules engine; a store with a dozen classes across multiple countries usually does.

Communicate Shipping Costs Clearly

Clear communication heads off cart abandonment before it happens. Display shipping estimates on the product page itself, not just at checkout. Build a dedicated shipping policy page that explains, in plain language, how rates differ by product type, and use cart notices to tell customers how close they are to a free shipping threshold. None of this changes the underlying shipping class setup, but it determines whether customers trust the number they see at checkout or bail because it feels arbitrary.

A Worked Example: Three Products, Three Weights

Numbers make this concrete. Say you run a home goods store selling candles. The product “Signature Candle” has three variations: a 4oz travel size, an 8oz standard size, and a 16oz jar that ships in its own reinforced box.

You’d set up three shipping classes: Small (4oz), Standard (8oz), and Oversized (16oz jar). Under Flat Rate, Small costs $3.50, Standard costs $5.50, and Oversized costs $9.00, reflecting the actual packaging and carrier cost difference rather than a single blanket rate that overcharges the travel size and undercharges the jar.

A customer who buys one of each, under “per class” calculation, pays $3.50 + $5.50 + $9.00 = $18.00 in shipping. Under “per order,” they pay only $9.00, the single highest class cost, and the other two ship “free” as far as the calculation is concerned. If your actual carrier cost for shipping all three together is closer to $14, then “per order” is quietly costing you money on every mixed cart. This is exactly the kind of gap that only shows up once you compare your WooCommerce shipping charges against your actual carrier invoice at the end of the month, so it’s worth running that comparison at least once before assuming your calculation type is right.

International Shipping Classes

Everything above applies per zone, which means international shipping needs its own pass. A shipping class cost configured for your domestic zone does not carry over to an international zone automatically, you have to open each zone’s Flat Rate method and set the class costs there too. It’s easy to configure domestic rates carefully and then forget international customers entirely, leaving them with a “No shipping class cost” fallback that’s either zero or wildly wrong.

If you ship internationally, budget extra testing time for this specifically. Add a heavyweight variation to the cart, switch the shipping calculator’s address to a country outside your default zone, and confirm the rate that appears actually reflects what you’d pay to ship it there. A rate that looks correct domestically can be silently broken for every country outside your home market.

Frequently Asked Questions

Can a single product have variations across more than two shipping classes?

Yes. Each variation is independent and can be assigned any shipping class you’ve created, there’s no limit tied to the parent product. A shirt with five sizes could theoretically use three different classes if, say, the largest sizes ship in a bigger box.

Do shipping classes affect tax calculation?

No. Shipping classes only control shipping cost. Tax is calculated separately based on your tax settings and the customer’s location, and shipping classes have no direct bearing on it, though shipping itself may or may not be taxable depending on your jurisdiction and your WooCommerce tax settings.

What happens if I delete a shipping class that’s still assigned to variations?

Those variations fall back to “No shipping class,” which uses whatever fallback cost you’ve configured (often zero, if you never set one). Before deleting a class, reassign any variations using it, or you risk quietly shipping items for free.

Can I set a shipping class cost that varies by shipping zone?

Yes, and this is worth doing deliberately. Shipping class costs are configured per zone, not globally, so a heavyweight item can cost $12 to ship domestically and $35 internationally simply by setting different values on the Flat Rate method inside each zone’s configuration.

Does the shipping class affect which carrier gets used?

Not directly. Shipping classes only feed into cost calculation for methods like Flat Rate. If you’re using a live-rate plugin that pulls quotes from USPS, UPS, or DHL, the carrier selection and box-size logic in that plugin is usually separate from WooCommerce’s native shipping class system, though many live-rate plugins let you map shipping classes to package dimensions as an input into their own rate request.

Why does my shipping class cost show as $0.00 even though I entered a number?

Check that you clicked Save Changes on the shipping method itself, not just the shipping zone. It’s a common miss, especially on stores managed by more than one person, where a change gets typed into the field and the page gets navigated away from before the save actually registers.


How to Set Quantity Limits for Each Product Variation in WooCommerce

Schema Markup for WooCommerce Products