Discount Plugins

This article assumes you have a clear understanding of PHP, PHP Classes, and arrays, as well as a good working knowledge of CartThrob.

CartThrob has a discount plugin interface, and several helper functions that simplify the creation of discount plugins. Refer to one of the included discount plugins as an example. The "Percentage Off Product" plugin uses most of the functionality available to your discount plugins, so it's a good starter example of what's possible.

Overview

Discount plugins are PHP Classes that contain at a minimum a $title, a get_discount function and a validate function.

All discount plugins are stored in the following location: cartthrob » cartthrob » plugins » discounts. You can look there for additional discount plugins to use as a reference.

Discount plugins are used for both automatically applied discounts, as well as coupons/vouchers that require a code to use. Discounts and coupons/vouchers both use EE channels. You can set the field that will be used as the coupon code in CartThrob settings > Discounts > Coupon Code Field. By default the title is used as the coupon code field, but you can override this in the coupon settings.

IMPORTANT

  1. Your plugin classname should match your plugin file name. If it does not match, it will not be recognized.

  2. Your plugin filename/classname needs to begin with Cartthrob_discount or it will not be recognized as a discount plugin.

  3. By default, sessions data is automatically available for all discount plugins you create, so you do not have to, and should not start a session for your plugin, or plugin functions.

  4. You need to create a language file for each discount plugin (see more about language files). Each language file should be named the same name as your plugin, with _lang at the end, and in all lower case (example: cartthrob_discount_my_shipping_plugin_lang.php)

Table of Contents

Plugin Information

These fields, located at the top of the plugin allow you to set some general information about your plugin. Title is required. The rest are optional.

public $title = 'Percentage Off Product';
public $note = 'This discount plugin only discounts one entry id.';

Language Files

You should probably create a language file for your plugin if you intend to have any settings available to select. The naming convention for the language file is as follows:

cartthrob_discount_YOUR_PLUGIN_NAME_lang.php

Review existing language files for an example of the proper formatting. Create language key/value pairs as needed, for example.

my_title => 'Flat Rates 2', 

You would access this like so:

public $title   = 'my_title';

CartThrob will look for the my_title key in the language file, and replace it with the relevant value. If it's not found, then my_title will be used instead. Within the plugin itself, (to set error messages in validation) you can access language lines using

$this->core->lang('my_title')

Plugin Settings

Each plugin has the ability to store and manage its own settings. Each setting is an array that requires at a minimum array keys for name, type, and short_name of the setting. You can also add a default, options, note, settings (to generate a matrix of settings).

name

required key

Name is the settings name that the customer will see. Use plain text, or a reference to a language file key.

type

required key

This is the type of setting. The following settings types are recognized:

  1. text
  2. textarea
  3. radio (see options)
  4. select (see options)
  5. checkbox (see options) (if not checked, will not return ANY value.)
  6. header

The type will determine whether data stored in this setting is string data or an array. text, textarea and header are the only string types. The rest are arrays

short_name

required key

The short_name is what will be used by your plugin to access the content of this setting (see plugin_settings function below). short_names should only include "alpha-dash" characters. Alphabet + numeric + underscore and hyphen.

default

optional key

This is default data that should populate the setting.

options

(usually) optional key

Required if you are using a non-text type. Options is an array containing the selectable options in a radio or select dropdown. The option key is accessible using the plugin_settings function. The value is descriptive for the client only, and is not accessible, except by using the key in conjunction with a call to the language file.

'options' => array(
    'option' => 'Descriptive Name',
    'option2' => 'Other Descriptive Name',
),
note

optional key

Optional & purely descriptive. Generally the "name" key should be fairly short, but the "note" key can contain one or more paragraphs as needed to describe the setting in detail to the user. Feel free to use HTML in your note field.

Example

$public $settings = array(
    array(
        'name' => 'Settings Example', // descriptive name
        'short_name' => 'settings_example', // you will use this to access this setting your code.
        'type' => 'text', 
        'default' => 'Whatevs', // optional
    ),
    array(
        'name' => 'Settings Example 2', 
        'short_name' => 'settings_example_2', 
        'type' => 'radio',
        'default' => 'yes',
        'options' => array(
            'yes' => 'Yes',
            'no' => 'No',
        ),
    ),
);

Required Functions

initialize

Only needed if you want to set a plugin wide variable in one central location.

parameters: plugin_settings (array) return: void

