I'm trying to construct a shipping module for UK's Royal Mail (or at least the parts I need right now...!). I've written PHP code for calculating what methods are applicable based on shipping address and weight, but plumbing this logic into my site is eluding me. I should add that, as Royal Mail doesn't have an API for pricing, my module bundles the rate-tables for the various methods/services (CSV format) so I need to use code, not Rules, to implement it.

It seems the way to do this is to use the hook_commerce_shipping_* hooks, but it doesn't appear that I'm doing so correctly.

This is my first experience with using hooks (and Drupal on a serious dev level, TBH) but I have successfully implemented hook_commerce_cart_product_prepare() in another custom module, so I think what I'm doing should be working. In my module I wrote the following, just to test that I'd successfully implemented the hook:

 * Implements hook_commerce_shipping_calculate_rate()
function royalmail_commerce_shipping_calculate_rate($line_item) {
    drupal_set_message(print_r($line_item, TRUE),'error');

...and it seems I hadn't, because the message never appeared when I progressed to the shipping pane of the checkout.

I also tried various other "canaries" I should be able to spot evidence of, including but not limited to drupal_exit(), echo, die(), var_dump() and so on, but nothing appears. Same story for hook_commerce_shipping_collect_rates(), which I actually tried to implement first but ended up doing so with Rules instead while I was scratching my head (though I'd prefer this be in native code too, ideally).

Am I doing it wrong? Thanks in advance.


It looks like you are using commerce shipping 2.x which differs a lot from 1.x in terms of integration.

What you need to do is:

  1. Define a shipping method, use hook_commerce_shipping_method_info.
  2. Define one or more shipping services use hook_commerce_shipping_service_info
  3. When you define the shipping services, you can select a rate callback, if none is selected, commerce shipping will by default try to use SERVICE_NAME_rate, where SERVICE_NAME is the keyed name used in the hook_commerce_shipping_service_info hook. The rate callback have this signature:

    function service_name_rate($shipping_service, $order) {
      // Logic here.
      return array(
        'amount' => $amount,
        'currency_code' => $currency_code,
        'data' => array(),

You can look at the example module within the commerce shipping module which serves as documentation, or you can look at some of the other shipping methods, like UPS.

  • Thanks googletorp, I never even noticed the example module tucked in there! Your answer has me on the right track, but can I ask one subsidiary question: Is the function where I implement hook_commerce_shipping_service_info() the appropriate place to choose only the applicable service(s) for an order? Or can the SERVICE_NAME_rate() function(s) return NULL, FALSE or something similar to indicate the service cannot be offered on that order?
    – Headbank
    Feb 23 '13 at 16:13
  • Just to add, I'm still having no success implementing the hooks I mentioned above, nor hook_commerce_shipping_service_rate_options_alter() (which I now think might be the answer to the above). Can I trace/debug these hooks somehow?
    – Headbank
    Feb 23 '13 at 20:47
  • Answering my own comment, yes the rate callback function can return FALSE to prevent that service being added as an option.
    – Headbank
    Feb 24 '13 at 16:31
  • However I'm still at a loss with the hooks, which (despite my cack-handed phrasing) is what I'm really interested in. What do I actually have to do to implement hook_commerce_shipping_method_collect_rates()? Without this, I'm apparently stuck putting most of my code in the rate callback function, per-service, which is horrendously inefficient. Neither the example nor UPS modules address this.
    – Headbank
    Feb 24 '13 at 16:41
  • @Headbank The comment thread is not a good place for Q&A. For help on hooks, see the api.php file. Returning FALSE in the rate callback should only be used if the service is unable to calculate the rate, fx weight based quote but the products have no weight defined. For the most part you should use rules to setup when the shipping service is available.
    – googletorp
    Feb 25 '13 at 10:08

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.