Is there a way to change the order of the shipping services? I have several flat rate services and i'd like to change the order.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

googletorp’s picture

Are you talking about the order in the backend?

googletorp’s picture

Are you talking about the order in the backend?

BWPanda’s picture

Version: 7.x-2.0-beta1 » 7.x-2.x-dev

I too would like the ability to change the order the shipping services appear in on the checkout form.

I have two shipping options, standard and express. As the standard option is cheaper, I'd like it to appear first as the default, but it seems they're listed in alphabetical order and so standard appears last...

Adding those drag 'n drop weight things (found on most other Drupal forms) to the form from the screenshot above would be perfect.

googletorp’s picture

Status: Active » Postponed (maintainer needs more info)

Have you tried using the rules weight system to do sorting?

BWPanda’s picture

Status: Postponed (maintainer needs more info) » Active

I looked for some weights in Rules to change originally (and again just now), but I can't seem to find anything... There's only one Rule for shipping, and the two shipping services (express and standard) are implemented as Rules Components which don't have weights...

Could you help point me in the right direction?

googletorp’s picture

Assigned: Unassigned » rszrama

Sounds like this is a flaw in the way the 2.x branch has organized the Rules, since this is possible in the 1.x. I'll assign Ryan to this, since he made the most of this and knows why it was built the way it was.

Summit’s picture

Hi,
What I can see that the services are placed in alphabet from a-z as a workaround for now.
Off course +1 for Weight possibility on Shipping Services!

Greetings, Martijn

FAAREIA’s picture

Hi people, if anyone has large amount of services here is a link to make them in a select box. Plus an incomplete (i'm not a programmer so i can't figure it out how to complete the sort function) code of a callback sort function.

rszrama’s picture

Component: User interface » Code
Assigned: rszrama » Unassigned
Category: support » feature

As with the core Tax module, the Shipping 2.x branch abstracts the calculation of shipping services for an order through a single rule with an action that collects all the available rates for services of each method. If you look at your Rules list, you'll see the Collect rates: [Shipping method] rules in there for each shipping method module you've enabled. The action on that rule will loop over all shipping services for the given method and manually execute the rule components for each one to determine if it should be on the order or not. Inside that action, we can't change the execution order of components, as they're governed by the service's weight, but what could happen is you simply remove the default action and replace it with the necessary actions to manually call your various service rules components.

That said, on testing, it didn't matter if I split it out, flat rate services were still ordered alphabetically. What we could do is change the checkout form code to respect the order these things were added to the array, but I'm not sure that's the easiest solution. It seems it would be easier to add a "sort order" weight to flat rate services, which would be a simple feature request to that module rather than something the Shipping module itself needs to take care of. Perhaps a hybrid approach would be the best, as it would be most flexible.

So the task for this issue:

Update the checkout pane so it displays shipping services in the order in which they were added to the order's data array.

juan.pompa’s picture

Ryan,

I agree with you. We have the same problem here, as we have 7 different shipping services. Adding a sort order "weight" to flat rate services would be very helpfull. It would allow to present them to the client in a particular order.

Thanks a lot for your work. There are many of us using your insights and comments.

Cheers.
juan

olegel’s picture

Hi, guys!
I have faced with the same problem, that I couldn't sort shipping services in the way Id like to. I've read all above comments and didn't understand clearly what means update checkout pane (what to change there). Then I started to experiment and I found out the order is being changed if to write machine names of the shipping services in alphabetical order. So I deleted all my services and added them again with respect to machine's names alphabetical order. I had to delete them first since I couldnt edit machine names. So it can help to those who cant programm and write sorting functions!

kingandy’s picture

Project: Commerce Shipping » Commerce Flat Rate
Version: 7.x-2.x-dev » 7.x-1.x-dev

