I've got a client with very specific shipping requirements. Essentially, he wants to assign specific shipping costs for every single zone for every single product. Like this:

  • Product A shipping to Canada = $25
  • Product A shipping to Continental US = $40
  • Product A shipping to Alaska and Hawaii = $60
  • Product A shipping to Europe Zone 1 = $100
  • Product A shipping to Europe Zone 2 = $125
  • Product A shipping to Europe Zone 3 = $150
  • Product A shipping to Asia Zone 1 = $200
  • Product A shipping to Asia Zone 2 = $220
  • Product A shipping to Asia Zone 3 = $230

Now multiply this by 25 products. And he wants to be able to change the shipping costs whenever he needs to so it will be essential that he can adjust it from the backend rather than through code.

Any thoughts on this? My initial idea was to use the Default Item Weight Rate option and have each product assigned a weight. Of course, the weight wouldn't reflect the actual weight of the product, it would just be a way of easily adjusting the shipping rate. The problem I see is that adjusting the weight would adjust the shipping cost across all zones rather than just the zone he wants to change.

Is my only option then to create a shipping category for every product and using Category Rate Overrides?

1 Answer 1


Were I doing this, I would create a single (or an entry, or a global I guess) with a table (or maybe Matrix) field that would hold the shipping price chart.

I'd then create a custom shipping plugin in Commerce, that references this data and returns the shipping cost.

This would give a very nice UI for editing the products shipping, and would be a simple plugin to make.

Here's an example function that gets rate from a table:

public function getRatesForZone($zone, $slug){

    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->section = 'freightData';
    $criteria->slug = $slug;

    $ratesTable = $criteria->first();

    $rates = [];
    foreach ($ratesTable->postRates as $row){

            $rates = $row;


    // If we reach here we couldn't find rates, return nothing
    return $rates;


Beyond that you just implement a shipping rule/method - see https://craftcommerce.com/docs/shipping-methods

In this case, a small amount of custom code will give both a better result and better UI I think, rather than trying to shoehorn in to the methods Commerce provides (although note I have not really investigated the Commerce methods much of late - I find custom shipping is usually the more controllable way to go!)

  • The project went on hiatus for a bit but I'm back at it. I ran this by the client but he prefers to go with the shipping categories. But I will keep this solution for other projects. Thanks!
    – Wonko
    Feb 15, 2017 at 15:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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