You are here

hooks.php in Ubercart 5

Same filename and directory in other branches
  1. 6.2 docs/hooks.php

These are the hooks that are invoked by the Übercart core.

Core hooks are typically called in all modules at once using module_invoke_all().

File

docs/hooks.php
View source
<?php

/**
 * @file
 * These are the hooks that are invoked by the Übercart core.
 *
 * Core hooks are typically called in all modules at once using
 * module_invoke_all().
 */

/**
 * @addtogroup hooks
 * @{
 */

/**
 * Do extra processing when an item is added to the shopping cart.
 *
 * Some modules need to be able to hook into the process of adding items to a
 * cart. For example, an inventory system may need to check stock levels and
 * prevent an out of stock item from being added to a customer's cart. This hook
 * lets developers squeeze right in at the end of the process after the product
 * information is all loaded and the product is about to be added to the cart.
 * In the event that a product should not be added to the cart, you simply have
 * to return a failure message described below. This hook may also be used simply
 * to perform some routine action when products are added to the cart.
 *
 * @param $nid
 *   The node ID of the product
 * @param $qty
 *   The quantity being added
 * @param $data
 *   The data array, including attributes and model number adjustments
 * @return
 *   The function can use this data to whatever purpose to see if the item can
 *   be added to the cart or not. The function should return an array containing
 *   the result array. (This is due to the nature of Drupal's module_invoke_all()
 *   function. You must return an array within an array or other module data will
 *   end up getting ignored.) At this moment, there are only three keys:
 *   - "success": TRUE or FALSE for whether the specified quantity of the item
 *       may be added to the cart or not; defaults to TRUE.
 *   - "message": the fail message to display in the event of a failure; if
 *       omitted, Ubercart will display a default fail message.
 *   - "silent": return TRUE to suppress the display of any messages; useful
 *       when a module simply needs to do some other processing during an add to
 *       cart or fail silently.
 */
function hook_add_to_cart($nid, $qty, $data) {
  if ($qty > 1) {
    $result[] = array(
      'success' => FALSE,
      'message' => t('Sorry, you can only add one of those at a time.'),
    );
  }
  return $result;
}

/**
 * Add extra information to a cart item's "data" array.
 *
 * This is effectively the submit handler of any alterations to the Add to Cart
 * form. It provides a standard way to store the extra information so that it
 * can be used by hook_add_to_cart().
 *
 * @param $form_values
 *   The values submitted to the Add to Cart form.
 * @return
 *   An array of data to be merged into the item added to the cart.
 */
function hook_add_to_cart_data($form_values) {
  $node = node_load($form_values['nid']);
  return array(
    'module' => 'uc_product',
    'shippable' => $node->shippable,
  );
}

/**
 * Calculate tax line items for an order.
 *
 * @param $order
 *   An order object or an order id.
 * @return
 *   An array of tax line items keyed by a module-specific id.
 */
function hook_calculate_tax($order) {
  global $user;
  if (is_numeric($order)) {
    $order = uc_order_load($order);
    $account = user_load(array(
      'uid' => $order->uid,
    ));
  }
  else {
    if ((int) $order->uid) {
      $account = user_load(array(
        'uid' => intval($order->uid),
      ));
    }
    else {
      $account = $user;
    }
  }
  if (!is_object($order)) {
    return array();
  }
  if (empty($order->delivery_postal_code)) {
    $order->delivery_postal_code = $order->billing_postal_code;
  }
  if (empty($order->delivery_zone)) {
    $order->delivery_zone = $order->billing_zone;
  }
  if (empty($order->delivery_country)) {
    $order->delivery_country = $order->billing_country;
  }
  if (is_array($order->line_items)) {
    foreach ($order->line_items as $i => $line) {
      if (substr($line['type'], 0, 4) == 'tax_' && substr($line['type'], 5) != 'subtotal') {
        unset($order->line_items[$i]);
      }
    }
  }
  $_SESSION['taxes'] = array();
  $taxes = uc_taxes_get_rates();
  foreach ($taxes as $tax) {

    // Gotta pass a fake line_item entity for the data to be saved to $_SESSION.
    workflow_ng_invoke_event('calculate_tax_' . $tax->id, $order, $tax, $account, array());

    //$order->line_items[] = array('type' => 'tax', 'amount' => $_SESSION['taxes'][$tax->id]['amount']);
  }
  $order->taxes = $_SESSION['taxes'];
  unset($_SESSION['taxes']);

  //array_unshift($order->taxes, array('id' => 'subtotal', 'name' => t('Subtotal excluding taxes'), 'amount' => $amount, 'weight' => -10));
  return $order->taxes;
}

/**
 * Control the display of an item in the cart.
 *
 * Product type modules allow the creation of nodes that can be added to the
 * cart. The cart determines how they are displayed through this hook. This is
 * especially important for product kits, because it may be displayed as a single
 * unit in the cart even though it is represented as several items.
 *
 * @param $item
 *   The item in the cart to display.
 * @return
 *   A form array containing the following elements:
 *   - "nid"
 *     - #type: value
 *     - #value: The node id of the $item.
 *   - "module"
 *     - #type: value
 *     - #value: The module implementing this hook and the node represented by
 *       $item.
 *   - "remove"
 *     - #type: checkbox
 *     - #value: If selected, removes the $item from the cart.
 *   - "options"
 *     - #type: markup
 *     - #value: Themed markup (usually an unordered list) displaying extra information.
 *   - "title"
 *     - #type: markup
 *     - #value: The displayed title of the $item.
 *   - "#total"
 *     - "type": float
 *     - "value": Numeric price of $item. Notice the '#' signifying that this is
 *       not a form element but just a value stored in the form array.
 *   - "data"
 *     - #type: hidden
 *     - #value: The serialized $item->data.
 *   - "qty"
 *     - #type: textfield
 *     - #value: The quantity of $item in the cart. When "Update cart" is clicked,
 *         the customer's input is saved to the cart.
 */
