2016-02-17 19:29:09 +00:00
< ? php
/**
* REST API Coupons controller
*
* Handles requests to the / coupons endpoint .
*
* @ author WooThemes
* @ category API
* @ package WooCommerce / API
* @ since 2.6 . 0
*/
if ( ! defined ( 'ABSPATH' ) ) {
exit ;
}
/**
* REST API Coupons controller class .
*
* @ package WooCommerce / API
2016-02-22 19:43:52 +00:00
* @ extends WC_REST_Posts_Controller
2016-02-17 19:29:09 +00:00
*/
2016-02-22 19:43:52 +00:00
class WC_REST_Coupons_Controller extends WC_REST_Posts_Controller {
2016-02-17 19:29:09 +00:00
2016-03-07 18:36:17 +00:00
/**
* Endpoint namespace .
*
* @ var string
*/
2016-03-31 18:25:31 +00:00
protected $namespace = 'wc/v1' ;
2016-03-07 18:36:17 +00:00
2016-02-17 19:29:09 +00:00
/**
* Route base .
*
* @ var string
*/
2016-02-22 18:49:38 +00:00
protected $rest_base = 'coupons' ;
2016-02-17 19:29:09 +00:00
/**
2016-02-22 19:43:52 +00:00
* Post type .
2016-02-17 19:29:09 +00:00
*
* @ var string
*/
2016-02-22 19:43:52 +00:00
protected $post_type = 'shop_coupon' ;
2016-02-17 19:29:09 +00:00
2016-03-30 21:42:51 +00:00
/**
* Order refunds actions .
*/
public function __construct () {
add_filter ( " woocommerce_rest_ { $this -> post_type } _query " , array ( $this , 'query_args' ), 10 , 2 );
}
2016-02-17 19:29:09 +00:00
/**
* Register the routes for coupons .
*/
public function register_routes () {
2016-03-07 18:36:17 +00:00
register_rest_route ( $this -> namespace , '/' . $this -> rest_base , array (
2016-02-23 15:16:21 +00:00
array (
'methods' => WP_REST_Server :: READABLE ,
'callback' => array ( $this , 'get_items' ),
'permission_callback' => array ( $this , 'get_items_permissions_check' ),
'args' => $this -> get_collection_params (),
),
2016-02-26 20:24:33 +00:00
array (
'methods' => WP_REST_Server :: CREATABLE ,
'callback' => array ( $this , 'create_item' ),
'permission_callback' => array ( $this , 'create_item_permissions_check' ),
2016-03-01 20:59:02 +00:00
'args' => array_merge ( $this -> get_endpoint_args_for_item_schema ( WP_REST_Server :: CREATABLE ), array (
'code' => array (
'required' => true ,
),
) ),
2016-02-26 20:24:33 +00:00
),
'schema' => array ( $this , 'get_public_item_schema' ),
2016-02-23 15:16:21 +00:00
) );
2016-03-07 18:36:17 +00:00
register_rest_route ( $this -> namespace , '/' . $this -> rest_base . '/(?P<id>[\d]+)' , array (
2016-02-22 19:44:47 +00:00
array (
'methods' => WP_REST_Server :: READABLE ,
'callback' => array ( $this , 'get_item' ),
'permission_callback' => array ( $this , 'get_item_permissions_check' ),
'args' => array (
'context' => $this -> get_context_param ( array ( 'default' => 'view' ) ),
),
),
2016-02-26 20:24:33 +00:00
array (
'methods' => WP_REST_Server :: EDITABLE ,
'callback' => array ( $this , 'update_item' ),
'permission_callback' => array ( $this , 'update_item_permissions_check' ),
'args' => $this -> get_endpoint_args_for_item_schema ( WP_REST_Server :: EDITABLE ),
),
2016-02-23 18:28:43 +00:00
array (
'methods' => WP_REST_Server :: DELETABLE ,
'callback' => array ( $this , 'delete_item' ),
'permission_callback' => array ( $this , 'delete_item_permissions_check' ),
'args' => array (
'force' => array (
'default' => false ,
'description' => __ ( 'Whether to bypass trash and force deletion.' , 'woocommerce' ),
),
),
),
2016-02-26 20:24:33 +00:00
'schema' => array ( $this , 'get_public_item_schema' ),
2016-02-22 19:44:47 +00:00
) );
2016-05-11 19:34:53 +00:00
register_rest_route ( $this -> namespace , '/' . $this -> rest_base . '/batch' , array (
array (
'methods' => WP_REST_Server :: EDITABLE ,
'callback' => array ( $this , 'batch_items' ),
'permission_callback' => array ( $this , 'batch_items_permissions_check' ),
'args' => $this -> get_endpoint_args_for_item_schema ( WP_REST_Server :: EDITABLE ),
),
'schema' => array ( $this , 'get_public_batch_schema' ),
) );
2016-02-22 19:44:47 +00:00
}
2016-03-30 21:42:51 +00:00
/**
* Query args .
*
* @ param array $args
* @ param WP_REST_Request $request
* @ return array
*/
public function query_args ( $args , $request ) {
global $wpdb ;
if ( ! empty ( $request [ 'code' ] ) ) {
$id = $wpdb -> get_var ( $wpdb -> prepare ( " SELECT id FROM $wpdb->posts WHERE post_title = %s AND post_type = 'shop_coupon' AND post_status = 'publish' " , $request [ 'code' ] ) );
$args [ 'post__in' ] = array ( $id );
}
return $args ;
}
2016-02-22 19:44:47 +00:00
/**
* Prepare a single coupon output for response .
*
* @ param WP_Post $post Post object .
* @ param WP_REST_Request $request Request object .
* @ return WP_REST_Response $data
*/
public function prepare_item_for_response ( $post , $request ) {
2016-08-26 14:20:44 +00:00
$code = wc_get_coupon_code_by_id ( $post -> ID );
$coupon = new WC_Coupon ( $code );
$data = $coupon -> get_data ();
$format_decimal = array ( 'amount' , 'minimum_amount' , 'maximum_amount' );
$format_date = array ( 'date_created' , 'date_modified' , 'date_expires' );
// Format decimal values.
foreach ( $format_decimal as $key ) {
2016-08-26 14:24:01 +00:00
$data [ $key ] = wc_format_decimal ( $data [ $key ], 2 );
2016-08-26 14:20:44 +00:00
}
2016-02-22 19:44:47 +00:00
2016-08-26 14:20:44 +00:00
// Format date values.
foreach ( $format_date as $key ) {
$data [ $key ] = $data [ $key ] ? wc_rest_prepare_date_response ( get_gmt_from_date ( date ( 'Y-m-d H:i:s' , $data [ $key ] ) ) ) : false ;
}
2016-02-22 19:44:47 +00:00
2016-08-26 14:20:44 +00:00
$context = ! empty ( $request [ 'context' ] ) ? $request [ 'context' ] : 'view' ;
$data = $this -> add_additional_fields_to_object ( $data , $request );
$data = $this -> filter_response_by_context ( $data , $context );
2016-02-22 19:44:47 +00:00
$response = rest_ensure_response ( $data );
2016-03-15 19:53:51 +00:00
$response -> add_links ( $this -> prepare_links ( $post ) );
2016-02-22 19:44:47 +00:00
/**
* Filter the data for a response .
*
* The dynamic portion of the hook name , $this -> post_type , refers to post_type of the post being
* prepared for the response .
*
* @ param WP_REST_Response $response The response object .
* @ param WP_Post $post Post object .
* @ param WP_REST_Request $request Request object .
*/
2016-03-15 20:22:53 +00:00
return apply_filters ( " woocommerce_rest_prepare_ { $this -> post_type } " , $response , $post , $request );
2016-02-17 19:29:09 +00:00
}
2016-02-26 20:24:33 +00:00
2016-08-26 14:42:42 +00:00
/**
* Only reutrn writeable props from schema .
* @ param array $schema
* @ return bool
*/
protected function filter_writable_props ( $schema ) {
return empty ( $schema [ 'readonly' ] );
}
2016-02-26 20:24:33 +00:00
/**
* Prepare a single coupon for create or update .
*
* @ param WP_REST_Request $request Request object .
* @ return WP_Error | stdClass $data Post object .
*/
protected function prepare_item_for_database ( $request ) {
2016-08-26 15:15:18 +00:00
global $wpdb ;
2016-08-26 14:42:42 +00:00
$id = isset ( $request [ 'id' ] ) ? absint ( $request [ 'id' ] ) : 0 ;
$coupon = new WC_Coupon ( $id );
$schema = $this -> get_item_schema ();
$data_keys = array_keys ( array_filter ( $schema [ 'properties' ], array ( $this , 'filter_writable_props' ) ) );
2016-02-26 20:24:33 +00:00
2016-03-29 22:11:49 +00:00
// Validate required POST fields.
2016-08-24 04:50:12 +00:00
if ( 'POST' === $request -> get_method () && 0 === $coupon -> get_id () ) {
2016-03-29 22:11:49 +00:00
if ( empty ( $request [ 'code' ] ) ) {
return new WP_Error ( 'woocommerce_rest_empty_coupon_code' , sprintf ( __ ( 'The coupon code cannot be empty.' , 'woocommerce' ), 'code' ), array ( 'status' => 400 ) );
}
}
2016-08-26 14:42:42 +00:00
// Handle all writable props
foreach ( $data_keys as $key ) {
$value = $request [ $key ];
if ( ! is_null ( $value ) ) {
switch ( $key ) {
case 'code' :
$coupon_code = apply_filters ( 'woocommerce_coupon_code' , $value );
$id = $coupon -> get_id () ? $coupon -> get_id () : 0 ;
// Check for duplicate coupon codes.
$coupon_found = $wpdb -> get_var ( $wpdb -> prepare ( "
SELECT $wpdb -> posts . ID
FROM $wpdb -> posts
WHERE $wpdb -> posts . post_type = 'shop_coupon'
AND $wpdb -> posts . post_status = 'publish'
AND $wpdb -> posts . post_title = % s
AND $wpdb -> posts . ID != % s
" , $coupon_code , $id ) );
if ( $coupon_found ) {
return new WP_Error ( 'woocommerce_rest_coupon_code_already_exists' , __ ( 'The coupon code already exists' , 'woocommerce' ), array ( 'status' => 400 ) );
}
$coupon -> set_code ( $coupon_code );
break ;
case 'meta_data' :
if ( is_array ( $value ) ) {
foreach ( $value as $meta ) {
$coupon -> update_meta_data ( $meta [ 'key' ], $meta [ 'value' ], $meta [ 'id' ] );
}
}
break ;
case 'description' :
$coupon -> set_description ( wp_filter_post_kses ( $value ) );
break ;
default :
if ( is_callable ( array ( $coupon , " set_ { $key } " ) ) ) {
$coupon -> { " set_ { $key } " }( $value );
}
break ;
}
2016-02-26 20:24:33 +00:00
}
}
/**
* Filter the query_vars used in `get_items` for the constructed query .
*
* The dynamic portion of the hook name , $this -> post_type , refers to post_type of the post being
* prepared for insertion .
*
2016-08-26 14:42:42 +00:00
* @ param WC_Coupon $coupon The coupon object .
2016-02-26 20:24:33 +00:00
* @ param WP_REST_Request $request Request object .
*/
2016-08-22 22:06:21 +00:00
return apply_filters ( " woocommerce_rest_pre_insert_ { $this -> post_type } " , $coupon , $request );
}
/**
* Create a single item .
*
* @ param WP_REST_Request $request Full details about the request .
* @ return WP_Error | WP_REST_Response
*/
public function create_item ( $request ) {
if ( ! empty ( $request [ 'id' ] ) ) {
return new WP_Error ( " woocommerce_rest_ { $this -> post_type } _exists " , sprintf ( __ ( 'Cannot create existing %s.' , 'woocommerce' ), $this -> post_type ), array ( 'status' => 400 ) );
}
$coupon_id = $this -> save_coupon ( $request );
if ( is_wp_error ( $coupon_id ) ) {
return $coupon_id ;
}
$post = get_post ( $coupon_id );
$this -> update_additional_fields_for_object ( $post , $request );
$this -> add_post_meta_fields ( $post , $request );
/**
* Fires after a single item is created or updated via the REST API .
*
* @ param object $post Inserted object ( not a WP_Post object ) .
* @ param WP_REST_Request $request Request object .
* @ param boolean $creating True when creating item , false when updating .
*/
do_action ( " woocommerce_rest_insert_ { $this -> post_type } " , $post , $request , true );
$request -> set_param ( 'context' , 'edit' );
$response = $this -> prepare_item_for_response ( $post , $request );
$response = rest_ensure_response ( $response );
$response -> set_status ( 201 );
$response -> header ( 'Location' , rest_url ( sprintf ( '/%s/%s/%d' , $this -> namespace , $this -> rest_base , $post -> ID ) ) );
return $response ;
}
/**
* Update a single coupon .
*
* @ param WP_REST_Request $request Full details about the request .
* @ return WP_Error | WP_REST_Response
*/
public function update_item ( $request ) {
2016-08-26 14:20:44 +00:00
try {
$post_id = ( int ) $request [ 'id' ];
2016-08-22 22:06:21 +00:00
2016-08-26 14:20:44 +00:00
if ( empty ( $post_id ) || $this -> post_type !== get_post_type ( $post_id ) ) {
return new WP_Error ( " woocommerce_rest_ { $this -> post_type } _invalid_id " , __ ( 'ID is invalid.' , 'woocommerce' ), array ( 'status' => 400 ) );
}
2016-08-22 22:06:21 +00:00
2016-08-26 14:20:44 +00:00
$coupon_id = $this -> save_coupon ( $request );
if ( is_wp_error ( $coupon_id ) ) {
return $coupon_id ;
}
2016-08-22 22:06:21 +00:00
2016-08-26 14:20:44 +00:00
$post = get_post ( $coupon_id );
$this -> update_additional_fields_for_object ( $post , $request );
/**
* Fires after a single item is created or updated via the REST API .
*
* @ param object $post Inserted object ( not a WP_Post object ) .
* @ param WP_REST_Request $request Request object .
* @ param boolean $creating True when creating item , false when updating .
*/
do_action ( " woocommerce_rest_insert_ { $this -> post_type } " , $post , $request , false );
$request -> set_param ( 'context' , 'edit' );
$response = $this -> prepare_item_for_response ( $post , $request );
return rest_ensure_response ( $response );
} catch ( Exception $e ) {
return new WP_Error ( $e -> getErrorCode (), $e -> getMessage (), array ( 'status' => $e -> getCode () ) );
}
2016-08-22 22:06:21 +00:00
}
/**
* Saves a coupon to the database .
*/
public function save_coupon ( $request ) {
2016-08-26 14:42:42 +00:00
try {
$coupon = $this -> prepare_item_for_database ( $request );
$coupon -> save ();
return $coupon -> get_id ();
} catch ( WC_Data_Exception $e ) {
return new WP_Error ( $e -> getErrorCode (), $e -> getMessage (), array ( 'status' => $e -> getCode () ) );
} catch ( WC_REST_Exception $e ) {
return new WP_Error ( $e -> getErrorCode (), $e -> getMessage (), array ( 'status' => $e -> getCode () ) );
2016-02-26 20:24:33 +00:00
}
}
/**
2016-03-10 00:34:14 +00:00
* Get the Coupon ' s schema , conforming to JSON Schema .
2016-02-26 20:24:33 +00:00
*
* @ return array
*/
public function get_item_schema () {
$schema = array (
'$schema' => 'http://json-schema.org/draft-04/schema#' ,
'title' => $this -> post_type ,
'type' => 'object' ,
'properties' => array (
'id' => array (
'description' => __ ( 'Unique identifier for the object.' , 'woocommerce' ),
'type' => 'integer' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
),
'code' => array (
'description' => __ ( 'Coupon code.' , 'woocommerce' ),
'type' => 'string' ,
'context' => array ( 'view' , 'edit' ),
),
2016-03-30 17:53:46 +00:00
'date_created' => array (
2016-02-26 20:24:33 +00:00
'description' => __ ( " The date the coupon was created, in the site's timezone. " , 'woocommerce' ),
'type' => 'date-time' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
),
2016-03-30 17:53:46 +00:00
'date_modified' => array (
2016-02-26 20:24:33 +00:00
'description' => __ ( " The date the coupon was last modified, in the site's timezone. " , 'woocommerce' ),
'type' => 'date-time' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
),
2016-03-31 19:32:12 +00:00
'description' => array (
'description' => __ ( 'Coupon description.' , 'woocommerce' ),
'type' => 'string' ,
'context' => array ( 'view' , 'edit' ),
),
'discount_type' => array (
'description' => __ ( 'Determines the type of discount that will be applied.' , 'woocommerce' ),
'type' => 'string' ,
2016-04-28 21:38:35 +00:00
'default' => 'fixed_cart' ,
2016-03-31 19:32:12 +00:00
'enum' => array_keys ( wc_get_coupon_types () ),
'context' => array ( 'view' , 'edit' ),
),
2016-02-26 20:24:33 +00:00
'amount' => array (
'description' => __ ( 'The amount of discount.' , 'woocommerce' ),
2016-06-20 20:20:12 +00:00
'type' => 'string' ,
2016-02-26 20:24:33 +00:00
'context' => array ( 'view' , 'edit' ),
),
2016-08-26 14:20:44 +00:00
'date_expires' => array (
2016-03-31 19:32:12 +00:00
'description' => __ ( 'UTC DateTime when the coupon expires.' , 'woocommerce' ),
'type' => 'string' ,
'context' => array ( 'view' , 'edit' ),
),
'usage_count' => array (
'description' => __ ( 'Number of times the coupon has been used already.' , 'woocommerce' ),
'type' => 'integer' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
),
2016-02-26 20:24:33 +00:00
'individual_use' => array (
'description' => __ ( 'Whether coupon can only be used individually.' , 'woocommerce' ),
'type' => 'boolean' ,
2016-04-28 21:38:35 +00:00
'default' => false ,
2016-02-26 20:24:33 +00:00
'context' => array ( 'view' , 'edit' ),
),
'product_ids' => array (
'description' => __ ( " List of product ID's the coupon can be used on. " , 'woocommerce' ),
'type' => 'array' ,
'context' => array ( 'view' , 'edit' ),
),
'exclude_product_ids' => array (
'description' => __ ( " List of product ID's the coupon cannot be used on. " , 'woocommerce' ),
'type' => 'array' ,
'context' => array ( 'view' , 'edit' ),
),
'usage_limit' => array (
'description' => __ ( 'How many times the coupon can be used.' , 'woocommerce' ),
'type' => 'integer' ,
'context' => array ( 'view' , 'edit' ),
),
'usage_limit_per_user' => array (
2016-04-23 04:32:22 +00:00
'description' => __ ( 'How many times the coupon can be used per customer.' , 'woocommerce' ),
2016-02-26 20:24:33 +00:00
'type' => 'integer' ,
'context' => array ( 'view' , 'edit' ),
),
'limit_usage_to_x_items' => array (
'description' => __ ( 'Max number of items in the cart the coupon can be applied to.' , 'woocommerce' ),
'type' => 'integer' ,
'context' => array ( 'view' , 'edit' ),
),
2016-03-31 19:32:12 +00:00
'free_shipping' => array (
2016-02-26 20:24:33 +00:00
'description' => __ ( 'Define if can be applied for free shipping.' , 'woocommerce' ),
'type' => 'boolean' ,
2016-04-28 21:38:35 +00:00
'default' => false ,
2016-02-26 20:24:33 +00:00
'context' => array ( 'view' , 'edit' ),
),
2016-03-31 19:32:12 +00:00
'product_categories' => array (
2016-02-26 20:24:33 +00:00
'description' => __ ( " List of category ID's the coupon applies to. " , 'woocommerce' ),
'type' => 'array' ,
'context' => array ( 'view' , 'edit' ),
),
2016-03-31 19:32:12 +00:00
'excluded_product_categories' => array (
2016-02-26 20:24:33 +00:00
'description' => __ ( " List of category ID's the coupon does not apply to. " , 'woocommerce' ),
'type' => 'array' ,
'context' => array ( 'view' , 'edit' ),
),
'exclude_sale_items' => array (
'description' => __ ( 'Define if should not apply when have sale items.' , 'woocommerce' ),
'type' => 'boolean' ,
2016-04-28 21:38:35 +00:00
'default' => false ,
2016-02-26 20:24:33 +00:00
'context' => array ( 'view' , 'edit' ),
),
'minimum_amount' => array (
'description' => __ ( 'Minimum order amount that needs to be in the cart before coupon applies.' , 'woocommerce' ),
2016-06-20 20:20:12 +00:00
'type' => 'string' ,
2016-02-26 20:24:33 +00:00
'context' => array ( 'view' , 'edit' ),
),
'maximum_amount' => array (
'description' => __ ( 'Maximum order amount allowed when using the coupon.' , 'woocommerce' ),
2016-06-20 20:20:12 +00:00
'type' => 'string' ,
2016-02-26 20:24:33 +00:00
'context' => array ( 'view' , 'edit' ),
),
2016-03-31 19:32:12 +00:00
'email_restrictions' => array (
2016-02-26 20:24:33 +00:00
'description' => __ ( 'List of email addresses that can use this coupon.' , 'woocommerce' ),
'type' => 'array' ,
'context' => array ( 'view' , 'edit' ),
),
2016-03-31 19:32:12 +00:00
'used_by' => array (
'description' => __ ( 'List of user IDs who have used the coupon.' , 'woocommerce' ),
'type' => 'array' ,
2016-02-26 20:24:33 +00:00
'context' => array ( 'view' , 'edit' ),
2016-03-31 19:32:12 +00:00
'readonly' => true ,
2016-02-26 20:24:33 +00:00
),
),
);
2016-06-30 21:25:39 +00:00
return $this -> add_additional_fields_schema ( $schema );
2016-02-26 20:24:33 +00:00
}
2016-03-30 21:42:51 +00:00
/**
* Get the query params for collections of attachments .
*
* @ return array
*/
public function get_collection_params () {
$params = parent :: get_collection_params ();
$params [ 'code' ] = array (
'description' => __ ( 'Limit result set to resources with a specific code.' , 'woocommerce' ),
'type' => 'string' ,
'sanitize_callback' => 'sanitize_text_field' ,
'validate_callback' => 'rest_validate_request_arg' ,
);
return $params ;
}
2016-02-17 19:29:09 +00:00
}