public function initialize($plugin_settings = array())
{
    // this would add categories to the options in Settings Example 2 (in the example above)
    $this->settings[1]['options'] = $this->core->get_categories();

    parent::initialize($plugin_settings);
}
get_discount

parameters: none return: float (the shipping cost)

This function returns the amount of the discount. This is where you add all the logic needed to calculate the discount. The amount returned should not be in a money format, but should be as a float (ex. 10.01, 22, 9.25)

public function get_discount()
{
    return 10; 
}
validate

parameters: none return: boolean (whether or not validation was successful)

This function validates the coupon code and returns errors if the code is not valid. This function is also used in automatically applied discount plugins, but errors are ignored, and the discount is simply not applied. If the discount should be applied, return TRUE, else return FALSE.

public function validate()
{
    $valid = FALSE;

    // in this example, we're looking for a list of entry IDs in a text field, 
    // splitting them apart (using spaces, pipes) 
    // and turning them into an array
    if ($this->plugin_settings('entry_ids') && $entry_ids = preg_split('#\s*[,|]\s*#', trim($this->plugin_settings('entry_ids'))))
    {
        // we're checking to see if any of these entry_ids is in the cart. If so, this is valid
        $valid = (count(array_intersect($this->core->cart->product_ids(), $entry_ids)) > 0);
    }

    // oops its not valid. We're returning an error. This error is ignored with automatically applied discounts. 
    // discounts with validation errors are ignored
    if ( ! $valid)
    {
        $this->set_error( $this->core->lang('coupon_not_valid_for_items') );
    }

    return $valid;
}

Helper Functions

  1. plugin_settings
  2. sanitize_number
  3. lang
  4. set_error
  5. set_total
  6. set_shipping
plugin_settings

Outputs the contents of a particular setting, called by the setting's "short_name". The plugin setting may return an array or string, depending on how you set it up (see settings above).

(mixed) $this->plugin_settings('YOUR_KEY'); 

example:

if ($this->plugin_settings('test_mode') == 'test')
{
    $sample_price = 10; 
}
sanitize_number

Cleans a number so that it's a float value. This helps remove incompatible formatting like $ signs or commas.

$this->core->sanitize_number($this->plugin_settings('percentage_off')
lang

Returns a key from the lang file

$this->core->lang('coupon_not_valid_for_items');
set_error

Sets an error that will be output if the coupon code is not valid

$this->set_error( $this->core->lang('coupon_not_valid_for_items') );  
set_total

This sets the cart total to the specified amount. This is will override all cart calculations.

//free order
$this->core->cart->set_total(0);
set_shipping

This sets the cart shipping to the specified amount. This will override the calculated shipping value.

//free shipping
$this->core->cart->set_shipping(0);

Core Cart Functions

Any of CartThrob's methods can be used by a discount plugin, the following is a short list of the most useful core cart functions available for discount purposes.

  1. customer_info
  2. cart_items
  3. subtotal
  4. shipping

ExpressionEngine functions can also be called if it is instantiated.

$this->EE =& get_instance(); 
customer_info

This returns an array of all of the customer information.

(array) $this->core->cart->customer_info(); 

You can also call specific customer info:

$this->core->cart->customer_info("first_name"); 
cart_items

Outputs the contents of all items in the cart.

(object) $this->core->cart->items(); 

You can also access object methods for each item in the cart:

foreach ($this->core->cart->items() as $key => $item)
{
    echo $item->quantity(); 
    echo $item->price();
    echo $item->weight(); 
    echo $item->product_id();
}
subtotal
$this->core->cart->subtotal();
shipping
$this->core->cart->shipping();
Examples

The following is a very simple example that returns a percentage based discount calculated using the cart subtotal. See cartthrob > cartthrob > plugins > discount for additional discount plugins to use as a reference.

<?php if ( ! defined('CARTTHROB_PATH')) Cartthrob_core::core_error('No direct script access allowed');

class Cartthrob_discount_percentage_off extends Cartthrob_discount
{
    public $title = 'percentage_off';
    public $settings = array(
        array(
            'name' => 'percentage_off',
            'short_name' => 'percentage_off',
            'note' => 'percentage_off_note',
            'type' => 'text'
        )
    );

    public function get_discount()
    {
        return $this->core->cart->subtotal() * ($this->core->sanitize_number($this->plugin_settings('percentage_off')) / 100);
    }
}