function hook_cart_display($item) {
  $node = node_load($item->nid);
  $element = array();
  $element['nid'] = array(
    '#type' => 'value',
    '#value' => $node->nid,
  );
  $element['module'] = array(
    '#type' => 'value',
    '#value' => 'uc_product',
  );
  $element['remove'] = array(
    '#type' => 'checkbox',
  );
  $op_names = '';
  if (module_exists('uc_attribute')) {
    $op_names = "<ul class=\"cart-options\">\n";
    foreach ($item->options as $option) {
      $op_names .= '<li>' . $option['attribute'] . ': ' . $option['name'] . "</li>\n";
    }
    $op_names .= "</ul>\n";
  }
  $element['options'] = array(
    '#value' => $op_names,
  );
  $element['title'] = array(
    '#value' => l($node->title, 'node/' . $node->nid),
  );
  $element['#total'] = $item->price * $item->qty;
  $element['data'] = array(
    '#type' => 'hidden',
    '#value' => serialize($item->data),
  );
  $element['qty'] = array(
    '#type' => 'textfield',
    '#default_value' => $item->qty,
    '#size' => 3,
    '#maxlength' => 3,
  );
  return $element;
}

/**
 * Add extra data about an item in the cart.
 *
 * Products that are added to a customer's cart are referred as items until the
 * sale is completed. Just think of a grocery store having a bunch of products
 * on the shelves but putting a sign over the express lane saying "15 Items or
 * Less." hook_cart_item() is in charge of acting on items at various times like
 * when they are being added to a cart, saved, loaded, and checked out.
 *
 * Here's the rationale for this hook: Products may change on a live site during
 * a price increase or change to attribute adjustments. If a user has previously
 * added an item to their cart, when they go to checkout or view their cart
 * screen we want the latest pricing and model numbers to show. So, the essential
 * product information is stored in the cart, but when the items in a cart are
 * loaded, modules are given a chance to adjust the data against the latest settings.
 *
 * @param $op
 *   The action that is occurring. Possible values:
 *   - "load" - Passed for each item when a cart is being loaded in the function
 *       uc_cart_get_contents(). This gives modules the chance to tweak information
 *       for items when the cart is being loaded prior to being view or added to
 *       an order. No return value is expected.
 *   - "can_ship" - Passed when a cart is being scanned for items that are not
 *       shippable items. Übercart will bypass cart and checkout operations
 *       specifically related to tangible products if nothing in the cart is
 *       shippable. hook_cart_item functions that check for this op are expected
 *       to return TRUE or FALSE based on whether a product is shippable or not.
 * @return
 *   No return value for load.
 *   TRUE or FALSE for can_ship.
 */
function hook_cart_item($op, &$item) {
  switch ($op) {
    case 'load':
      $term = array_shift(taxonomy_node_get_terms_by_vocabulary($item->nid, variable_get('uc_manufacturer_vid', 0)));
      $arg1->manufacturer = $term->name;
      break;
  }
}

/**
 * Register callbacks for a cart pane.
 *
 * The default cart view page displays a table of the cart contents and a few
 * simple form features to manage the cart contents. For a module to add
 * information to this page, it must use hook_cart_pane to define extra panes
 * that may be ordered to appear above or below the default information.
 *
 * @param $items
 *   The current contents of the shopping cart.
 * @return
 *   The function is expected to return an array of pane arrays with the following
 *   keys:
 *   - "id"
 *     - type: string
 *     - value: The internal ID of the pane, using a-z, 0-9, and - or _.
 *   - "title"
 *     - type: string
 *     - value: The name of the cart pane displayed to the user.  Use t().
 *   - "enabled"
 *     - type: boolean
 *     - value: Whether the pane is enabled by default or not. (Defaults to TRUE.)
 *   - "weight"
 *     - type: integer
 *     - value: The weight of the pane to determine its display order. (Defaults
 *         to 0.)
 *   - "body"
 *     - type: string
 *     - value: The body of the pane when rendered on the cart view screen.
 *
 * The body gets printed to the screen if it is on the cart view page.  For the
 * settings page, the body field is ignored.  You may want your function to check
 * for a NULL argument before processing any queries or foreach() loops.
 */
function hook_cart_pane($items) {
  $panes[] = array(
    'id' => 'cart_form',
    'title' => t('Default cart form'),
    'enabled' => TRUE,
    'weight' => 0,
    'body' => !is_null($items) ? drupal_get_form('uc_cart_view_form', $items) : '',
  );
  return $panes;
}

/**
 * Register callbacks for a checkout pane.
 *
 * The checkout screen for Ubercart is a compilation of enabled checkout panes.
 * A checkout pane can be used to display order information, collect data from
 * the customer, or interact with other panes. Panes are defined in enabled modules
 * with hook_checkout_pane() and displayed and processed through specified callback
 * functions. Some of the settings for each pane are configurable from the checkout
 * settings page with defaults being specified in the hooks.
 *
 * The default panes are defined in uc_cart.module in the function
 * uc_cart_checkout_pane(). These include panes to display the contents of the
 * shopping cart and to collect essential site user information, a shipping address,
 * a payment address, and order comments. Other included modules offer panes for
 * shipping and payment purposes as well.
 *
 * @return
 *   An array of checkout pane arrays using the following keys:
 *   - "id"
 *     - type: string
 *     - value: The internal ID of the checkout pane, using a-z, 0-9, and - or _.
 *   - "title"
 *     - type: string
 *     - value:The name of the pane as it appears on the checkout form.
 *   - "desc"
 *     - type: string
 *     - value: A short description of the pane for the admin pages.
 *   - "callback"
 *     - type: string
 *     - value: The name of the callback function for this pane.  View
 *         @link http://www.ubercart.org/docs/developer/245/checkout this page @endlink
 *         for more documentation and examples of checkout pane callbacks.
 *   - "weight"
 *     - type: integer
 *     - value: Default weight of the pane, defining its order on the checkout form.
 *   - "enabled"
 *     - type: boolean
 *     - value: Optional. Whether or not the pane is enabled by default. Defaults
 *         to TRUE.
 *   - "process"
 *     - type: boolean
 *     - value: Optional. Whether or not this pane needs to be processed when the
 *         checkout form is submitted. Defaults to TRUE.
 *   - "collapsible"
 *     - type: boolean
 *     - value: Optional. Whether or not this pane is displayed as a collapsible
 *         fieldset. Defaults to TRUE.
 */
function hook_checkout_pane() {
  $panes[] = array(
    'id' => 'cart',
    'callback' => 'uc_checkout_pane_cart',
    'title' => t('Cart Contents'),
    'desc' => t("Display the contents of a customer's shopping cart."),
    'weight' => 1,
    'process' => FALSE,
    'collapsible' => FALSE,
  );
  return $panes;
}

/**
 * Give clearance to a user to download a file.
 *
 * By default the uc_file module can implement 3 restrictions on downloads: by
 * number of IP addresses downloaded from, by number of downloads, and by a set
 * expiration date. Developers wishing to add further restrictions can do so by
 * implementing this hook. After the 3 aforementioned restrictions are checked,
 * the uc_file module will check for implementations of this hook.
 *
 * @param $user
 *   The drupal user object that has requested the download
 * @param $file_download
 *   The file download object as defined as a row from the uc_file_users table
 *   that grants the user the download
 * @return
 *   TRUE or FALSE depending on whether the user is to be permitted download of
 *   the requested files. When a implementation returns FALSE it should set an
 *   error message in Drupal using drupal_set_message() to inform customers of
 *   what is going on.
 */
function hook_download_authorize($user, $file_download) {
  if (!$user->status) {
    drupal_set_message(t("This account has been banned and can't download files anymore. "), 'error');
    return FALSE;
  }
  else {
    return TRUE;
  }
}

/**
 * Perform actions on file products.
 *
 * The uc_file module comes with a file manager (found at Administer » Store
 * administration » Products » View file downloads) that provides some basic
 * functionality: deletion of multiple files and directories, and upload of single
 * files (those looking to upload multiple files should just directly upload them
 * to their file download directory then visit the file manager which automatically
 * updates new files found in its directory). Developers that need to create more
 * advanced actions with this file manager can do so by using this hook.
 *
 * @param $op
 *   The operation being taken by the hook, possible ops defined below.
 *   - 'info': Called before the uc_file module builds its list of possible file
 *       actions. This op is used to define new actions that will be placed in
 *       the file action select box.
 *   - 'insert': Called after uc_file discovers a new file in the file download
 *       directory.
 *   - 'form': When any defined file action is selected and submitted to the form
 *       this function is called to render the next form. Because this is called
 *       whenever a module-defined file action is selected, the variable
 *       $args['action'] can be used to define a new form or append to an existing
 *       form.
 *   - 'upload': After a file has been uploaded, via the file manager's built in
 *       file upload function, and moved to the file download directory this op
 *       can perform any remaining operations it needs to perform on the file
 *       before its placed into the uc_files table.
 *   - 'upload_validate': This op is called to validate the uploaded file that
 *       was uploaded via the file manager's built in file upload function. At
 *       this point, the file has been uploaded to PHP's temporary directory.
 *       Files passing this upload validate function will be moved into the file
 *       downloads directory.
 *   - 'validate': This op is called to validate the file action form.
 *   - 'submit': This op is called to submit the file action form.
 * @param $args
 *   A keyed array of values that varies depending on the op being performed,
 *   possible values defined below.
 *   - 'info': None
 *   - 'insert':
 *     - 'file_object': The file object of the newly discovered file
 *   - 'form':
 *     - 'action': The file action being performed as defined by the key in the
 *         array sent by hook_file_action($op = 'info')
 *     - 'file_ids' - The file ids (as defined in the uc_files table) of the
 *          selected files to perform the action on
 *   - 'upload':
 *     - 'file_object': The file object of the file moved into file downloads
 *         directory
 *     - 'form_id': The form_id variable of the form_submit function
 *     - 'form_values': The form_values variable of the form_submit function
 *   - 'upload_validate':
 *     - 'file_object': The file object of the file that has been uploaded into
 *         PHP's temporary upload directory
 *     - 'form_id': The form_id variable of the form_validate function
 *     - 'form_values': The form_values variable of the form_validate function
 *   - 'validate':
 *     - 'form_id': The form_id variable of the form_validate function
 *     - 'form_values': The form_values variable of the form_validate function
 *   - 'submit':
 *     - 'form_id': The form_id variable of the form_submit function
 *     - 'form_values': The form_values variable of the form_submit function
 * @return
 *   The return value of hook depends on the op being performed, possible return
 *   values defined below.
 *   - 'info': The associative array of possible actions to perform. The keys are
 *       unique strings that defines the actions to perform. The values are the
 *       text to be displayed in the file action select box.
 *   - 'insert': None
 *   - 'form': This op should return an array of drupal form elements as defined
 *       by the drupal form API.
 *   - 'upload': None
 *   - 'upload_validate': None
 *   - 'validate': None
 *   - 'submit': None
 */
