Need some help with your project? Contact me

Creating a variable (percentage-based) shipping service in Drupal Commerce

In this tutorial you will learn how to create a variable shipping price with Drupal Commerce by calculating the price of the shipping service as a percentage of the total amount of the order. And all this without a single line of code.

So what is the problem? Drupal Commerce comes with a cool module called Commerce Shipping (included in the Commerce Kickstart distro) that allows you to create your own flat rate shipping services.

There is one shipping method available only (flat) but you can create based on that any number of services you want. The problem is that they are all flat. Yes, you can create all sorts of cool calculation rules to use these services depending on the order and stuff, but I had to bang my head against the wall a few times before realizing how to create a service whose price is a percentage of the total order. Not so obvious but I'll guide you through it.

So the first thing you need to do is create a shipping service. Go to admin/commerce/config/shipping and click on Add flat rate service. Give it a name, description and set the Base rate to 0. We will manipulate this value with a Rule in a minute.

After saving, go to admin/commerce/config/shipping/calculation-rules and add a new calculation rule. You'll notice that it already contains the right event for us: Calculating a shipping rate. This puts us in the right scope of the shipping line item. All we need to do is add a condition and two actions.

So first up, add a condition called Text comparison. In the Text Data selector, paste the following: commerce-line-item:line-item-label or navigate until you reach the equivalent. In the Matching Text Value field, type in the name of the shipping service you created eariler. And you can leave the rest as is. So what does this condition mean? Well, it will only trigger the actions that follow to the shipping service you created so in case the user is presented with a choice of multiple services, the value manipulation will happen only on the one you want. So lets now see the actions.

Add an action of the type: Calculate a value. Under Input value 1 you'll need the following: commerce-line-item:order:commerce-order-total:amount. For the operator select multiplication (*) and set the Input value 2 to 0.something. That is, the number which multiplyed by the total order amount will result in the amount you'd like as the shipping cost. For example, for a shipping price of 20% of the order amount, you'll put 0.2. For 50% it's 0.5. You get it. Then under Provided Variables (the variable in which the result gets stored), specify a name and save the rule action.

Now we can add the second action: Add an amount to the unit price. Under the Line item data selector, specify the following: commerce_line_item. This will perform the addition to our shipping line item we have in scope. Then under the Amount data selector, find the variable in which you stored the calculation in the action above and specify it there. And under the value of the Price Component Type, select the shipping service you created in the beginning. Then it's up to you what you select under Price Rounding Mode (it's quite obvious). And that's it. Save the action and the rule and try it out.

Add some products to the cart, proceed to the checkout and you'll see that the value of this shipping service will be a percentage of the total order amount (percentage that you specified in the rule). And you can even edit the rule further to perform these calculations under all sorts of other conditions - such as if the order value is under/over a particular amount. Or whatever you want.

Hope this helps.

Comments

Thank you for the post, it was very helpful.

Danny, thanks a lot 4 this part: "In the Matching Text Value field, type in the name of the shipping service you created eariler. And you can leave the rest as is. So what does this condition mean? Well, it will only trigger the actions that follow to the shipping service you created so in case the user is presented with a choice of multiple services, the value manipulation will happen only on the one you want."

Hi,

I need to add the shipping value from a calculation rule, without using "Add an amount to the unit price", and add it to the total. I coudn't find an option to add it to the total order, except for the each line item. Please help me.

Use commerce-line-item:commerce-shipping-service instead

The label comparison is fragile if you ever rename the service without thinking.

Use the following two comparisons instead (line item type is "shipping", shipping service is "percentage based"):

Parameter: Data to compare: [commerce-line-item:type], Data value: Shipping
Parameter: Data to compare: [commerce-line-item:commerce-shipping-service, Data value: "NAME OF YOUR SERVICE"]

You will want to add a "Delete all shipping line items from an order" action before the action to calculate the shipping percentage on the calculation rule. Without this, shipping will continue to increase each time a user goes backwards in the checkout workflow (i.e. they click "Back" to go back and edit their addresses, etc).

The target should be "commerce-line-item:order".

Thank you for the tutorial. Everything works fine except for one thing:

commerce-line-item:order:commerce-order-total:amount

This amount includes Tax as well, so the amount of shipping costs isn't correct.

How can i get the tax removed from commerce-line-item:order:commerce-order-total:amount ?

Thank you!!!

Add new comment

You can post comments in Markdown and basic HTML tags.
For code blocks, wrap your code within '~~~'. For example:
~~~
$var = 'my variable';
~~~