By the time the shipping services are passed to hook_commerce_shipping_service_info_alter, they have been assigned a 'weight' property. This weight appears to be based solely on the order the various modules return their methods (commerce_shipping_services() steps through each module that implements the hook, then each of the shipping services, and sets each weight to "$weight++"). I guess this means the 'Commerce Shipping' part of this issue, as described by Ryan in #9 above, is complete. I'm moving it over to Commerce Flat Rate so we can actually tackle the issue eswiderski originally raised.

FWIW it looks like this should be fairly trivial - just add a 'weight' integer field to the commerce_flat_rate_service table, create some way of editing those weights (either on individual forms or using the tabledrag method), and respect those weights inside the commerce_flat_rate_commerce_shipping_service_info function instead of just 'SELECT * FROM {commerce_flat_rate_service}'.

In the meantime I've used this hook to re-order my shipping rates manually by simply overriding the weight property:

/**
 * Implements hook_commerce_shipping_service_info_alter().
 */
function mymodule_commerce_shipping_service_info_alter(&$shipping_services) {
  if (isset($shipping_services['my_flat_rate'])) {
    $shipping_services['my_flat_rate']['weight'] = -10;
  }
}
Memes11’s picture

what if we have more than 20 rates? how to order them properly as weight is only from -10 to 10.

I have many shipment rates as there is no module (known to me) for HK post and I am setting up a shop for worldwide shipment and the weight base rule is not suitable, I end up having one rate for each country and each 500g section from 0 to 20kg. I do not want to take any shortcut as I do not want my customer to get over charged for transportation.

Thanks

rszrama’s picture

In that case you'd need to alter them via code I suppose. Weights don't have to be integers, but only integers can be set via the UI.

maxchock’s picture

i am also in the middle of the limitation. I need to run a Shipping calculation after another 2 shipping calculation..

Infinitee’s picture

kingandy, where exactly did you add the hook?

Thanks,

Update: I really don't like hacking modules but, to get my preferred shipping set as the selected default, I added: 'weight' => -10, to line 70 of...

\profiles\commerce_kickstart\profiles\commerce_kickstart\modules\commerce_kickstart\commerce_kickstart_product\commerce_kickstart_product.features.inc

Of coarse this only works for Commerce Kickstart but, you can search your flat rate module for express_shipping to find what you may be looking for.

marktheshark’s picture

+1 for being able to reorder within flat shipping rates. I currently have premium listed before standard shipping which is quite inconvenient for the visitor...

kingandy’s picture

@Infinitee, I think I made a new module just to introduce the hook. Either that or I used an existing custom "site-specific utilities" type of module...

iwant2fly’s picture