function hook_file_action($op, $args) {
  switch ($op) {
    case 'info':
      return array(
        'uc_image_watermark_add_mark' => 'Add Watermark',
      );
    case 'insert':

      //automatically adds watermarks to any new files that are uploaded to the file download directory
      _add_watermark($args['file_object']->filepath);
      break;
    case 'form':
      if ($args['action'] == 'uc_image_watermark_add_mark') {
        $form['watermark_text'] = array(
          '#type' => 'textfield',
          '#title' => t('Watermark Text'),
        );
        $form['submit_watermark'] = array(
          '#type' => 'submit',
          '#value' => t('Add Watermark'),
        );
      }
      return $form;
    case 'upload':
      _add_watermark($args['file_object']->filepath);
      break;
    case 'upload_validate':

      //Given a file path, function checks if file is valid JPEG
      if (!_check_image($args['file_object']->filepath)) {
        form_set_error('upload', t('Uploaded file is not a valid JPEG'));
      }
      break;
    case 'validate':
      if ($args['form_values']['action'] == 'uc_image_watermark_add_mark') {
        if (empty($args['form_values']['watermark_text'])) {
          form_set_error('watermar_text', t('Must fill in text'));
        }
      }
      break;
    case 'submit':
      if ($args['form_values']['action'] == 'uc_image_watermark_add_mark') {
        foreach ($args['form_values']['file_ids'] as $file_id) {
          $filename = db_result(db_query("SELECT filename FROM {uc_files} WHERE fid = %d", $file_id));

          //Function adds watermark to image
          _add_watermark($filename);
        }
      }
      break;
  }
}

/**
 * Make changes to a file before it is downloaded by the customer.
 *
 * Stores, either for customization, copy protection or other reasons, might want
 * to send customized downloads to customers. This hook will allow this to happen.
 * Before a file is opened to be transfered to a customer, this hook will be called
 * to make any altercations to the file that will be used to transfer the download
 * to the customer. This, in effect, will allow a developer to create a new,
 * personalized, file that will get transfered to a customer.
 *
 * @param $file_user
 *   The file_user object (i.e. an object containing a row from the uc_file_users
 *   table) that corresponds with the user download being accessed.
 * @param $ip
 *   The IP address from which the customer is downloading the file
 * @param $fid
 *   The file id of the file being transfered
 * @param $file
 *   The file path of the file to be transfered
 * @return
 *   The path of the new file to transfer to customer.
 */
function hook_file_transfer_alter($file_user, $ip, $fid, $file) {
  $file_data = file_get_contents($file) . " [insert personalized data]";

  //for large files this might be too memory intensive
  $new_file = tempnam(file_directory_temp(), 'tmp');
  file_put_contents($new_file, $file_data);
  return $new_file;
}

/**
 * Used to define line items that are attached to orders.
 *
 * A line item is a representation of charges, fees, and totals for an order.
 * Default line items include the subtotal and total line items, the tax line
 * item, and the shipping line item. There is also a generic line item that store
 * admins can use to add extra fees and discounts to manually created orders.
 * Module developers will use this hook to define new types of line items for
 * their stores. An example use would be for a module that allows customers to
 * use coupons and wants to represent an entered coupon as a line item.
 *
 * Once a line item has been defined in hook_line_item, Übercart will begin
 * interacting with it in various parts of the code. One of the primary ways this
 * is done is through the callback function you specify for the line item.
 *
 * @return
 *   Your hook should return an array of associative arrays. Each item in the
 *   array represents a single line item and should use the following keys:
 *   - "id"
 *     - type: string
 *     - value: The internal ID of the line item.
 *   - "title"
 *     - type: string
 *     - value: The title of the line item shown to the user in various interfaces.
 *         Use t().
 *   - "callback"
 *     - type: string
 *     - value: Name of the line item's callback function, called for various
 *         operations.
 *   - "weight"
 *     - type: integer
 *     - value: Display order of the line item in lists; "lighter" items are
 *         displayed first.
 *   - "stored"
 *     - type: boolean
 *     - value: Whether or not the line item will be stored in the database.
 *         Should be TRUE for any line item that is modifiable from the order
 *         edit screen.
 *   - "add_list"
 *     - type: boolean
 *     - value: Whether or not a line item should be included in the "Add a Line
 *         Item" select box on the order edit screen.
 *   - "calculated"
 *     - type: boolean
 *     - value: Whether or not the value of this line item should be added to the
 *         order total. (Ex: would be TRUE for a shipping charge line item but
 *         FALSE for the subtotal line item since the product prices are already
 *         taken into account.)
 *   - "display_only"
 *     - type: boolean
 *     - value: Whether or not this line item is simply a display of information
 *         but not calculated anywhere. (Ex: the total line item uses display to
 *         simply show the total of the order at the bottom of the list of line
 *         items.)
 */
