Created coupons POST and PUT endpoints and coupons schema

This commit is contained in:
Claudio Sanches 2016-02-26 17:24:33 -03:00
parent 7593285824
commit 53db5ff4c8
2 changed files with 588 additions and 2 deletions

View File

@ -51,6 +51,23 @@ abstract class WC_REST_Posts_Controller extends WP_REST_Controller {
return true; return true;
} }
/**
* Check if a given request has access to create an item.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function create_item_permissions_check( $request ) {
$post_type = get_post_type_object( $this->post_type );
if ( ! current_user_can( $post_type->cap->create_posts ) ) {
return new WP_Error( 'woocommerce_rest_cannot_create', sprintf( __( 'Sorry, you are not allowed to create a new %s.', 'woocommerce' ), $this->post_type ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/** /**
* Check if a given request has access to read items. * Check if a given request has access to read items.
* *
@ -63,6 +80,23 @@ abstract class WC_REST_Posts_Controller extends WP_REST_Controller {
return current_user_can( $post_type->cap->read_private_posts ); return current_user_can( $post_type->cap->read_private_posts );
} }
/**
* Check if a given request has access to update an item.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function update_item_permissions_check( $request ) {
$post = get_post( $request['id'] );
$post_type = get_post_type_object( $this->post_type );
if ( $post && ! $this->check_update_permission( $post ) ) {
return new WP_Error( 'woocommerce_rest_cannot_edit', sprintf( __( 'Sorry, you are not allowed to update this %s.', 'woocommerce' ), $this->post_type ), array( 'status' => rest_authorization_required_code() ) );;
}
return true;
}
/** /**
* Check if a given request has access to delete an item. * Check if a given request has access to delete an item.
* *
@ -70,7 +104,6 @@ abstract class WC_REST_Posts_Controller extends WP_REST_Controller {
* @return bool|WP_Error * @return bool|WP_Error
*/ */
public function delete_item_permissions_check( $request ) { public function delete_item_permissions_check( $request ) {
$post = get_post( $request['id'] ); $post = get_post( $request['id'] );
if ( $post && ! $this->check_delete_permission( $post ) ) { if ( $post && ! $this->check_delete_permission( $post ) ) {
@ -94,7 +127,18 @@ abstract class WC_REST_Posts_Controller extends WP_REST_Controller {
} }
/** /**
* Check if we can delete a post. * Check if we can edit an item.
*
* @param object $post Post object.
* @return boolean Can we edit it?
*/
protected function check_update_permission( $post ) {
$post_type = get_post_type_object( $this->post_type );
return current_user_can( $post_type->cap->edit_post, $post->ID );
}
/**
* Check if we can delete an item.
* *
* @param object $post Post object. * @param object $post Post object.
* @return boolean Can we delete it? * @return boolean Can we delete it?
@ -128,6 +172,178 @@ abstract class WC_REST_Posts_Controller extends WP_REST_Controller {
return $response; return $response;
} }
/**
* 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 ) );
}
$post = $this->prepare_item_for_database( $request );
if ( is_wp_error( $post ) ) {
return $post;
}
$post->post_type = $this->post_type;
$post_id = wp_insert_post( $post, true );
if ( is_wp_error( $post_id ) ) {
if ( in_array( $post_id->get_error_code(), array( 'db_insert_error' ) ) ) {
$post_id->add_data( array( 'status' => 500 ) );
} else {
$post_id->add_data( array( 'status' => 400 ) );
}
return $post_id;
}
$post->ID = $post_id;
$schema = $this->get_item_schema();
// if ( ! empty( $schema['properties']['sticky'] ) ) {
// if ( ! empty( $request['sticky'] ) ) {
// stick_post( $post_id );
// } else {
// unstick_post( $post_id );
// }
// }
// if ( ! empty( $schema['properties']['featured_media'] ) && isset( $request['featured_media'] ) ) {
// $this->handle_featured_media( $request['featured_media'], $post->ID );
// }
// $terms_update = $this->handle_terms( $post->ID, $request );
// if ( is_wp_error( $terms_update ) ) {
// return $terms_update;
// }
$post = get_post( $post_id );
$this->update_additional_fields_for_object( $post, $request );
// Add meta fields.
$meta_fields = $this->add_post_meta_fields( $post, $request );
if ( is_wp_error( $meta_fields ) ) {
// Remove post.
wp_delete_post( $post->ID, true );
return $meta_fields;
}
/**
* 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', WC_API::REST_API_NAMESPACE, $this->rest_base, $post_id ) ) );
return $response;
}
/**
* Add post meta fields.
*
* @param WP_Post $post
* @param WP_REST_Request $request
* @return bool|WP_Error
*/
protected function add_post_meta_fields( $post, $request ) {
return true;
}
/**
* Update a single post.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|WP_REST_Response
*/
public function update_item( $request ) {
$id = (int) $request['id'];
$post = get_post( $id );
if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce' ), array( 'status' => 400 ) );
}
$post = $this->prepare_item_for_database( $request );
if ( is_wp_error( $post ) ) {
return $post;
}
// Convert the post object to an array, otherwise wp_update_post will expect non-escaped input.
$post_id = wp_update_post( (array) $post, true );
if ( is_wp_error( $post_id ) ) {
if ( in_array( $post_id->get_error_code(), array( 'db_update_error' ) ) ) {
$post_id->add_data( array( 'status' => 500 ) );
} else {
$post_id->add_data( array( 'status' => 400 ) );
}
return $post_id;
}
$schema = $this->get_item_schema();
// if ( ! empty( $schema['properties']['featured_media'] ) && isset( $request['featured_media'] ) ) {
// $this->handle_featured_media( $request['featured_media'], $post_id );
// }
// if ( ! empty( $schema['properties']['sticky'] ) && isset( $request['sticky'] ) ) {
// if ( ! empty( $request['sticky'] ) ) {
// stick_post( $post_id );
// } else {
// unstick_post( $post_id );
// }
// }
// $terms_update = $this->handle_terms( $post->ID, $request );
// if ( is_wp_error( $terms_update ) ) {
// return $terms_update;
// }
$post = get_post( $post_id );
$this->update_additional_fields_for_object( $post, $request );
// Update meta fields.
$meta_fields = $this->update_post_meta_fields( $post, $request );
if ( is_wp_error( $meta_fields ) ) {
return $meta_fields;
}
/**
* 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 );
return rest_ensure_response( $response );
}
/**
* Update post meta fields.
*
* @param WP_Post $post
* @param WP_REST_Request $request
* @return bool|WP_Error
*/
protected function update_post_meta_fields( $post, $request ) {
return true;
}
/** /**
* Get a collection of posts. * Get a collection of posts.
* *

View File

@ -47,6 +47,13 @@ class WC_REST_Coupons_Controller extends WC_REST_Posts_Controller {
'permission_callback' => array( $this, 'get_items_permissions_check' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ),
'args' => $this->get_collection_params(), 'args' => $this->get_collection_params(),
), ),
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'create_item' ),
'permission_callback' => array( $this, 'create_item_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
),
'schema' => array( $this, 'get_public_item_schema' ),
) ); ) );
register_rest_route( WC_API::REST_API_NAMESPACE, '/' . $this->rest_base . '/(?P<id>[\d]+)', array( register_rest_route( WC_API::REST_API_NAMESPACE, '/' . $this->rest_base . '/(?P<id>[\d]+)', array(
@ -58,6 +65,12 @@ class WC_REST_Coupons_Controller extends WC_REST_Posts_Controller {
'context' => $this->get_context_param( array( 'default' => 'view' ) ), 'context' => $this->get_context_param( array( 'default' => 'view' ) ),
), ),
), ),
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 ),
),
array( array(
'methods' => WP_REST_Server::DELETABLE, 'methods' => WP_REST_Server::DELETABLE,
'callback' => array( $this, 'delete_item' ), 'callback' => array( $this, 'delete_item' ),
@ -69,6 +82,7 @@ class WC_REST_Coupons_Controller extends WC_REST_Posts_Controller {
), ),
), ),
), ),
'schema' => array( $this, 'get_public_item_schema' ),
) ); ) );
} }
@ -131,4 +145,360 @@ class WC_REST_Coupons_Controller extends WC_REST_Posts_Controller {
*/ */
return apply_filters( 'woocommerce_rest_prepare_' . $this->post_type, $response, $post, $request ); return apply_filters( 'woocommerce_rest_prepare_' . $this->post_type, $response, $post, $request );
} }
/**
* 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 ) {
global $wpdb;
$data = new stdClass;
// ID.
if ( isset( $request['id'] ) ) {
$data->ID = absint( $request['id'] );
}
$schema = $this->get_item_schema();
// Validate required POST fields.
if ( 'POST' === $request->get_method() && empty( $data->ID ) ) {
if ( empty( $request['code'] ) ) {
return new WP_Error( 'woocommerce_rest_missing_parameter', sprintf( __( 'Missing parameter %s.', 'woocommerce' ), 'code' ), array( 'status' => 400 ) );
}
}
// Code.
if ( ! empty( $schema['properties']['code'] ) && ! empty( $request['code'] ) ) {
$coupon_code = apply_filters( 'woocommerce_coupon_code', $request['code'] );
$id = isset( $data->ID ) ? $data->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 ) );
}
$data->post_title = $coupon_code;
}
// Content.
$data->post_content = '';
// Excerpt.
if ( ! empty( $schema['properties']['excerpt'] ) && isset( $request['description'] ) ) {
$data->post_excerpt = wp_filter_post_kses( $request['description'] );
}
// Post type.
$data->post_type = $this->post_type;
// Post status.
$data->post_status = 'publish';
// Comment status.
$data->comment_status = 'closed';
// Ping status.
$data->ping_status = 'closed';
/**
* 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.
*
* @param stdClass $data An object representing a single item prepared
* for inserting or updating the database.
* @param WP_REST_Request $request Request object.
*/
return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}", $data, $request );
}
/**
* Expiry date format.
*
* @param string $expiry_date
* @return string
*/
protected function get_coupon_expiry_date( $expiry_date ) {
if ( '' != $expiry_date ) {
return date( 'Y-m-d', strtotime( $expiry_date ) );
}
return '';
}
/**
* Add post meta fields.
*
* @param WP_Post $post
* @param WP_REST_Request $request
* @return bool|WP_Error
*/
protected function add_post_meta_fields( $post, $request ) {
$data = $request->get_json_params();
$defaults = array(
'type' => 'fixed_cart',
'amount' => 0,
'individual_use' => false,
'product_ids' => array(),
'exclude_product_ids' => array(),
'usage_limit' => '',
'usage_limit_per_user' => '',
'limit_usage_to_x_items' => '',
'usage_count' => '',
'expiry_date' => '',
'enable_free_shipping' => false,
'product_category_ids' => array(),
'exclude_product_category_ids' => array(),
'exclude_sale_items' => false,
'minimum_amount' => '',
'maximum_amount' => '',
'customer_emails' => array(),
'description' => ''
);
$data = wp_parse_args( $data, $defaults );
// Set coupon meta.
update_post_meta( $post->ID, 'discount_type', $data['type'] );
update_post_meta( $post->ID, 'coupon_amount', wc_format_decimal( $data['amount'] ) );
update_post_meta( $post->ID, 'individual_use', ( true === $data['individual_use'] ) ? 'yes' : 'no' );
update_post_meta( $post->ID, 'product_ids', implode( ',', array_filter( array_map( 'intval', $data['product_ids'] ) ) ) );
update_post_meta( $post->ID, 'exclude_product_ids', implode( ',', array_filter( array_map( 'intval', $data['exclude_product_ids'] ) ) ) );
update_post_meta( $post->ID, 'usage_limit', absint( $data['usage_limit'] ) );
update_post_meta( $post->ID, 'usage_limit_per_user', absint( $data['usage_limit_per_user'] ) );
update_post_meta( $post->ID, 'limit_usage_to_x_items', absint( $data['limit_usage_to_x_items'] ) );
update_post_meta( $post->ID, 'usage_count', absint( $data['usage_count'] ) );
update_post_meta( $post->ID, 'expiry_date', $this->get_coupon_expiry_date( wc_clean( $data['expiry_date'] ) ) );
update_post_meta( $post->ID, 'free_shipping', ( true === $data['enable_free_shipping'] ) ? 'yes' : 'no' );
update_post_meta( $post->ID, 'product_categories', array_filter( array_map( 'intval', $data['product_category_ids'] ) ) );
update_post_meta( $post->ID, 'exclude_product_categories', array_filter( array_map( 'intval', $data['exclude_product_category_ids'] ) ) );
update_post_meta( $post->ID, 'exclude_sale_items', ( true === $data['exclude_sale_items'] ) ? 'yes' : 'no' );
update_post_meta( $post->ID, 'minimum_amount', wc_format_decimal( $data['minimum_amount'] ) );
update_post_meta( $post->ID, 'maximum_amount', wc_format_decimal( $data['maximum_amount'] ) );
update_post_meta( $post->ID, 'customer_email', array_filter( array_map( 'sanitize_email', $data['customer_emails'] ) ) );
return true;
}
/**
* Update post meta fields.
*
* @param WP_Post $post
* @param WP_REST_Request $request
* @return bool|WP_Error
*/
protected function update_post_meta_fields( $post, $request ) {
if ( isset( $request['amount'] ) ) {
update_post_meta( $post->ID, 'coupon_amount', wc_format_decimal( $request['amount'] ) );
}
if ( isset( $request['individual_use'] ) ) {
update_post_meta( $post->ID, 'individual_use', ( true === $request['individual_use'] ) ? 'yes' : 'no' );
}
if ( isset( $request['product_ids'] ) ) {
update_post_meta( $post->ID, 'product_ids', implode( ',', array_filter( array_map( 'intval', $request['product_ids'] ) ) ) );
}
if ( isset( $request['exclude_product_ids'] ) ) {
update_post_meta( $post->ID, 'exclude_product_ids', implode( ',', array_filter( array_map( 'intval', $request['exclude_product_ids'] ) ) ) );
}
if ( isset( $request['usage_limit'] ) ) {
update_post_meta( $post->ID, 'usage_limit', absint( $request['usage_limit'] ) );
}
if ( isset( $request['usage_limit_per_user'] ) ) {
update_post_meta( $post->ID, 'usage_limit_per_user', absint( $request['usage_limit_per_user'] ) );
}
if ( isset( $request['limit_usage_to_x_items'] ) ) {
update_post_meta( $post->ID, 'limit_usage_to_x_items', absint( $request['limit_usage_to_x_items'] ) );
}
if ( isset( $request['usage_count'] ) ) {
update_post_meta( $post->ID, 'usage_count', absint( $request['usage_count'] ) );
}
if ( isset( $request['expiry_date'] ) ) {
update_post_meta( $post->ID, 'expiry_date', $this->get_coupon_expiry_date( wc_clean( $request['expiry_date'] ) ) );
}
if ( isset( $request['enable_free_shipping'] ) ) {
update_post_meta( $post->ID, 'free_shipping', ( true === $request['enable_free_shipping'] ) ? 'yes' : 'no' );
}
if ( isset( $request['product_category_ids'] ) ) {
update_post_meta( $post->ID, 'product_categories', array_filter( array_map( 'intval', $request['product_category_ids'] ) ) );
}
if ( isset( $request['exclude_product_category_ids'] ) ) {
update_post_meta( $post->ID, 'exclude_product_categories', array_filter( array_map( 'intval', $request['exclude_product_category_ids'] ) ) );
}
if ( isset( $request['exclude_sale_items'] ) ) {
update_post_meta( $post->ID, 'exclude_sale_items', ( true === $request['exclude_sale_items'] ) ? 'yes' : 'no' );
}
if ( isset( $request['minimum_amount'] ) ) {
update_post_meta( $post->ID, 'minimum_amount', wc_format_decimal( $request['minimum_amount'] ) );
}
if ( isset( $request['maximum_amount'] ) ) {
update_post_meta( $post->ID, 'maximum_amount', wc_format_decimal( $request['maximum_amount'] ) );
}
if ( isset( $request['customer_emails'] ) ) {
update_post_meta( $post->ID, 'customer_email', array_filter( array_map( 'sanitize_email', $request['customer_emails'] ) ) );
}
}
/**
* Get the Post's schema, conforming to JSON Schema.
*
* @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' ),
'required' => true,
),
'type' => array(
'description' => __( 'Determines the type of discount that will be applied.', 'woocommerce' ),
'type' => 'string',
'enum' => array_keys( wc_get_coupon_types() ),
'context' => array( 'view', 'edit' ),
),
'created_at' => array(
'description' => __( "The date the coupon was created, in the site's timezone.", 'woocommerce' ),
'type' => 'date-time',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'updated_at' => array(
'description' => __( "The date the coupon was last modified, in the site's timezone.", 'woocommerce' ),
'type' => 'date-time',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'amount' => array(
'description' => __( 'The amount of discount.', 'woocommerce' ),
'type' => 'float',
'context' => array( 'view', 'edit' ),
),
'individual_use' => array(
'description' => __( 'Whether coupon can only be used individually.', 'woocommerce' ),
'type' => 'boolean',
'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(
'description' => __( 'How many times the coupon can be user per customer.', 'woocommerce' ),
'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' ),
),
'usage_count' => array(
'description' => __( 'Number of times the coupon has been used already.', 'woocommerce' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'expiry_date' => array(
'description' => __( 'UTC DateTime when the coupon expires.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'enable_free_shipping' => array(
'description' => __( 'Define if can be applied for free shipping.', 'woocommerce' ),
'type' => 'boolean',
'context' => array( 'view', 'edit' ),
),
'product_category_ids' => array(
'description' => __( "List of category ID's the coupon applies to.", 'woocommerce' ),
'type' => 'array',
'context' => array( 'view', 'edit' ),
),
'exclude_product_category_ids' => array(
'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',
'context' => array( 'view', 'edit' ),
),
'minimum_amount' => array(
'description' => __( 'Minimum order amount that needs to be in the cart before coupon applies.', 'woocommerce' ),
'type' => 'float',
'context' => array( 'view', 'edit' ),
),
'maximum_amount' => array(
'description' => __( 'Maximum order amount allowed when using the coupon.', 'woocommerce' ),
'type' => 'float',
'context' => array( 'view', 'edit' ),
),
'customer_emails' => array(
'description' => __( 'List of email addresses that can use this coupon.', 'woocommerce' ),
'type' => 'array',
'context' => array( 'view', 'edit' ),
),
'description' => array(
'description' => __( 'Coupon description.', 'woocommerce' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
),
);
return $this->add_additional_fields_schema( $schema );;
}
} }