This is the documentation for LemonStand V1, which has been discontinued. You can learn more and upgrade your store here.

LemonStand Version 1 Has Been Discontinued

This documentation is for LemonStand Version 1. LemonStand is now offered as a cloud-based eCommerce platform.
You can try the new LemonStand and learn about upgrading here.

Guide to Developing Shipping Modules

LemonStand shipping modules are PHP classes defined in scripts located in the shipping_types directory of a LemonStand module. Any LemonStand module can host any number of shipping modules. Before you begin developing a new shipping module you should choose whether you want to develop it as a Shop module class, or as a class of a separate custom module. You can choose the first option if you are developing a new shipping module for a private use. The last option will allow you to share the module through the LemonStand marketplace. 

Click here to  download a shipping module template.

Structure of a shipping module

Shipping module classes should extend the Shop_ShippingType class. This abstract PHP class contains all methods sufficient for developing any shipping module. By overriding methods of this base class you can add specific features to your shipping module.

There is a naming convention, which allows LemonStand to load shipping module classes automatically. Shipping module class names should have the following structure: ModuleCode_ShippingModuleName_Shipping. The ModuleCode_ prefix and the _Shipping suffix are required. Between the prefix and suffix can you use any suitable name, describing the shipping module. Shipping module class name example: Shop_FedEx_Shipping, MyModule_Usps_Shipping.

Each shipping module class should be defined in a separate file, with the name matching the class name it contains, written in lower case. If the class name was the MyModule_Usps_Shipping, a corresponding file name, would be mymodule_usps_shipping.php.

Aside from the shipping module PHP file, shipping modules can also have a directory, with name matching the module PHP file name. The directory should be located in the same directory with the module PHP file, i.e. in the modules/shop/shipping_types directory, in case if the shipping module belongs to the Shop module, or modules/mymodule/shipping_types, in case if the module belongs to a custom module with the MyModule code. If a shipping module file name is mymodule_usps_shipping.php, than the corresponding module directory name is mymodule_usps_shipping. Module directories can contain XML or any other files required for the module. Below is a screenshot of the modules/shop/shipping_types directory. On the screenshot you can see some shipping module PHP files and corresponding directories.

Common shipping module functions

Regardless of a specific shipping service all shipping module classes have a set of common function. Each module should provide the information about itself - the shipping service name and description. Also each module should have a configuration form, which LemonStand administrators will use for creating a shipping option and setting module-specific parameters. All required shipping module functions should be implemented as class methods described below.

Defining a shipping module class

Below is a partial declaration of a shipping module class, which implements the FedEx shipping service integration. The code defines the class and a method which returns the module specific information.

<?
  class Shop_Ups_Shipping extends Shop_ShippingType
  {
    public function get_info()
    {
      return array(
        'name'=>'UPS',
        'description'=>'This shipping method allows to request quotes 
            and shipping options from the United Parcel Service of America (UPS).
            You must have a UPS account in order to use this method.'
      );
    }
  }
?>

The get_info() method should be declared in all shipping modules. The method should return an array containing the module name and description. This information will be presented in the Add Shipping Method form in the Administration Area:

Building a shipping module configuration form

Another required shipping module class method is the build_config_ui(). This method builds the module configuration form and it is similar to the define_form_fields() method of the model class, which we described in the Forms article. In this method you can add tabs and fields to the module configuration form. All field values are saved automatically and you can access them inside the shipping quote request code. In this method you should add only module-specific fields, for example fields for API user name and password. All fields which are common for all shipping modules, for example shipping option name, description and checkboxes for selecting countries the option is applicable for, are added by LemonStand automatically. The set of fields depends on specific shipping service and you need to refer to your shipping service API description in order to find out which configuration fields you need to create on the configuration form.

Below is a definition of the build_config_ui() method of the UPS shipping module.