function hook_line_item() {
  $items[] = array(
    'id' => 'generic',
    'title' => t('Empty Line'),
    'weight' => 2,
    'default' => FALSE,
    'stored' => TRUE,
    'add_list' => TRUE,
    'calculated' => TRUE,
    'callback' => 'uc_line_item_generic',
  );
  return $items;
}

/**
 * Perform actions on orders.
 *
 * An order in Übercart represents a single transaction. Orders are created
 * during the checkout process where they sit in the database with a status of In
 * Checkout. When a customer completes checkout, the order's status gets updated
 * to show that the sale has gone through. Once an order is created, and even
 * during its creation, it may be acted on by any module to connect extra
 * information to an order. Every time an action occurs to an order, hook_order()
 * gets invoked to let your modules know what's happening and make stuff happen.
 *
 * @param $op
 *   The action being performed.
 * @param &$arg1
 *   This is the order object or a reference to it as noted below.
 * @param $arg2
 *   This is variable and is based on the value of $op:
 *   - new: Called when an order is created. $arg1 is a reference to the new
 *       order object, so modules may add to or modify the order at creation.
 *   - save: When an order object is being saved, the hook gets invoked with this
 *       op to let other modules do any necessary saving. $arg1 is a reference to
 *       the order object.
 *   - load: Called when an order is loaded after the order and product data has
 *       been loaded from the database. Passes $arg1 as the reference to the
 *       order object, so modules may add to or modify the order object when it's
 *       loaded.
 *   - submit: When a sale is being completed and the customer has clicked the
 *       Submit order button from the checkout screen, the hook is invoked with
 *       this op. This gives modules a chance to determine whether or not the
 *       order should be allowed. An example use of this is the credit module
 *       attempting to process payments when an order is submitted and returning
 *       a failure message if the payment failed.
 *
 *       To prevent an order from passing through, you must return an array
 *       resembling the following one with the failure message:
 *       @code
 *         return array(array('pass' => FALSE, 'message' => t('We were unable to process your credit card.')));
 *       @endcode
 *   - can_update: Called before an order's status is changed to make sure the
 *       order can be updated. $arg1 is the order object with the old order
 *       status ID ($arg1->order_status), and $arg2 is simply the new order
 *       status ID. Return FALSE to stop the update for some reason.
 *   - update: Called when an order's status is changed. $arg1 is the order
 *       object with the old order status ID ($arg1->order_status), and $arg2 is
 *       the new order status ID.
 *   - can_delete: Called before an order is deleted to verify that the order may
 *       be deleted. Returning FALSE will prevent a delete from happening. (For
 *       example, the payment module returns FALSE by default when an order has
 *       already received payments.)
 *   - delete: Called when an order is deleted and before the rest of the order
 *       information is removed from the database. Passes $arg1 as the order
 *       object to let your module clean up it's tables.
 *   - total: Called when the total for an order is being calculated after the
 *       total of the products has been added. Passes $arg1 as the order object.
 *       Expects in return a value (positive or negative) by which to modify the
 *       order total.
 */
function hook_order($op, &$arg1, $arg2) {
  switch ($op) {
    case 'save':

      // Do something to save payment info!
      break;
  }
}

/**
 * Add links to local tasks for orders on the admin's list of orders.
 *
 * @param $order
 *   An order object.
 * @return
 *   An array of specialized link arrays. Each link has the following keys:
 *   - "name": The title of page being linked.
 *   - "url": The link path. Do not use url(), but do use the $order's order_id.
 *   - "icon": HTML of an image.
 *   - "title": Title attribute text (mouseover tool-tip).
 */
function hook_order_actions($order) {
  $actions = array();
  $module_path = base_path() . drupal_get_path('module', 'uc_shipping');
  if (user_access('fulfill orders')) {
    $result = db_query("SELECT nid FROM {uc_order_products} WHERE order_id = %d AND data LIKE '%%s:9:\"shippable\";s:1:\"1\";%%'", $order->order_id);
    if (db_num_rows($result)) {
      $title = t('Package order !order_id products.', array(
        '!order_id' => $order->order_id,
      ));
      $actions[] = array(
        'name' => t('Package'),
        'url' => 'admin/store/orders/' . $order->order_id . '/packages',
        'icon' => '<img src="' . $module_path . '/images/package.gif" alt="' . $title . '" />',
        'title' => $title,
      );
      $result = db_query("SELECT package_id FROM {uc_packages} WHERE order_id = %d", $order->order_id);
      if (db_num_rows($result)) {
        $title = t('Ship order !order_id packages.', array(
          '!order_id' => $order->order_id,
        ));
        $actions[] = array(
          'name' => t('Ship'),
          'url' => 'admin/store/orders/' . $order->order_id . '/shipments',
          'icon' => '<img src="' . $module_path . '/images/ship.gif" alt="' . $title . '" />',
          'title' => $title,
        );
      }
    }
  }
  return $actions;
}