This seems to be an issue for the FedEx shipping module as well (http://drupal.org/node/1955574) It seems to me that this ability to sort the displayed rates by price should probably be a feature in the overall Commerce Shipping module rather than in some of the various shipping method modules. Thoughts?

marktheshark’s picture

Used the approach in #13 as well, thanks for sharing!

mesch’s picture

As I see it there are two distinct goals discussed in this thread:

1. Sort services by name.
2. Sort services by price.

The two don't necessarily work together, since in many cases the rates depend on the order contents.

iwant2fly (post #20) sponsored a solution to #2. I'm posting it here for feedback and in case it is of use to others. In words the approach is to fetch the rates from the $order object, and then use that array to sort the $options displayed on the checkout pane.

/**
 * Implements hook_commerce_shipping_service_rate_options_alter()
 */
function [module_name]_commerce_shipping_service_rate_options_alter(&$options, $order) {
	// If there is more than one shipping service available, sort them by line item unit price
	if (count($order->shipping_rates) > 1) {
		// Collect rates from line items
		$service_prices = array();
		foreach ($order->shipping_rates as $service => $line_item) {
			$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
			$unit_price = $line_item_wrapper->commerce_unit_price->value();
		  $service_prices[$service] = $unit_price['amount'];
		}

		// array_multisort can be used here because $options and $order->shipping_rates contain the same number of elements (i.e. services).
		array_multisort($service_prices, SORT_NUMERIC, SORT_ASC, $options);
	}
}

This could be integrated into the commerce shipping module by adding a toggle switch somewhere in the UI to turn this sorting on/off.

2ndmile’s picture

Issue summary: View changes

Nice one MEsch. Exactly what I was looking for.

mengi’s picture

#22 Works for me. Using only Flat Rate shipping services, and shipping options are listed by price now.

Being able to assign weights to the shipping options would definitely give greater control but ultimately I simply wanted the options ordered by price so I think this is a great solution.

MrPeanut’s picture

#22 is working for me as well. I would second the request to assign weights for more control. (In my case, I'd like to show all USPS options first, sorted by price, then all UPS options, sorted by price.)

frost’s picture

no. 22 works for me, thanks!

lukasss’s picture

hook_form_alter

$form['commerce_shipping']['shipping_service']['shipping_1']['#weight'] = 0;
$form['commerce_shipping']['shipping_service']['shipping_2']['#weight'] = 1;

ShaneOnABike’s picture

I think that adding the above feature is pretty important. It makes it easier for the person (user) to recognize what price is what.. it's a bit all over the place right now with all the shipping items listed one after another (unless you have a favourite provider I can't see any reason to do it without sorting by price)

fhdrupal’s picture

My problem is not exactly the same but somehow similar, if anyone have any idea, can share with me please.
Basically I need a condition in the calculation rules by product weight, to get the whole cart/order products weight and to compare it with maximum weight this rules is valid for. If the weight exceeds the limit, change shipping service.

Thanks in advance,

lukasss’s picture

You can this through hook_form_alter. There you have to write your code and starting from change weight:

$form['commerce_shipping']['shipping_service']['shipping_1']['#weight'] = 0;
$form['commerce_shipping']['shipping_service']['shipping_2']['#weight'] = 1;

Sorry for bad england

faerykisses’s picture

hi,

Has any progress been made with this issue? i am unsure where to implement the code in #22 as I am new to coding and drupal commerce . This issue however is causing me issues in that people keep choosing the most expensive option as default.

Many thanks
Trixie

heyehren’s picture

No 22 works for me. Thanks to mesch

kevster’s picture

Excellent - #22 works for, many thx @mesch

merauluka’s picture

Mine is similar to #22, but I added an additional "multiplier" to my function to force International options to the bottom of the list.

/**
 * Implements hook_commerce_shipping_service_info_alter().
 * Reweight the shipping options so:
 * 1) Non-international methods appear first.
 * 2) The lowest cost options are shown first.
 */
function CUSTOM_MODULE_commerce_shipping_service_info_alter(&$shipping_services) {
  $shipping_weight = array();
  foreach ($shipping_services as $key => $row) {
    $shipping_weight[$key] = $shipping_services[$key]['base_rate']['amount'];
    // Default multiplier is 1.
    $multiplier = 1;
    // Compute the weight based on the cost of the service in dollars.
    $weight = round($shipping_weight[$key] / 100);
    if (strpos($key, "international") !== FALSE) {
      // Add a multiplier to international methods so they float to the bottom.
      $multiplier = 100;
    }
    // Set the weight on the shipping service.
    $shipping_services[$key]['weight'] = $weight * $multiplier;
  }
  // Sort the output array using our newly set weights
  array_multisort($shipping_weight, SORT_DESC, $shipping_services);
}

  • rszrama committed b667d27 on 7.x-1.x
    Issue #1537394 by rszrama: add a weight column to flat rate services...
rszrama’s picture

Status: Active » Fixed

I had a need for this (combined with adding support for a default value), so I implemented it via a simple weight column on the commerce_flat_rate_service table that turns into the $service['weight'] property on load. Sorry it took so long to get this in. :-/

Commit diff: http://cgit.drupalcode.org/commerce_flat_rate/diff/?id=b667d27

Khumbu’s picture

kudos...works like a charm...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

kevster’s picture

Good stuff - #22 worked a treat for me with a custom shipping module too - still ordered by price which is just what I wanted.