public function build_config_ui($host_obj, $context = null)
{
  if ($context !== 'preview')
  {
    $host_obj->add_field('api_user', 'User Name', 'left')->tab('API Credentials')->
      comment('UPS API user name.', 'above')->renderAs(frm_text)->validation()->
      required('Please specify API user name');
    $host_obj->add_field('api_password', 'User Password', 'right')->tab('API Credentials')->
      comment('UPS API password.', 'above')->renderAs(frm_password)->validation();
    $host_obj->add_field('access_key', 'API Access Key')->tab('API Credentials')->
      comment('UPS API access key.', 'above')->renderAs(frm_text)->validation()->
      required('Please specify API access key');
  }

  $host_obj->add_field('container', 'Container Type', 'left')->tab('Shipping Parameters')->
    renderAs(frm_dropdown)->validation()->required('Please specify container type');
  $host_obj->add_field('pickup_type', 'Pickup Type', 'right')->tab('Shipping Parameters')->
    renderAs(frm_dropdown)->validation()->required('Please specify pickup type');
  $host_obj->add_field('allowed_methods', ' Allowed methods')->tab('Shipping Parameters')->
    renderAs(frm_checkboxlist)->validation();

  $host_obj->add_field('free_shipping_enabled', ' Enable free shipping option')->
    tab('Free Shipping')->renderAs(frm_checkbox)->validation();
  $host_obj->add_field('free_shipping_option', ' Free shipping method')->
    tab('Free Shipping')->renderAs(frm_dropdown)->validation();
  $host_obj->add_field('free_shipping_min_amount', 'Minimum order amount for free shipping', 'full', db_number)->
    tab('Free Shipping')->renderAs(frm_text)->validation();
}

The method receives 2 parameters - the Active Record object, which should be used for adding form fields, and a form context. If the form context value is preview, the method should not create any form fields which contain API user names or passwords, because the shipping method preview form is available in read-only mode from the Order Preview page. The example code creates a number of UPS-specific fields and tabs on the configuration form. Below is a screenshot of the API Credentials tab of the module configuration form:

To add fields to the configuration form, the code inside the build_config_ui() method should call the add_field() method of the object, passed in the first method parameter. This method has two parameters - the field identifier and the field title. Field identifiers should be compatible with PHP variable names - they should not contain spaces, and they can contain only Latin characters and numbers. Using the optional third parameter you can specify a field alignemt on the form. Allowed parameter values are left, right and full (it is a default value).

The add_field() method returns an object of the Db_FormFieldDefinition class, which you can use for configuring a field appearance and validation rules. The renderAs() method allows to specify a preferable control type for a field. You can find a list of possible control types in the Db_FormFieldDefinition class description.

The code above sets the drop-down control type for some fields (Container Type, Pickup Type and Free shipping method). For each drop-down field there has to be defined a method returning a list of options. The method name should have the following structure: get_field_name_options. Thus, for the container field valid method name is get_order_container_options. The method should have a single parameter with default value -1. Below is an example of the method:

public function get_container_options($current_key_value = -1)
{
  $container_types = array(
    '00'=>'Unknown',
    '01'=>'UPS letter',
    ...
    '30'=>'Pallet'
  );
  
  if ($current_key_value == -1)
    return $container_types;

  return array_key_exists($current_key_value, $container_types) ? $container_types[$current_key_value] : null;
}

The methods return arrays of available options as an associative array with indexes matching option identifiers and values matching option titles. Methods which return option lists, should check the method parameter value. If the parameter value is equal to -1, a method should return all possible options as array. If the parameter value is not -1, the method should try to find an option corresponding the parameter value, and return the option name (title). You can find the corresponding condition in the get_container_options() method example above.

Validating the configuration form data

All shipping module classes should override the validate_config_on_save() method. Inside this method a module can check configuration field values before the configuration is saved to the database. The method has a single parameter - an object, with fields matching form fields defined in the build_config_ui() method. The method should be implemented even if you are not going to perform any parameter validation. In this case you can leave it empty. Example:

public function validate_config_on_save($host_obj)
{
  if ($host_obj->free_shipping_enabled && !strlen($host_obj->free_shipping_min_amount))
    $host_obj->validation->setError('Please specify minimum order amount for free shipping
      or disable the free shipping option', 'free_shipping_min_amount', true);
    
  ...
}

Initializing the configuration form field values

You can initialize values of the configuration form fields using the init_config_data() optional method. The values will be applied when a shipping option based on your shipping module is created. The method receives a single parameter, which you can use for setting values to fields defined in the build_config_ui() method. Example:

public function init_config_data($host_obj)
{
  $host_obj->api_user = 'john_01';
}

Processing the shipping quote requests

The get_quote() method is the heart of any shipping module. This method returns a list of available shipping options and shipping quotes. The method receives a single parameter - the associative array of values, which identify the cart content, shipping location, etc. Method definition:

public function get_quote($parameters)
{
}

The $parameters array has the following keys:

  • host_obj - an object containing the shipping module configuration values
  • country_id - specifies the shipping country identifier. Use the Shop_Country class to load a country object by its identifier.
  • state_id - specifies shipping state identifier. Use the Shop_CountryState class to load a state by its identifier.
  • zip - specifies shipping zip/postal code
  • city - specifies shipping city name
  • total_price - specifies total price of items in the shopping cart
  • total_volume - specifies total volume of items in the shopping cart
  • total_weight - specifies total weight of items in the shopping cart
  • total_item_num - specifies total number of items in the shopping cart
  • cart_items - a list of cart items (Shop_CartItem objects)
  • is_business - determines whether the shipping location is a business address 

The simplest way to work with the values contained in the $parameters parameter  in the method is to run the extract() function in the beginning of the method body. The extract() function converts array elements to local variables. Example:

public function get_quote($parameters)
{
  extract($parameters);
  
  // Now you can work with the $parameters elements as with local variables.  
}

There are single-option and multi-option shipping services. Most of the shipping services are multi-option. For example, FedEx provides the following shipping options (services): Europe First International Priority, FedEx 1-Day Freight, FedEx Express Saver and so on. Depending on the shipping service and available options, the get_quote() method can return the following values:

  • null - of no shipping options are available.
  • numeric value - shipping quote for a single-option shipping services.
  • array of option names and quote values for multi-option shipping service. Value format:
    array(
       'UPS Express'=>array('id'=>'express', 'quote'=>12.29),
       'UPS Expedited'=>array('id'=>'expedited, 'quote'=>32.12)
    )

You can use any identifiers and names of options for multi-option shipping modules. They only need to be consistent with the option names and identifiers returned by the list_enabled_options() method described below.

Inside the method you should request the shipping service gateway, parse the response and prepare the result value. Please refer to the shipping service implementation guide for details.

If the shipping service gateway requires the request to be a XML document, you can use the XML formatting features which are built into the Shop_ShippingType class. Inside the shipping method directory (described above) you can place XML template files, containing PHP code. Example of the Access Request XML template file from UPS shipping module:

<AccessRequest xml:lang='en-US'>
  <AccessLicenseNumber><?= h($settings_obj->access_key) ?></AccessLicenseNumber>
  <UserId><?= h($settings_obj->api_user) ?></UserId>
  <Password><?= h($settings_obj->api_password) ?></Password>
</AccessRequest>

As you can see the template contains several PHP blocks, which refer to variable passed from outside. To get a formatted XML document in the shipping module code you should call the format_xml_template() method. This method accepts 2 parameters - the XML template file name, and an array of variables. The method returns a formatted XML string which you can send to the shipping service gateway. Example:

$access_doc = $this->format_xml_template('access_doc.xml', array('settings_obj'=>$host_obj));

Returning a list of services for the Free Shipping

The Discount Engine supports the Free Shipping Options feature, which enables users to choose specific shipping services to make free when the discount action takes effect.

Multi-option shipping options should implement the list_enabled_options() method for returning a list of enabled shipping options. Implementing this method is required for multi-option shipping modules, if you are going to distribute your shipping service through the Marketplace.

The method accepts a single parameter - the object with the configuration field values. The method should return an array containing a list of shipping options in the following format:
array(
  array('id'=>'option_id_1', 'name'=>'Option 1 name'),
  array('id'=>'option_id_2', 'name'=>'Option 2 name')
)

The option names and identifiers should match the option names and identifiers returned by the get_quote() method.

Next: LemonStand Module Templates
Previous: Extending Existing Models
Return to Extending LemonStand