/**
 * Register callbacks for an order pane.
 *
 * This hook is used to add panes to the order viewing and administration screens.
 * The default panes include areas to display and edit addresses, products,
 * comments, etc. Developers should use this hook when they need to display or
 * modify any custom data pertaining to an order. For example, a store that uses
 * a custom checkout pane to find out a customer's desired delivery date would
 * then create a corresponding order pane to show the data on the order screens.
 *
 * hook_order_pane() works by defining new order panes and providing a little bit
 * of information about them. View the return value section below for information
 * about what parts of an order pane are defined by the hook.
 *
 * The real meat of an order pane is its callback function (which is specified in
 * the hook). The callback function handles what gets displayed on which screen
 * and what data can be manipulated. That is all somewhat out of the scope of
 * this API page, so you'll have to click here to read more about what a callback
 * function should contain.
*/
function hook_order_pane() {
  $panes[] = array(
    'id' => 'payment',
    'callback' => 'uc_order_pane_payment',
    'title' => t('Payment'),
    'desc' => t('Specify and collect payment for an order.'),
    'class' => 'pos-left',
    'weight' => 4,
    'show' => array(
      'view',
      'edit',
      'customer',
    ),
  );
  return $panes;
}

/**
 * Register payment gateway callbacks.
 *
 * @see @link http://www.ubercart.org/docs/api/hook_payment_gateway @endlink
 *
 * @return
 *   Returns an array of payment gateways, which are arrays with the following keys:
 *   - "id"
 *     - type: string
 *     - value: The internal ID of the payment gateway, using a-z, 0-9, and - or
 *         _.
 *   - "title"
 *     - type: string
 *     - value: The name of the payment gateway displayed to the user. Use t().
 *   - "description"
 *     - type: string
 *     - value: A short description of the payment gateway.
 *   - "settings"
 *     - type: string
 *     - value: The name of a function that returns an array of settings form
 *         elements for the gateway.
 */
function hook_payment_gateway() {
  $gateways[] = array(
    'id' => 'test_gateway',
    'title' => t('Test Gateway'),
    'description' => t('Process credit card payments through the Test Gateway.'),
    'credit' => 'test_gateway_charge',
  );
  return $gateways;
}

/**
 * Register callbacks for payment methods.
 *
 * Payment methods are different ways to collect payment. By default, Übercart
 * comes with support for check, credit card, and generic payments. Payment
 * methods show up at checkout or on the order administration screens, and they
 * collect different sorts of information from the user that is used to process
 * or track the payment.
 *
 * @return
 *   An array of payment methods.
 */
function hook_payment_method() {
  $methods[] = array(
    'id' => 'check',
    'name' => t('Check'),
    'title' => t('Check or Money Order'),
    'desc' => t('Pay by mailing a check or money order.'),
    'callback' => 'uc_payment_method_check',
    'weight' => 1,
    'checkout' => TRUE,
  );
  return $methods;
}

/**
 * Perform actions on product classes.
 *
 * @param $type
 *   The node type of the product class.
 * @param $op
 *   The action being performed on the product class:
 *   - "insert": A new node type is created, or an existing node type is being
 *       converted into a product type.
 *   - "update": A product class has been updated.
 *   - "delete": A product class has been deleted. Modules that have attached
 *       additional information to the node type because it is a product type
 *       should delete this information.
 */
function hook_product_class($type, $op) {
  switch ($op) {
    case 'delete':
      db_query("DELETE FROM {uc_class_attributes} WHERE pcid = '%s'", $type);
      db_query("DELETE FROM {uc_class_attribute_options} WHERE pcid = '%s'", $type);
      break;
  }
}

/**
 * List node types which should be considered products.
 *
 * Trusts the duck philosophy of object identification: if it walks like a duck,
 * quacks like a duck, and has feathers like a duck, it's probably a duck.
 * Products are nodes with prices, SKUs, and everything else Übercart expects
 * them to have.
 *
 * @return
 *   Array of node type ids.
 */
function hook_product_types() {
  return array(
    'product_kit',
  );
}

/**
 * Handle additional data for shipments.
 *
 * @param $op
 *   The action being taken on the shipment. One of the following values:
 *   - "load": The shipment and its packages are loaded from the database.
 *   - "save": Changes to the shipment have been written.
 *   - "delete": The shipment has been deleted and the packages are available
 *     for reshipment.
 * @param &$shipment
 *   The shipment object.
 * @return
 *   Only given when $op is "load". An array of extra data to be added to the
 *   shipment object.
 */
function hook_shipment($op, &$shipment) {
  switch ($op) {
    case 'save':
      $google_order_number = uc_google_checkout_get_google_number($shipment->order_id);
      if ($google_order_number && $shipment->is_new) {
        $xml_data = '';
        foreach ($shipment->packages as $package) {
          if ($package->tracking_number) {
            $tracking_number = $package->tracking_number;
          }
          else {
            if ($shipment->tracking_number) {
              $tracking_number = $shipment->tracking_number;
            }
          }
          if ($tracking_number) {
            foreach ($package->products as $product) {
              $xml_data .= '<item-shipping-information>';
              $xml_data .= '<item-id>';
              $xml_data .= '<merchant-item-id>' . check_plain($product->nid . '|' . $product->model) . '</merchant-item-id>';
              $xml_data .= '</item-id>';
              $xml_data .= '<tracking-data-list>';
              $xml_data .= '<tracking-data>';
              $xml_data .= '<carrier>' . check_plain($shipment->carrier) . '</carrier>';
              $xml_data .= '<tracking-number>' . check_plain($tracking_number) . '</tracking-number>';
              $xml_data .= '</tracking-data>';
              $xml_data .= '</tracking-data-list>';
              $xml_data .= '</item-shipping-information>';
            }
          }
        }
        if ($xml_data) {
          $request = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
          $request .= '<ship-items xmlns="http://checkout.google.com/schema/2" google-order-number="' . $google_order_number . '">';
          $request .= '<item-shipping-information-list>';
          $request .= $xml_data;
          $request .= '</item-shipping-information-list>';
          $request .= '<send-email>true</send-email>';
          $request .= '</ship-items>';
          $response = uc_google_checkout_send_request('request', $request);
        }
      }
      break;
    case 'delete':
      $google_order_number = uc_google_checkout_get_google_number($shipment->order_id);
      if ($google_order_number) {
        foreach ($shipment->packages as $package) {
          foreach ($package->products as $product) {
            $reset_ids[] = check_plain($product->nid . '|' . $product->model);
          }
        }
        $request = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
        $request .= '<reset-items-shipping-information xmlns="http://checkout.google.com/schema/2" google-order-number="' . $google_order_number . '">';
        $request .= '<item-ids>';
        foreach (array_unique($reset_ids) as $item_id) {
          $request .= '<item-id>';
          $request .= '<merchant-item-id>' . $item_id . '</merchant-item-id>';
          $request .= '</item-id>';
        }
        $request .= '</item-ids>';
        $request .= '<send-email>false</send-email>';
        $request .= '</reset-items-shipping-information>';
      }
      $response = uc_google_checkout_send_request('request', $request);
      break;
  }
}

/**
 * Define callbacks and service options for shipping methods.
 *
 * The shipping quote controller module, uc_quote, expects a very specific
 * structured array of methods from the implementations of this hook.
 *
 * The weights and enabled flags for shipping methods and types are set at the
 * Shipping Quote Settings page under Store Configuration. They keys of the
 * variables are the ids of the shipping methods. The "quote" and "ship" arrays of
 * the method are both optional.
 *
 * @return
 *   An array of shipping methods which have the following keys.
 *   - "type": The quote and shipping types are ids of the product shipping type
 *       that these methods apply to. type may also be 'order' which indicates
 *       that the quote applies to the entire order, regardless of the shipping
 *       types of its products. This is used by quote methods that are base on
 *       the location of the customer rather than their purchase.
 *   - "callback": The function that is called by uc_quote when a shipping quote
 *       is requested. Its arguments are the array of products and an array of
 *       order details (the shipping address). The return value is an array
 *       representing the rates quoted and errors returned (if any) for each
 *       option in the accessorials array.
 *   - "accessorials": This array represents the different options the customer
 *       may choose for their shipment. The callback function should generate a
 *       quote for each option in accessorials and return them via an array.
 *       drupal_to_js() is very useful for this.
 *       @code
 *         return array(
 *           '03' => array('rate' => 15.75, 'format' => uc_currency_format(15.75) 'option_label' => t('UPS Ground'),
 *                         'error' => 'Additional handling charge automatically applied.'),
 *           '14' => array('error' => 'Invalid package type.'),
 *           '59' => array('rate' => 26.03, 'format' => uc_currency_format(26.03), 'option_label' => t('UPS 2nd Day Air A.M.'))
 *         );
 *       @endcode
 *   - "pkg_types": The list of package types that the shipping method can handle.
 *       This should be an associative array that can be used as the #options of
 *       a select form element. It is recommended that a function be written to
 *       output this array so the method doesn't need to be found just for the
 *       package types.
 */
function hook_shipping_method() {
  $methods = array();
  $enabled = variable_get('uc_quote_enabled', array(
    'ups' => true,
  ));
  $weight = variable_get('uc_quote_method_weight', array(
    'ups' => 0,
  ));
  $methods['ups'] = array(
    'id' => 'ups',
    'title' => t('UPS'),
    'enabled' => $enabled['ups'],
    'weight' => $weight['ups'],
    'quote' => array(
      'type' => 'small package',
      'callback' => 'uc_ups_quote',
      'accessorials' => array(
        '03' => t('UPS Ground'),
        '11' => t('UPS Standard'),
        '01' => t('UPS Next Day Air'),
        '13' => t('UPS Next Day Air Saver'),
        '14' => t('UPS Next Day Early A.M.'),
        '02' => t('UPS 2nd Day Air'),
        '59' => t('UPS 2nd Day Air A.M.'),
        '12' => t('UPS 3-Day Select'),
      ),
    ),
    'ship' => array(
      'type' => 'small package',
      'callback' => 'uc_ups_fulfill_order',
      'pkg_types' => array(
        '01' => t('UPS Letter'),
        '02' => t('Customer Supplied Package'),
        '03' => t('Tube'),
        '04' => t('PAK'),
        '21' => t('UPS Express Box'),
        '24' => t('UPS 25KG Box'),
        '25' => t('UPS 10KG Box'),
        '30' => t('Pallet'),
      ),
    ),
  );
  return $methods;
}

/**
 * Define shipping types for shipping methods.
 *
 * This hook defines a shipping type that this module is designed to handle.
 * These types are specified by a machine- and human-readable name called 'id',
 * and 'title' respectively. Shipping types may be set for individual products,
 * manufacturers, and for the entire store catalog. Shipping modules should be
 * careful to use the same shipping type ids as other similar shipping modules
 * (i.e., FedEx and UPS both operate on "small package" shipments). Modules that
 * do not fulfill orders may not need to implement this hook.
 *
 * @return
 *   An array of shipping types keyed by a machine-readable name.
 */
