Skip to content

Instantly share code, notes, and snippets.

@wpsmith
Created September 12, 2012 20:17
Show Gist options
  • Select an option

  • Save wpsmith/3709581 to your computer and use it in GitHub Desktop.

Select an option

Save wpsmith/3709581 to your computer and use it in GitHub Desktop.
Promotions API for Shopp
<?php
/**
* Promotions API
*
* Plugin api for manipulating promotions.
*
* @author Travis Smith
* @version 1.0
* @copyright Ingenesis Limited, June 30, 2011
* @license GNU GPL version 3 (or later) {@see license.txt}
* @package shopp
* @since 1.3
* @subpackage shopp
**/
/**
* Creates a Shopp Promotion.
*
* $defaults = array(
* // Enable the promo
* 'status' => 'enabled',
*
* // DATES
* 'starts' => array(
* 'month' => '',
* 'date' => '',
* 'year' => '',
* ),
* 'ends' => array(
* 'month' => '',
* 'date' => '',
* 'year' => '',
* ),
*
* // DISCOUNT
* 'type' => 'Percentage Off',
* //Options: Percentage Off,
* Amount Off,
* Free Shipping,
* Buy X Get Y Free (target must be Cart Item)
* 'discount' => '',
* 'buyqty' => '',
* 'getqty' => '',
*
* // CONDITIONS
* 'search' => 'any', //Options: any, all
* 'target' => 'Catalog', //Options: Catalog, Cart, Cart Item
* 'rules' => array(),
* 'property' => '',
* if ( Catalog == target ):
* Options: Name,
* Category,
* Variation,
* Price,
* Sales Price,
* Type,
* In Stock
* if ( Cart == target ):
* Options: Any item name,
* Any item quantity,
* Any item amount,
* Total quantity,
* Shipping amount,
* Subtotal amount,
* Discount amount,
* Customer type,
* Ship-to country,
* Promo use count,
* Promo code,
*
* 'logic' => '',
* ['rules'][#]['property'] = Name, Category, Variation
* Options: Is equal to,
* Is not equal to,
* Contains,
* Does not contain,
* Begins with,
* Ends with
* ['rules'][#]['property'] = Price, Sales Price, In Stock
* Options: Is equal to,
* Is not equal to,
* Is greater than,
* Is greater than or equal to,
* Is less than,
* Is less than or equal to
* ['rules'][#]['property'] = Type
* Options: Is equal to,
* Is not equal to,
* 'value' => '',
*
* 'item' => array(
* array( 'property' => '', 'logic' => '', 'value' => '', ),
* ),
* 'property' => '',
* Options: Name,
* Category,
* Tag name,
* Variation,
* Input name,
* Input Value,
* Quantity,
* Unit price,
* Total price,
* Discount amount
* 'logic' => '',
['rules']['item'][#]['property'] = Name, Category, Tag name, Variation, Input name, Input Value
* Options: Is equal to,
* Is not equal to,
* Contains,
* Does not contain,
* Begins with,
* Ends with
*
['rules']['item'][#]['property'] = Unit price, Total price, Discount amount
* Options: Is equal to,
* Is not equal to,
* Is greater than,
* Is greater than or equal to,
* Is less than,
* Is less than or equal to
* 'value' => '',
*
* );
*
* @author Travis Smith
* @since 1.3.0
* @param array $args (required) Array of arguments needed to create Promo.
* @return Promotion Object New Promotion Object.
*/
function shopp_create_promo( $args = array() ) {
$defaults = array(
'name' => '',
// Status
'status' => false,
// Discount
'type' => 'Percentage Off',
// Conditions
'search' => 'any',
'target' => 'Catalog',
);
$args = wp_parse_args( $args, $defaults );
// Bail if no name was given
if ( '' == $args['name'] ) return false;
// Create Promotion Object
$Promotion = new Promotion();
// Setup Promotion Object
$Promotion->name = $name;
$Promotion->uses = 0;
$Promotion->created = null;
$Promotion->modified = null;
$Promotion->status = isset( $args['status'] ) ? $args['status'] : '';
// Update/Save Promotion Object
$Promotion->updates( $args );
$Promotion->save();
do_action_ref_array( 'shopp_promo_saved', array( &$Promotion ) );
if ( 'Catalog' == $Promotion->target )
$Promotion->catalog_discounts();
return $Promotion;
}
/**
* Determines whether a promo exists already or not.
*
* @author Travis Smith
* @since 1.3.0
* @uses shopp_get_promo_id() Gets a Promotion ID based on Promo Name.
* @param string|int $name (required) Name of the Promotion.
* @return bool True if promotion exists and false otherwise.
*/
function shopp_promo_exists( $promo ) {
$id = shopp_get_promo_id( $promo );
if ( false != $id )
return true;
else
return false;
}
/**
* Gets a Promotion ID based on Promo Name.
* If $name is an integer, it will be returned as the ID.
*
* @author Travis Smith
* @since 1.3.0
* @param string|int $name (required) Name of the Promotion.
* @return int $Promotion->id Promotion ID.
*/
function shopp_get_promo_id( $name ) {
if ( is_string( $name ) ) {
$Promotion = new Promotion();
$Promotion->load( array( 'name' => $name ) );
if ( ! empty( $Promotion->id ) )
return $Promotion->id;
else
return false;
}
elseif ( is_int( $name ) ) return $name;
else return false;
}
/**
* Gets a Promotion Name based on Promo ID.
* If $id is an string, it will be returned as the name.
*
* @author Travis Smith
* @since 1.3.0
* @param string|int $id (required) ID of the Promotion.
* @return int $Promotion->name Promotion name.
*/
function shopp_get_promo_name( $id ) {
if ( is_int( $id ) ) {
$Promotion = new Promotion();
$Promotion->load( array( 'id' => $id ) );
if ( ! empty( $Promotion->name ) )
return $Promotion->name;
else
return false;
}
elseif ( is_string( $name ) ) return $name;
else return false;
}
/**
* Gets a Promotion ID based on Promo Name.
* If $name is an integer, it will be returned as the ID.
*
* @author Travis Smith
* @since 1.3.0
* @param string|int $promo (required) Name/ID of the Promotion.
* @return Promotion Object New Promotion Object.
*/
function shopp_promo_duplicate( $promo ) {
if ( is_array( $promo ) ) return false;
// Duplicate
$id = shopp_get_promo_id( $promo );
$Promotion = new Promotion( $id );
$Promotion->duplicate();
// Return newly created Promotion Object
$table = DatabaseObject::tablename(Promotion::$table);
$query = "SELECT id FROM $table ORDER BY id DESC LIMIT 1";
$promo = DB::query( $query, 'array' );
$id = $promo[0]->id;
return new Promotion( $id );
}
/**
* Deletes a or a set of Promotions
*
* @author Travis Smith
* @since 1.3.0
* @param mixed $arg (required) Array Promotion IDs/Names,
* String Name
* Int ID
* @return bool True on deletion; False if invalid/empty.
*/
function shopp_promo_delete( $promos ) {
if ( '' == $promos ) return false;
$delete = array();
// Array of IDs
if ( is_array( $promos ) ) {
// Validate Array
foreach( $promos as $i ) {
if ( is_int( $i ) ) $id = $i;
elseif ( is_string( $i ) ) $id = shopp_get_promo_id( $i );
$delete[] = $id;
}
}
// Else: dealing with a single ID
elseif ( is_int( $promos ) ) {
$delete[] = $promos;
}
// Else: dealing with a single Name
elseif ( is_string( $promos ) ) {
$id = shopp_get_promo_id( $promos );
$delete[] = $id;
}
// Delete the Promotions
if ( ! empty( $delete ) ) {
$Promotion = new Promotion();
$Promotion->deleteset( $delete );
return true;
}
else
return false;
}
/**
* Enables a or a set of Promotions
*
* @author Travis Smith
* @since 1.3.0
* @uses _shopp_promo_method() Helper function that uses the Promotion Class.
* @param mixed $promo (required) Array Promotion IDs/Names,
* String Name
* Int ID
* @return bool True on enablement; False if invalid/empty.
*/
function shopp_promo_enable( $promos ) {
return _shopp_promo_method( $promos );
}
/**
* Helper function that uses the Promotion Class.
*
* @author Travis Smith
* @since 1.3.0
* @see shopp_promo_enable(), shopp_promo_disable(), shopp_promo_used()
* @param mixed $promo (required) Array Promotion IDs/Names,
* String Name
* Int ID
* @return bool True on enablement; False if invalid/empty.
*/
function _shopp_promo_method( $promos, $method = 'enableset' ) {
if ( ! is_array( $promos ) )
$promos = array( shopp_get_promo_id( $promos ) );
if ( is_array( $promos ) )
Promotion::$method( $promos );
else
return false;
return true;
}
/**
* Disables a or a set of Promotions
*
* @author Travis Smith
* @since 1.3.0
* @uses _shopp_promo_method() Helper function that uses the Promotion Class.
* @param mixed $promo (required) Array Promotion IDs/Names,
* String Name
* Int ID
* @return bool True on disablement; False if invalid/empty.
*/
function shopp_promo_disable( $promos ) {
return _shopp_promo_method( $promos, 'disableset' );
}
/**
* Records when a specific promotion is used of an existing promotion.
*
* @author Travis Smith
* @since 1.3.0
* @uses _shopp_promo_method() Helper function that uses the Promotion Class.
* @param mixed $promo (required) Array Promotion IDs/Names,
* String Name
* Int ID
* @return bool True on disablement; False if invalid/empty.
*/
function shopp_promo_used( $promos ) {
return _shopp_promo_method( $promos, 'used' );
}
/**
* Sets discount arguments is used of an existing promotion.
*
* @author Travis Smith
* @since 1.3.0
* @uses _shopp_promo_method() Helper function that uses the Promotion Class.
* @param mixed $promo (required) String Name
* Int ID
* @return bool True on disablement; False if invalid/empty.
* @return Promotion Object Modified Promotion Object.
*/
function shopp_promo_set_discount( $promo, $args ) {
$defaults = array(
'type' => '', //Options: Percentage Off, Amount Off, Free Shipping, Buy X Get Y Free (target must be Cart Item)
'discount' => '',
'buyqty' => '',
'getqty' => '',
);
$args = wp_parse_args( $args, $defaults );
$args['id'] = shopp_get_promo_id( $promo );
// Validate Args
switch( $args['type'] ) {
case 'Percentage Off':
case 'Amount Off':
$args['discount'] = is_numeric( $args['discount'] ) ? $args['discount'] : 0;
if ( ! isset( $args['discount'] ) ) return false;
case 'Free Shipping':
if ( isset( $args['buyqty'] ) ) unset( $args['buyqty'] );
if ( isset( $args['getqty'] ) ) unset( $args['getqty'] );
break;
case 'Buy X Get Y Free':
if ( isset( $args['discount'] ) ) unset( $args['discount'] );
if ( ! isset( $args['buyqty'] ) || ! isset( $args['getqty'] ) ) return false;
$args['buyqty'] = intval( $args['buyqty'] );
$args['getqty'] = intval( $args['getqty'] );
break;
default:
break;
}
// Update Promotion
$Promotion = new Promotion( $args['id'] );
$Promotion->updates( $args );
$Promotion->save();
do_action_ref_array( 'shopp_promo_saved', array( &$Promotion ) );
return $Promotion;
}
/**
* Sets start/end dates is used of an existing promotion.
*
* $args = array(
* 'starts' => array(
* 'month' => 10,
* 'date' => 1,
* 'year' => 2012,
* ),
* 'ends' => array(
* 'month' => 10,
* 'date' => 31,
* 'year' => 2012,
* ),
* );
* $date_set = shopp_promo_set_dates( 9, $args );
*
* @author Travis Smith
* @since 1.3.0
* @uses shopp_get_promo_id() Gets a Promotion ID based on Promo Name.
* @uses shopp_promo_validate_dates() Validates/Sanitizes the date.
* @param mixed $promo (required) String Name
* Int ID
* @return Promotion Object Modified Promotion Object.
*/
function shopp_promo_set_dates( $promo, $args ) {
$defaults = array(
'starts' => '',
'ends' => '',
);
$args = wp_parse_args( $args, $defaults );
$args['id'] = shopp_get_promo_id( $promo );
if ( is_array( $args['starts'] ) )
$args['starts'] = shopp_promo_validate_dates( $args['starts'] );
if ( is_array( $args['ends'] ) )
$args['ends'] = shopp_promo_validate_dates( $args['ends'] );
// Update Promotion
$Promotion = new Promotion( $args['id'] );
$Promotion->updates( $args );
$Promotion->save();
do_action_ref_array( 'shopp_promo_saved', array( &$Promotion ) );
return $Promotion;
}
/**
* Sets discount arguments is used of an existing promotion.
*
* @author Travis Smith
* @since 1.3.0
* @param array $date (required) Array of Month, Day, Year.
* @return string Validated UNIX date.
*/
function shopp_promo_validate_dates( $date ) {
$defaults = array(
'month' => '',
'date' => '',
'year' => '',
);
$date = wp_parse_args( $date, $defaults );
if ( checkdate ( $date['month'], $date['date'], $date['year'] ) )
return mktime( 0, 0, 0, $date['month'], $date['date'], $date['year'] );
else
return '';
}
/**
* Helper function to validate rules.
*
* @author Travis Smith
* @since 1.3.0
* @param array $rules Array of rules / conditions.
* @param string $target Conditions Target.
* @param bool $item Rules array as item.
*/
function _shopp_validate_rules( &$rules, $target, $item = false ) {
$i = 0;
foreach ( (array) $rules as $key => $rule ) {
if ( ! is_numeric( $key ) && 'item' == $key ) {
_shopp_validate_rules( $rule, $target, true );
}
else {
// Validate Property
if ( 'Cart Item' == $target && ! $item )
$rules[$i]['property'] = ( in_array( $rule['property'], _shopp_promo_target_properties( 'Cart' ) ) ) ? $rule['property'] : '';
else
$rules[$i]['property'] = ( in_array( $rule['property'], _shopp_promo_target_properties( $target ) ) ) ? $rule['property'] : '';
// Validate Logic
if ( in_array( $rules['property'], array( 'Name', 'Category', 'Tag name', 'Variation', 'Input name', 'Input Value', ) ) )
$rules[$i]['logic'] = ( in_array( $rule['logic'], _shopp_promo_qual_logic() ) ) ? $rule['logic'] : '';
if ( in_array( $rules['property'], array( 'Price', 'Sales Price', 'In Stock', 'Unit price', 'Total price', 'Discount amount', ) ) )
$rules[$i]['logic'] = ( in_array( $rule['logic'], _shopp_promo_quan_logic() ) ) ? $rule['logic'] : '';
if ( 'Type' == $rules['property'] )
$rules[$i]['logic'] = ( 'Is equal to' == $rule['logic'] ) ? 'Is equal to' : 'Is not equal to';
if ( '' == $rules[$i]['property'] || '' == $rules[$i]['logic'] )
unset( $rules[$i] );
// Increment Rule Counter
$i++;
}
}
}
/**
* Sets Rules / Conditions for an existing promotion.
*
* $defaults = array(
* 'search' => 'any', //Options: any, all
* 'target' => 'Catalog', //Options: Catalog, Cart, Cart Item
* 'rules' => array(),
* // 0 => array( 'property' =>'', 'logic' => '', 'value' => '' ),
* // 1 => array( 'property' =>'', 'logic' => '', 'value' => '' ),
* // 'item' => array( 'property' =>'', 'logic' => '', 'value' => '' ),
* // RULES keyless: ['rules'][#]
* 'property' => '', 'logic' => '', 'value' => '',
* if ( Catalog == target ): ['rules'][#]['property'] = Name, Category, Variation
* Options: Name, Options: Is equal to,
* Category, Is not equal to,
* Variation, Contains,
* Price, Does not contain,
* Sales Price, Begins with,
* Type, Ends with
* In Stock
* if ( Cart == target ): ['rules'][#]['property'] = Price, Sales Price, In Stock
* Options: Any item name, Options: Is equal to,
* Any item quantity, Is not equal to,
* Any item amount, Is greater than,
* Total quantity, Is greater than or equal to,
* Shipping amount, Is less than,
* Subtotal amount, Is less than or equal to
* Discount amount,
* Customer type, ['rules'][#]['property'] = Type
* Ship-to country, Options: Is equal to,
* Promo use count, Is not equal to,
* Promo code,
*
* // RULES item key: ['rules']['item']
* 'item' => array(
* array( 'property' => '', 'logic' => '', 'value' => '', ),
* ),
*
* 'property' => '', 'logic' => '',
* Options: Name, ['rules']['item'][#]['property'] = Name, Category, Tag name, Variation, Input name, Input Value
* Category, Options: Is equal to,
* Tag name, Is not equal to,
* Variation, Contains,
* Input name, Does not contain,
* Input Value, Begins with,
* Quantity, Ends with
* Unit price,
* Total price, ['rules']['item'][#]['property'] = Unit price, Total price, Discount amount
* Discount amount Options: Is equal to,
* Is not equal to,
* Is greater than,
* Is greater than or equal to,
* Is less than,
* Is less than or equal to
* 'value' => '',
*
*
*
* @author Travis Smith
* @since 1.3.0
* @see _shopp_validate_rules() Helper function to validate rules.
* @see _shopp_promo_target_properties() Helper function for condition properties based on target.
* @see _shopp_promo_qual_logic() Helper function for qualitative logic options.
* @see _shopp_promo_quan_logic() Helper function for quantitative logic options.
* @see _shopp_promo_condition_targets() Helper function for condition targets options.
* @param mixed $promo (required) String Name
* Int ID
* @param array $args (required) Array of Conditions/Rules.
* @return Promotion Object Modified Promotion Object.
*/
function shopp_promo_set_conditions( $promo, $args ) {
$defaults = array(
'search' => 'any', //Options: any, all
'target' => 'Catalog', //Options: Catalog, Cart, Cart Item
'rules' => array(),
);
// Setup Arguments & ID
$args = wp_parse_args( $args, $defaults );
$args['id'] = shopp_get_promo_id( $promo );
// Validate/Sanitize $args
$args['target'] = in_array( $args['target'], _shopp_promo_condition_targets() ) ? $args['target'] : '';
$args['search'] = 'any' == $args['target'] ? $args['target'] : 'all';
_shopp_validate_rules( $args['rules'], $args['target'] );
// Rules Valid
// Need to check to make sure there is at least 1 rule
$rules = $args['rules'];
unset( $rules['item'] );
if ( ! count( $rules ) )
$args['rules'][0] = array();
// Update Promotion
$Promotion = new Promotion( $args['id'] );
$Promotion->updates( $args );
$Promotion->save();
do_action_ref_array( 'shopp_promo_saved', array( &$Promotion ) );
return $Promotion;
}
/**
* Helper function for condition properties based on target.
*
* @author Travis Smith
* @since 1.3.0
* @see shopp_promo_set_conditions() Set conditions on an existing promotion.
* @return array Array of condition properties.
*/
function _shopp_promo_target_properties( $target = 'Catalog' ) {
switch( $target ) {
case 'Catalog':
return array( 'Name', 'Category', 'Variation', 'Price', 'Sales Price', 'Type', 'In Stock' );
break;
case 'Cart':
return array( 'Any item name', 'Any item quantity', 'Any item amount', 'Total quantity', 'Shipping amount', 'Subtotal amount', 'Discount amount', 'Customer type', 'Ship-to country', 'Promo use count', 'Promo code' );
break;
case 'Cart Item':
return array( 'Name', 'Category', 'Tag name', 'Variation', 'Input name', 'Input Value', 'Quantity', 'Unit price', 'Total price', 'Discount amount', );
break;
default:
break;
}
return;
}
/**
* Helper function for qualitative logic options.
*
* @author Travis Smith
* @since 1.3.0
* @see shopp_promo_set_conditions() Set conditions on an existing promotion.
* @return array Array of condition targets.
*/
function _shopp_promo_qual_logic() {
return array( 'Is equal to', 'Is not equal to', 'Contains', 'Does not contain', 'Begins with', 'Ends with', );
}
/**
* Helper function for quantitative logic options.
*
* @author Travis Smith
* @since 1.3.0
* @see shopp_promo_set_conditions() Set conditions on an existing promotion.
* @return array Array of condition targets
*/
function _shopp_promo_quan_logic() {
return array( 'Is equal to', 'Is not equal to', 'Is greater than', 'Is greater than or equal to', 'Is less than', 'Is less than or equal to', );
}
/**
* Helper function for condition targets options.
*
* @author Travis Smith
* @since 1.3.0
* @see shopp_promo_set_conditions() Set conditions on an existing promotion.
* @return array Array of condition targets.
*/
function _shopp_promo_condition_targets() {
return array( 'Catalog', 'Cart', 'Cart Item' );
}
/**
* Create Shopp Coupon Promotion.
*
* @author Travis Smith
* @since 1.3.0
* @uses shopp_create_promo() Creates a new promotion.
* @param mixed $promo (required) Array Promotion IDs/Names,
* String Name
* Int ID
* @param array $args (required) Array of arguments needed to create Promo.
* @return Promotion Object New Promotion Object.
*/
function shopp_create_coupon( $promo, $args = array() ) {
$defaults = array(
'type' => 'Percentage Off',
'discount' => '10',
'target' => 'Cart',
'rules' => array(
array(
'property' => 'Promo code',
'logic' => 'Is equal to',
'value' => $promo,
),
array(
'property' => 'Promo use count',
'logic' => 'Is less than',
'value' => '1'
),
),
);
$args = wp_parse_args( $args, $defaults );
return shopp_create_promo( $promo, $args );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment