Demystifying Ubercart's hook_order

One of the most frustrating things to deal with as a Drupal programmer can be Ubercart. Often, you need to complete a simple task such as sending an additional email, or giving a user a new role, and your options are to use Rules, Conditional Actions or just program it yourself.

Rules or Conditional Actions allow you to execute PHP, but sometimes you don't want to store your php code in an unformatted text field in the database. Enter hook_order(). One of Ubercart's primary hooks for getting stuff done.

According to the api documentation hook_order takes 3 parameters:

$op - The action being performed.
&$arg1 - This is the order object or a reference to it as noted below.
$arg2 - This is variable and will be specified in the table below.

It goes on to describe the different $op that will occur as: new, save, load, submit, can_update, update, can_delete, delete, and total. But what it doesn't tell us is the order of operation, nor how to use this to our benefit.

The following is a table of the important details in an actual order purchased through Ubercart. $arg1 is the actual order, so what we're interested in is the changes in $arg1->order_status.

$op $arg1->order_status $arg2
new in_checkout
presave in_checkout
total in_checkout
load in_checkout
total in_checkout
can_update in_checkout payment_recieved
update in_checkout payment_recieved
load payment_recieved
total payment_recieved
submit in_checkout
load payment_recieved
total payment_recieved
can_update payment_recieved completed
update payment_recieved completed
load completed
total completed

You can see that this hook is called quite often for the $op load and total, as the system applies tax and shipping values to the order total.

In most cases we'll only want our hook to fire once, so we need to find a point within all these hook calls that fits our need. This is easiest by comparing $arg1->order_status to $arg2.

The following code is an example for how to use this to perform some action on completed checkout. In $arg1->products, we have an array of all the products purchased in this order. This is what you want to look at to see if a specific product or type of product was purchased.

/* * Implementation of hook_order() */ function mymodule_order($op, &$arg1, $arg2) { // on the final update do the work we want if ($op == 'update' && $arg1->order_status == "payment_received" && $arg2 == "completed") { // perform some magic, send an email, or something else fancy. } }

Here is a look at the $arg1 object.

$arg1 => stdClass Object ( [order_id] => 29 [uid] => 1 [order_status] => completed [order_total] => 100 [product_count] => 1 [primary_email] => jonathand@websmiths.co [delivery_first_name] => [delivery_last_name] => [delivery_phone] => [delivery_company] => [delivery_street1] => [delivery_street2] => [delivery_city] => [delivery_zone] => 0 [delivery_postal_code] => [delivery_country] => 840 [billing_first_name] => Jonathan [billing_last_name] => Daggerhart [billing_phone] => [billing_company] => websmiths.co [billing_street1] => 123 fake st [billing_street2] => [billing_city] => fakesville [billing_zone] => 44 [billing_postal_code] => 28806 [billing_country] => 840 [payment_method] => credit [data] => Array ( [cc_data] => 6Ap>1O6MYja"Cp,Dk=_^M:![r46RM0pn!vIPr6PnU]kBQBnk"fC.."Z"S7( ;#Kf45h<6v$.dp.:lpV)j3{j-V[%-*69pWn1U*PIB%:ZvXu&>kj= ) [created] => 1317687167 [modified] => 1317687176 [host] => 69.132.183.191 [currency] => USD [products] => Array ( [0] => stdClass Object ( [order_product_id] => 36 [order_id] => 29 [nid] => 41 [title] => $100 Giftcard [manufacturer] => [model] => xyz-giftcard1 [qty] => 1 [cost] => 82.00000 [price] => 100.00000 [weight] => 0 [data] => Array ( [attributes] => Array() [shippable] => 0 [module] => uc_product ) [order_uid] => 1 ) ) [payment_details] => Array ( [cc_number] => 1111 [cc_exp_month] => 1 [cc_exp_year] => 2012 [cc_type] => ) [line_items] => Array ( [0] => Array ( [line_item_id] => subtotal [type] => subtotal [title] => Subtotal [amount] => 100 [weight] => 0 [data] => Array () ) ) )

Hope this helps clarify things for you. Good luck, and happy hook_order-ing.