function hook_shipping_type() {
  $weight = variable_get('uc_quote_type_weight', array(
    'small_package' => 0,
  ));
  $types = array();
  $types['small_package'] = array(
    'id' => 'small_package',
    'title' => t('Small Packages'),
    'weight' => $weight['small_package'],
  );
  return $types;
}

/**
 * Add status messages to the "Store administration" page.
 *
 * This hook is used to add items to the store status table on the main store
 * administration screen. Each item gets a row in the table that consists of a
 * status icon, title, and description. These items should be used to give
 * special instructions, notifications, or indicators for components of the cart
 * enabled by the modules. At a glance, a store owner should be able to look here
 * and see if a critical component of your module is not functioning properly.
 *
 * For example, if the catalog module is installed and it cannot find the catalog
 * taxonomy vocabulary, it will show an error message here to alert the store
 * administrator.
 *
 * @return
 *   An array of tore status items which are arrays with the following keys:
 *   - "status": "ok", "warning", or "error" depending on the message.
 *   - "title" The title of the status message or module that defines it.
 *   - "desc": The description; can be any message, including links to pages and
 *       forms that deal with the issue being reported.
 */
function hook_store_status() {
  if ($key = uc_credit_encryption_key()) {
    $statuses[] = array(
      'status' => 'ok',
      'title' => t('Credit card encryption'),
      'desc' => t('Credit card data in the database is currently being encrypted.'),
    );
  }
  return $statuses;
}

/**
 * Convenience function to display large blocks of text in several places.
 *
 * There are many instances where Ubercart modules have configurable blocks of
 * text. These usually come with default messages, like e-mail templates for new
 * orders. Because of the way default values are normally set, you're then stuck
 * having to copy and paste a large chunk of text in at least two different
 * places in the module (when you're wanting to use the variable or to display
 * the settings form with the default value). To cut down code clutter, this hook
 * was introduced. It lets you put your messages in one place and use the
 * function uc_get_message() to retrieve the default value at any time (and from
 * any module).
 *
 * The function is very simple, expecting no arguments and returning a basic
 * associative array with keys being message IDs and their values being the
 * default message. When you call uc_get_message(), use the message ID you set
 * here to refer to the message you want.
 *
 * Note: When using t(), you must not pass it a concatenated string! So our
 * example has no line breaks in the message even though it is much wider than 80
 * characters. Using concatenation breaks translation.
 *
 * @return
 *   An array of messages.
 */
function hook_uc_message() {
  $messages['configurable_message_example'] = t('This block of text represents a configurable message such as a set of instructions or an e-mail template.  Using hook_uc_message to handle the default values for these is so easy even your grandma can do it!');
  return $messages;
}

/**
 * Handle requests to update a cart item.
 *
 * @param $nid
 *   Node id of the cart item.
 * @param $data
 *   Array of extra information about the item.
 * @param $qty
 *   The quantity of this item in the cart.
 * @param $cid
 *   The cart id. Defaults to NULL, which indicates that the current user's cart
 *   should be retrieved with uc_cart_get_id().
 */
function hook_update_cart_item($nid, $data = array(), $qty, $cid = NULL) {
  if (!$nid) {
    return NULL;
  }
  $cid = !(is_null($cid) || empty($cid)) ? $cid : uc_cart_get_id();
  if ($qty < 1) {
    uc_cart_remove_item($nid, $cid, $data);
  }
  else {
    db_query("UPDATE {uc_cart_products} SET qty = %d, changed = %d WHERE nid = %d AND cart_id = '%s' AND data = '%s'", $qty, time(), $nid, $cid, serialize($data));
    cache_clear_all();
  }

  // Rebuild the items hash
  uc_cart_get_contents(NULL, 'rebuild');
  if (!strpos(request_uri(), 'cart', -4)) {
    drupal_set_message(t('Your item(s) have been updated.'));
  }
}

/**
 * @} End of "addtogroup hooks".
 */

Functions

Namesort descending Description
hook_add_to_cart Do extra processing when an item is added to the shopping cart.
hook_add_to_cart_data Add extra information to a cart item's "data" array.
hook_calculate_tax Calculate tax line items for an order.
hook_cart_display Control the display of an item in the cart.
hook_cart_item Add extra data about an item in the cart.
hook_cart_pane Register callbacks for a cart pane.
hook_checkout_pane Register callbacks for a checkout pane.
hook_download_authorize Give clearance to a user to download a file.
hook_file_action Perform actions on file products.
hook_file_transfer_alter Make changes to a file before it is downloaded by the customer.
hook_line_item Used to define line items that are attached to orders.
hook_order Perform actions on orders.
hook_order_actions Add links to local tasks for orders on the admin's list of orders.
hook_order_pane Register callbacks for an order pane.
hook_payment_gateway Register payment gateway callbacks.
hook_payment_method Register callbacks for payment methods.
hook_product_class Perform actions on product classes.
hook_product_types List node types which should be considered products.
hook_shipment Handle additional data for shipments.
hook_shipping_method Define callbacks and service options for shipping methods.
hook_shipping_type Define shipping types for shipping methods.
hook_store_status Add status messages to the "Store administration" page.
hook_uc_message Convenience function to display large blocks of text in several places.
hook_update_cart_item Handle requests to update a cart item.