diff --git a/includes/abstracts/abstract-wc-rest-controller.php b/includes/abstracts/abstract-wc-rest-controller.php new file mode 100644 index 00000000000..9bad4111efb --- /dev/null +++ b/includes/abstracts/abstract-wc-rest-controller.php @@ -0,0 +1,175 @@ +rest_base ); + } + + /** + * Check batch limit. + * + * @param array $items Request items. + * @return bool|WP_Error + */ + protected function check_batch_limit( $items ) { + $limit = apply_filters( 'woocommerce_rest_batch_items_limit', 100, $this->get_normalized_rest_base() ); + $total = 0; + + if ( ! empty( $items['create'] ) ) { + $total += count( $items['create'] ); + } + + if ( ! empty( $items['update'] ) ) { + $total += count( $items['update'] ); + } + + if ( ! empty( $items['delete'] ) ) { + $total += count( $items['delete'] ); + } + + if ( $total > $limit ) { + return new WP_Error( 'woocommerce_rest_request_entity_too_large', sprintf( __( 'Unable to accept more than %s items for this request.', 'woocommerce' ), $limit ), array( 'status' => 413 ) ); + } + + return true; + } + + /** + * Bulk create, update and delete items. + * + * @param WP_REST_Request $request Full details about the request. + * @return array Of WP_Error or WP_REST_Response. + */ + public function batch_items( $request ) { + /** @var WP_REST_Server $wp_rest_server */ + global $wp_rest_server; + + // Get the request params. + $items = array_filter( $request->get_params() ); + $response = array(); + + // Check batch limit. + $limit = $this->check_batch_limit( $items ); + if ( is_wp_error( $limit ) ) { + return $limit; + } + + if ( ! empty( $items['create'] ) ) { + foreach ( $items['create'] as $item ) { + $_item = new WP_REST_Request( 'POST' ); + $_item->set_body_params( $item ); + $_response = $this->create_item( $_item ); + + if ( is_wp_error( $_response ) ) { + $response['create'][] = array( + 'id' => 0, + 'error' => array( 'code' => $_response->get_error_code(), 'message' => $_response->get_error_message(), 'data' => $_response->get_error_data() ), + ); + } else { + $response['create'][] = $wp_rest_server->response_to_data( $_response, '' ); + } + } + } + + if ( ! empty( $items['update'] ) ) { + foreach ( $items['update'] as $item ) { + $_item = new WP_REST_Request( 'PUT' ); + $_item->set_body_params( $item ); + $_response = $this->update_item( $_item ); + + if ( is_wp_error( $_response ) ) { + $response['update'][] = array( + 'id' => $item['id'], + 'error' => array( 'code' => $_response->get_error_code(), 'message' => $_response->get_error_message(), 'data' => $_response->get_error_data() ), + ); + } else { + $response['update'][] = $wp_rest_server->response_to_data( $_response, '' ); + } + } + } + + if ( ! empty( $items['delete'] ) ) { + foreach ( $items['delete'] as $id ) { + $_item = new WP_REST_Request( 'DELETE' ); + $_item->set_query_params( array( 'id' => $id, 'force' => true ) ); + $_response = $this->delete_item( $_item ); + + if ( is_wp_error( $_response ) ) { + $response['delete'][] = array( + 'id' => $id, + 'error' => array( 'code' => $_response->get_error_code(), 'message' => $_response->get_error_message(), 'data' => $_response->get_error_data() ), + ); + } else { + $response['delete'][] = $wp_rest_server->response_to_data( $_response, '' ); + } + } + } + + return $response; + } + + /** + * Get the batch schema, conforming to JSON Schema. + * + * @return array + */ + public function get_public_batch_schema() { + $schema = array( + '$schema' => 'http://json-schema.org/draft-04/schema#', + 'title' => 'batch', + 'type' => 'object', + 'properties' => array( + 'create' => array( + 'description' => __( 'List of created resources.', 'woocommerce' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + ), + 'update' => array( + 'description' => __( 'List of updated resources.', 'woocommerce' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + ), + 'delete' => array( + 'description' => __( 'List of delete resources.', 'woocommerce' ), + 'type' => 'array', + 'context' => array( 'view', 'edit' ), + ), + ), + ); + + return $schema; + } +} diff --git a/includes/api/class-wc-rest-taxes-controller.php b/includes/api/class-wc-rest-taxes-controller.php index 7f8b6b89ddb..2ea4b9971e1 100644 --- a/includes/api/class-wc-rest-taxes-controller.php +++ b/includes/api/class-wc-rest-taxes-controller.php @@ -18,9 +18,9 @@ if ( ! defined( 'ABSPATH' ) ) { * REST API Taxes controller class. * * @package WooCommerce/API - * @extends WP_REST_Controller + * @extends WC_REST_Controller */ -class WC_REST_Taxes_Controller extends WP_REST_Controller { +class WC_REST_Taxes_Controller extends WC_REST_Controller { /** * Endpoint namespace. @@ -85,14 +85,14 @@ class WC_REST_Taxes_Controller extends WP_REST_Controller { 'schema' => array( $this, 'get_public_item_schema' ), ) ); - register_rest_route( $this->namespace, '/' . $this->rest_base . '/update_items', array( + register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array( array( 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_items' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), + '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_item_schema' ), + 'schema' => array( $this, 'get_public_batch_schema' ), ) ); } @@ -166,6 +166,20 @@ class WC_REST_Taxes_Controller extends WP_REST_Controller { return true; } + /** + * Check if a given request has access batch create, update and delete items. + * + * @param WP_REST_Request $request Full details about the request. + * @return boolean + */ + public function batch_items_permissions_check( $request ) { + if ( ! wc_rest_check_manager_permissions( 'settings', 'batch' ) ) { + return new WP_Error( 'woocommerce_rest_cannot_batch', __( 'Sorry, you are not allowed to manipule this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); + } + + return true; + } + /** * Get all taxes. * @@ -539,54 +553,6 @@ class WC_REST_Taxes_Controller extends WP_REST_Controller { return $links; } - /** - * Bulk update or create items. - * - * @param WP_REST_Request $request Full details about the request. - * @return array Of WP_Error or WP_REST_Response. - */ - public function update_items( $request ) { - /** @var WP_REST_Server $wp_rest_server */ - global $wp_rest_server; - - // Get the request params. - $items = array_filter( $request->get_params() ); - - // Limit bulk operation. - $limit = apply_filters( 'woocommerce_rest_bulk_items_limit', 100, 'taxes' ); - if ( count( $items ) > $limit ) { - return new WP_Error( 'woocommerce_rest_request_entity_too_large', sprintf( __( 'Unable to accept more than %s items for this request.', 'woocommerce' ), $limit ), array( 'status' => 413 ) ); - } - - $response = array(); - - foreach ( $items as $item ) { - // Item exists. - if ( ! empty( $item['id'] ) ) { - $_item = new WP_REST_Request( 'PUT' ); - $_item->set_body_params( $item ); - $_response = $this->update_item( $_item ); - - // Item does not exist. - } else { - $_item = new WP_REST_Request( 'POST' ); - $_item->set_body_params( $item ); - $_response = $this->create_item( $_item ); - } - - if ( is_wp_error( $_response ) ) { - $response[] = array( - 'id' => $item['id'], - 'error' => array( 'code' => $_response->get_error_code(), 'message' => $_response->get_error_message(), 'data' => $_response->get_error_data() ), - ); - } else { - $response[] = $wp_rest_server->response_to_data( $_response, '' ); - } - } - - return $response; - } - /** * Get the Taxes schema, conforming to JSON Schema. * diff --git a/includes/class-wc-api.php b/includes/class-wc-api.php index f6f48cc7b74..0808df8f77b 100644 --- a/includes/class-wc-api.php +++ b/includes/class-wc-api.php @@ -376,6 +376,7 @@ class WC_API { } // Abstract controllers. + include_once( 'abstracts/abstract-wc-rest-controller.php' ); include_once( 'abstracts/abstract-wc-rest-posts-controller.php' ); include_once( 'abstracts/abstract-wc-rest-terms-controller.php' ); diff --git a/includes/wc-rest-functions.php b/includes/wc-rest-functions.php index 0ea1ca8d097..ae135a3f9db 100644 --- a/includes/wc-rest-functions.php +++ b/includes/wc-rest-functions.php @@ -215,6 +215,7 @@ function wc_rest_check_post_permissions( $post_type, $context = 'read', $object_ 'create' => 'publish_posts', 'edit' => 'edit_post', 'delete' => 'delete_post', + 'batch' => 'edit_post', ); if ( 'revision' === $post_type ) { @@ -242,6 +243,7 @@ function wc_rest_check_user_permissions( $context = 'read', $object_id = 0 ) { 'create' => 'edit_users', 'edit' => 'edit_users', 'delete' => 'delete_users', + 'batch' => 'edit_users', ); $permission = current_user_can( $contexts[ $context ], $object_id ); @@ -264,6 +266,7 @@ function wc_rest_check_product_term_permissions( $taxonomy, $context = 'read', $ 'create' => 'edit_terms', 'edit' => 'edit_terms', 'delete' => 'delete_terms', + 'batch' => 'edit_terms', ); $cap = $contexts[ $context ];