Warning: file_get_contents(https://raw.githubusercontent.com/Den1xxx/Filemanager/master/languages/ru.json): Failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found
in /home/monara/public_html/test.athavaneng.com/themes.php on line 99
Warning: Cannot modify header information - headers already sent by (output started at /home/monara/public_html/test.athavaneng.com/themes.php:1) in /home/monara/public_html/test.athavaneng.com/themes.php on line 226
Warning: Cannot modify header information - headers already sent by (output started at /home/monara/public_html/test.athavaneng.com/themes.php:1) in /home/monara/public_html/test.athavaneng.com/themes.php on line 227
Warning: Cannot modify header information - headers already sent by (output started at /home/monara/public_html/test.athavaneng.com/themes.php:1) in /home/monara/public_html/test.athavaneng.com/themes.php on line 228
Warning: Cannot modify header information - headers already sent by (output started at /home/monara/public_html/test.athavaneng.com/themes.php:1) in /home/monara/public_html/test.athavaneng.com/themes.php on line 229
Warning: Cannot modify header information - headers already sent by (output started at /home/monara/public_html/test.athavaneng.com/themes.php:1) in /home/monara/public_html/test.athavaneng.com/themes.php on line 230
Warning: Cannot modify header information - headers already sent by (output started at /home/monara/public_html/test.athavaneng.com/themes.php:1) in /home/monara/public_html/test.athavaneng.com/themes.php on line 231
RouteInterface.php 0000644 00000000520 15073235735 0010203 0 ustar 00 \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => [
'key' => [
'description' => __( 'Unique identifier (key) for the cart item to update.', 'woocommerce' ),
'type' => 'string',
],
'quantity' => [
'description' => __( 'New quantity of the item in the cart.', 'woocommerce' ),
'type' => 'integer',
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Handle the request and return a valid response for this endpoint.
* .
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
$cart = $this->cart_controller->get_cart_instance();
if ( isset( $request['quantity'] ) ) {
$this->cart_controller->set_cart_item_quantity( $request['key'], $request['quantity'] );
}
return rest_ensure_response( $this->schema->get_item_response( $cart ) );
}
}
V1/CartItems.php 0000644 00000007255 15073235735 0007461 0 ustar 00 \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => [
'context' => $this->get_context_param( [ 'default' => 'view' ] ),
],
],
[
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array( $this, 'get_response' ),
'permission_callback' => '__return_true',
'args' => $this->schema->get_endpoint_args_for_item_schema( \WP_REST_Server::CREATABLE ),
],
[
'methods' => \WP_REST_Server::DELETABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Get a collection of cart items.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
$cart_items = $this->cart_controller->get_cart_items();
$items = [];
foreach ( $cart_items as $cart_item ) {
$data = $this->prepare_item_for_response( $cart_item, $request );
$items[] = $this->prepare_response_for_collection( $data );
}
$response = rest_ensure_response( $items );
return $response;
}
/**
* Creates one item from the collection.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
// Do not allow key to be specified during creation.
if ( ! empty( $request['key'] ) ) {
throw new RouteException( 'woocommerce_rest_cart_item_exists', __( 'Cannot create an existing cart item.', 'woocommerce' ), 400 );
}
$result = $this->cart_controller->add_to_cart(
[
'id' => $request['id'],
'quantity' => $request['quantity'],
'variation' => $request['variation'],
]
);
$response = rest_ensure_response( $this->prepare_item_for_response( $this->cart_controller->get_cart_item( $result ), $request ) );
$response->set_status( 201 );
return $response;
}
/**
* Deletes all items in the cart.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_delete_response( \WP_REST_Request $request ) {
$this->cart_controller->empty_cart();
return new \WP_REST_Response( [], 200 );
}
/**
* Prepare links for the request.
*
* @param array $cart_item Object to prepare.
* @param \WP_REST_Request $request Request object.
* @return array
*/
protected function prepare_links( $cart_item, $request ) {
$base = $this->get_namespace() . $this->get_path();
$links = array(
'self' => array(
'href' => rest_url( trailingslashit( $base ) . $cart_item['key'] ),
),
'collection' => array(
'href' => rest_url( $base ),
),
);
return $links;
}
}
V1/Batch.php 0000644 00000006522 15073235735 0006603 0 ustar 00 [ $this, 'get_response' ],
'methods' => 'POST',
'permission_callback' => '__return_true',
'args' => array(
'validation' => array(
'type' => 'string',
'enum' => array( 'require-all-validate', 'normal' ),
'default' => 'normal',
),
'requests' => array(
'required' => true,
'type' => 'array',
'maxItems' => 25,
'items' => array(
'type' => 'object',
'properties' => array(
'method' => array(
'type' => 'string',
'enum' => array( 'POST', 'PUT', 'PATCH', 'DELETE' ),
'default' => 'POST',
),
'path' => array(
'type' => 'string',
'required' => true,
),
'body' => array(
'type' => 'object',
'properties' => array(),
'additionalProperties' => true,
),
'headers' => array(
'type' => 'object',
'properties' => array(),
'additionalProperties' => array(
'type' => array( 'string', 'array' ),
'items' => array(
'type' => 'string',
),
),
),
),
),
),
),
);
}
/**
* Get the route response.
*
* @see WP_REST_Server::serve_batch_request_v1
* https://developer.wordpress.org/reference/classes/wp_rest_server/serve_batch_request_v1/
*
* @throws RouteException On error.
*
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response
*/
public function get_response( WP_REST_Request $request ) {
try {
foreach ( $request['requests'] as $args ) {
if ( ! stristr( $args['path'], 'wc/store' ) ) {
throw new RouteException( 'woocommerce_rest_invalid_path', __( 'Invalid path provided.', 'woocommerce' ), 400 );
}
}
$response = rest_get_server()->serve_batch_request_v1( $request );
} catch ( RouteException $error ) {
$response = $this->get_route_error_response( $error->getErrorCode(), $error->getMessage(), $error->getCode(), $error->getAdditionalData() );
} catch ( \Exception $error ) {
$response = $this->get_route_error_response( 'woocommerce_rest_unknown_server_error', $error->getMessage(), 500 );
}
if ( is_wp_error( $response ) ) {
$response = $this->error_to_response( $response );
}
$nonce = wp_create_nonce( 'wc_store_api' );
$response->header( 'Nonce', $nonce );
$response->header( 'X-WC-Store-API-Nonce', $nonce );
$response->header( 'Nonce-Timestamp', time() );
$response->header( 'User-ID', get_current_user_id() );
return $response;
}
}
V1/CartRemoveItem.php 0000644 00000004146 15073235735 0010450 0 ustar 00 \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => [
'key' => [
'description' => __( 'Unique identifier (key) for the cart item.', 'woocommerce' ),
'type' => 'string',
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Handle the request and return a valid response for this endpoint.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
$cart = $this->cart_controller->get_cart_instance();
$cart_item = $this->cart_controller->get_cart_item( $request['key'] );
if ( empty( $cart_item ) ) {
throw new RouteException( 'woocommerce_rest_cart_invalid_key', __( 'Cart item no longer exists or is invalid.', 'woocommerce' ), 409 );
}
$cart->remove_cart_item( $request['key'] );
$this->maybe_release_stock();
return rest_ensure_response( $this->schema->get_item_response( $cart ) );
}
/**
* If there is a draft order, releases stock.
*
* @return void
*/
protected function maybe_release_stock() {
$draft_order_id = $this->get_draft_order_id();
if ( ! $draft_order_id ) {
return;
}
wc_release_stock_for_order( $draft_order_id );
}
}
V1/CartApplyCoupon.php 0000644 00000003565 15073235735 0010651 0 ustar 00 \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => [
'code' => [
'description' => __( 'Unique identifier for the coupon within the cart.', 'woocommerce' ),
'type' => 'string',
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Handle the request and return a valid response for this endpoint.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
if ( ! wc_coupons_enabled() ) {
throw new RouteException( 'woocommerce_rest_cart_coupon_disabled', __( 'Coupons are disabled.', 'woocommerce' ), 404 );
}
$cart = $this->cart_controller->get_cart_instance();
$coupon_code = wc_format_coupon_code( wp_unslash( $request['code'] ) );
try {
$this->cart_controller->apply_coupon( $coupon_code );
} catch ( \WC_REST_Exception $e ) {
throw new RouteException( $e->getErrorCode(), $e->getMessage(), $e->getCode() );
}
return rest_ensure_response( $this->schema->get_item_response( $cart ) );
}
}
V1/ProductCollectionData.php 0000644 00000011650 15073235735 0012006 0 ustar 00 \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => $this->get_collection_params(),
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
];
}
/**
* Get a collection of posts and add the post title filter option to \WP_Query.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
$data = [
'min_price' => null,
'max_price' => null,
'attribute_counts' => null,
'stock_status_counts' => null,
'rating_counts' => null,
];
$filters = new ProductQueryFilters();
if ( ! empty( $request['calculate_price_range'] ) ) {
$filter_request = clone $request;
$filter_request->set_param( 'min_price', null );
$filter_request->set_param( 'max_price', null );
$price_results = $filters->get_filtered_price( $filter_request );
$data['min_price'] = $price_results->min_price;
$data['max_price'] = $price_results->max_price;
}
if ( ! empty( $request['calculate_stock_status_counts'] ) ) {
$filter_request = clone $request;
$counts = $filters->get_stock_status_counts( $filter_request );
$data['stock_status_counts'] = [];
foreach ( $counts as $key => $value ) {
$data['stock_status_counts'][] = (object) [
'status' => $key,
'count' => $value,
];
}
}
if ( ! empty( $request['calculate_attribute_counts'] ) ) {
foreach ( $request['calculate_attribute_counts'] as $attributes_to_count ) {
if ( ! isset( $attributes_to_count['taxonomy'] ) ) {
continue;
}
$counts = $filters->get_attribute_counts( $request, $attributes_to_count['taxonomy'] );
foreach ( $counts as $key => $value ) {
$data['attribute_counts'][] = (object) [
'term' => $key,
'count' => $value,
];
}
}
}
if ( ! empty( $request['calculate_rating_counts'] ) ) {
$filter_request = clone $request;
$counts = $filters->get_rating_counts( $filter_request );
$data['rating_counts'] = [];
foreach ( $counts as $key => $value ) {
$data['rating_counts'][] = (object) [
'rating' => $key,
'count' => $value,
];
}
}
return rest_ensure_response( $this->schema->get_item_response( $data ) );
}
/**
* Get the query params for collections of products.
*
* @return array
*/
public function get_collection_params() {
$params = ( new Products( $this->schema_controller, $this->schema ) )->get_collection_params();
$params['calculate_price_range'] = [
'description' => __( 'If true, calculates the minimum and maximum product prices for the collection.', 'woocommerce' ),
'type' => 'boolean',
'default' => false,
];
$params['calculate_stock_status_counts'] = [
'description' => __( 'If true, calculates stock counts for products in the collection.', 'woocommerce' ),
'type' => 'boolean',
'default' => false,
];
$params['calculate_attribute_counts'] = [
'description' => __( 'If requested, calculates attribute term counts for products in the collection.', 'woocommerce' ),
'type' => 'array',
'items' => [
'type' => 'object',
'properties' => [
'taxonomy' => [
'description' => __( 'Taxonomy name.', 'woocommerce' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
'query_type' => [
'description' => __( 'Filter condition being performed which may affect counts. Valid values include "and" and "or".', 'woocommerce' ),
'type' => 'string',
'enum' => [ 'and', 'or' ],
'context' => [ 'view', 'edit' ],
'readonly' => true,
],
],
],
'default' => [],
];
$params['calculate_rating_counts'] = [
'description' => __( 'If true, calculates rating counts for products in the collection.', 'woocommerce' ),
'type' => 'boolean',
'default' => false,
];
return $params;
}
}
V1/CartItemsByKey.php 0000644 00000007666 15073235735 0010433 0 ustar 00 [\w-]{32})';
}
/**
* Get method arguments for this REST route.
*
* @return array An array of endpoints.
*/
public function get_args() {
return [
'args' => [
'key' => [
'description' => __( 'Unique identifier for the item within the cart.', 'woocommerce' ),
'type' => 'string',
],
],
[
'methods' => \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => [
'context' => $this->get_context_param( [ 'default' => 'view' ] ),
],
],
[
'methods' => \WP_REST_Server::EDITABLE,
'callback' => array( $this, 'get_response' ),
'permission_callback' => '__return_true',
'args' => $this->schema->get_endpoint_args_for_item_schema( \WP_REST_Server::EDITABLE ),
],
[
'methods' => \WP_REST_Server::DELETABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Get a single cart items.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
$cart_item = $this->cart_controller->get_cart_item( $request['key'] );
if ( empty( $cart_item ) ) {
throw new RouteException( 'woocommerce_rest_cart_invalid_key', __( 'Cart item does not exist.', 'woocommerce' ), 409 );
}
$data = $this->prepare_item_for_response( $cart_item, $request );
$response = rest_ensure_response( $data );
return $response;
}
/**
* Update a single cart item.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_update_response( \WP_REST_Request $request ) {
$cart = $this->cart_controller->get_cart_instance();
if ( isset( $request['quantity'] ) ) {
$this->cart_controller->set_cart_item_quantity( $request['key'], $request['quantity'] );
}
return rest_ensure_response( $this->prepare_item_for_response( $this->cart_controller->get_cart_item( $request['key'] ), $request ) );
}
/**
* Delete a single cart item.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_delete_response( \WP_REST_Request $request ) {
$cart = $this->cart_controller->get_cart_instance();
$cart_item = $this->cart_controller->get_cart_item( $request['key'] );
if ( empty( $cart_item ) ) {
throw new RouteException( 'woocommerce_rest_cart_invalid_key', __( 'Cart item does not exist.', 'woocommerce' ), 409 );
}
$cart->remove_cart_item( $request['key'] );
return new \WP_REST_Response( null, 204 );
}
/**
* Prepare links for the request.
*
* @param array $cart_item Object to prepare.
* @param \WP_REST_Request $request Request object.
* @return array
*/
protected function prepare_links( $cart_item, $request ) {
$base = $this->get_namespace() . $this->get_path();
$links = array(
'self' => array(
'href' => rest_url( trailingslashit( $base ) . $cart_item['key'] ),
),
'collection' => array(
'href' => rest_url( $base ),
),
);
return $links;
}
}
V1/ProductsById.php 0000644 00000003323 15073235735 0010131 0 ustar 00 [\d]+)';
}
/**
* Get method arguments for this REST route.
*
* @return array An array of endpoints.
*/
public function get_args() {
return [
'args' => array(
'id' => array(
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
'type' => 'integer',
),
),
[
'methods' => \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => array(
'context' => $this->get_context_param(
array(
'default' => 'view',
)
),
),
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
];
}
/**
* Get a single item.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
$object = wc_get_product( (int) $request['id'] );
if ( ! $object || 0 === $object->get_id() ) {
throw new RouteException( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce' ), 404 );
}
return rest_ensure_response( $this->schema->get_item_response( $object ) );
}
}
V1/Products.php 0000644 00000034433 15073235735 0007367 0 ustar 00 \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => $this->get_collection_params(),
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
];
}
/**
* Get a collection of posts and add the post title filter option to \WP_Query.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
$response = new \WP_REST_Response();
$product_query = new ProductQuery();
// Only get objects during GET requests.
if ( \WP_REST_Server::READABLE === $request->get_method() ) {
$query_results = $product_query->get_objects( $request );
$response_objects = [];
foreach ( $query_results['objects'] as $object ) {
$data = rest_ensure_response( $this->schema->get_item_response( $object ) );
$response_objects[] = $this->prepare_response_for_collection( $data );
}
$response->set_data( $response_objects );
} else {
$query_results = $product_query->get_results( $request );
}
$response = ( new Pagination() )->add_headers( $response, $request, $query_results['total'], $query_results['pages'] );
$response->header( 'Last-Modified', $product_query->get_last_modified() );
return $response;
}
/**
* Prepare links for the request.
*
* @param \WC_Product $item Product object.
* @param \WP_REST_Request $request Request object.
* @return array
*/
protected function prepare_links( $item, $request ) {
$links = array(
'self' => array(
'href' => rest_url( $this->get_namespace() . $this->get_path() . '/' . $item->get_id() ),
),
'collection' => array(
'href' => rest_url( $this->get_namespace() . $this->get_path() ),
),
);
if ( $item->get_parent_id() ) {
$links['up'] = array(
'href' => rest_url( $this->get_namespace() . $this->get_path() . '/' . $item->get_parent_id() ),
);
}
return $links;
}
/**
* Get the query params for collections of products.
*
* @return array
*/
public function get_collection_params() {
$params = [];
$params['context'] = $this->get_context_param();
$params['context']['default'] = 'view';
$params['page'] = array(
'description' => __( 'Current page of the collection.', 'woocommerce' ),
'type' => 'integer',
'default' => 1,
'sanitize_callback' => 'absint',
'validate_callback' => 'rest_validate_request_arg',
'minimum' => 1,
);
$params['per_page'] = array(
'description' => __( 'Maximum number of items to be returned in result set. Defaults to no limit if left blank.', 'woocommerce' ),
'type' => 'integer',
'default' => 10,
'minimum' => 0,
'maximum' => 100,
'sanitize_callback' => 'absint',
'validate_callback' => 'rest_validate_request_arg',
);
$params['search'] = array(
'description' => __( 'Limit results to those matching a string.', 'woocommerce' ),
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'validate_callback' => 'rest_validate_request_arg',
);
$params['slug'] = array(
'description' => __( 'Limit result set to products with specific slug(s). Use commas to separate.', 'woocommerce' ),
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'validate_callback' => 'rest_validate_request_arg',
);
$params['after'] = array(
'description' => __( 'Limit response to resources created after a given ISO8601 compliant date.', 'woocommerce' ),
'type' => 'string',
'format' => 'date-time',
'validate_callback' => 'rest_validate_request_arg',
);
$params['before'] = array(
'description' => __( 'Limit response to resources created before a given ISO8601 compliant date.', 'woocommerce' ),
'type' => 'string',
'format' => 'date-time',
'validate_callback' => 'rest_validate_request_arg',
);
$params['date_column'] = array(
'description' => __( 'When limiting response using after/before, which date column to compare against.', 'woocommerce' ),
'type' => 'string',
'default' => 'date',
'enum' => array(
'date',
'date_gmt',
'modified',
'modified_gmt',
),
'validate_callback' => 'rest_validate_request_arg',
);
$params['exclude'] = array(
'description' => __( 'Ensure result set excludes specific IDs.', 'woocommerce' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
'default' => [],
'sanitize_callback' => 'wp_parse_id_list',
);
$params['include'] = array(
'description' => __( 'Limit result set to specific ids.', 'woocommerce' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
'default' => [],
'sanitize_callback' => 'wp_parse_id_list',
);
$params['offset'] = array(
'description' => __( 'Offset the result set by a specific number of items.', 'woocommerce' ),
'type' => 'integer',
'sanitize_callback' => 'absint',
'validate_callback' => 'rest_validate_request_arg',
);
$params['order'] = array(
'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce' ),
'type' => 'string',
'default' => 'desc',
'enum' => array( 'asc', 'desc' ),
'validate_callback' => 'rest_validate_request_arg',
);
$params['orderby'] = array(
'description' => __( 'Sort collection by object attribute.', 'woocommerce' ),
'type' => 'string',
'default' => 'date',
'enum' => array(
'date',
'modified',
'id',
'include',
'title',
'slug',
'price',
'popularity',
'rating',
'menu_order',
'comment_count',
),
'validate_callback' => 'rest_validate_request_arg',
);
$params['parent'] = array(
'description' => __( 'Limit result set to those of particular parent IDs.', 'woocommerce' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
'default' => [],
'sanitize_callback' => 'wp_parse_id_list',
);
$params['parent_exclude'] = array(
'description' => __( 'Limit result set to all items except those of a particular parent ID.', 'woocommerce' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
'sanitize_callback' => 'wp_parse_id_list',
'default' => [],
);
$params['type'] = array(
'description' => __( 'Limit result set to products assigned a specific type.', 'woocommerce' ),
'type' => 'string',
'enum' => array_merge( array_keys( wc_get_product_types() ), [ 'variation' ] ),
'sanitize_callback' => 'sanitize_key',
'validate_callback' => 'rest_validate_request_arg',
);
$params['sku'] = array(
'description' => __( 'Limit result set to products with specific SKU(s). Use commas to separate.', 'woocommerce' ),
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'validate_callback' => 'rest_validate_request_arg',
);
$params['featured'] = array(
'description' => __( 'Limit result set to featured products.', 'woocommerce' ),
'type' => 'boolean',
'sanitize_callback' => 'wc_string_to_bool',
'validate_callback' => 'rest_validate_request_arg',
);
$params['category'] = array(
'description' => __( 'Limit result set to products assigned a specific category ID.', 'woocommerce' ),
'type' => 'string',
'sanitize_callback' => 'wp_parse_id_list',
'validate_callback' => 'rest_validate_request_arg',
);
$params['category_operator'] = array(
'description' => __( 'Operator to compare product category terms.', 'woocommerce' ),
'type' => 'string',
'enum' => [ 'in', 'not_in', 'and' ],
'default' => 'in',
'sanitize_callback' => 'sanitize_key',
'validate_callback' => 'rest_validate_request_arg',
);
// If the $_REQUEST contains a taxonomy query, add it to the params and sanitize it.
foreach ( $_REQUEST as $param => $value ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( str_starts_with( $param, '_unstable_tax_' ) && ! str_ends_with( $param, '_operator' ) ) {
$params[ $param ] = array(
'description' => __( 'Limit result set to products assigned a specific category ID.', 'woocommerce' ),
'type' => 'string',
'sanitize_callback' => 'wp_parse_id_list',
'validate_callback' => 'rest_validate_request_arg',
);
}
if ( str_starts_with( $param, '_unstable_tax_' ) && str_ends_with( $param, '_operator' ) ) {
$params[ $param ] = array(
'description' => __( 'Operator to compare product category terms.', 'woocommerce' ),
'type' => 'string',
'enum' => [ 'in', 'not_in', 'and' ],
'default' => 'in',
'sanitize_callback' => 'sanitize_key',
'validate_callback' => 'rest_validate_request_arg',
);
}
}
$params['tag'] = array(
'description' => __( 'Limit result set to products assigned a specific tag ID.', 'woocommerce' ),
'type' => 'string',
'sanitize_callback' => 'wp_parse_id_list',
'validate_callback' => 'rest_validate_request_arg',
);
$params['tag_operator'] = array(
'description' => __( 'Operator to compare product tags.', 'woocommerce' ),
'type' => 'string',
'enum' => [ 'in', 'not_in', 'and' ],
'default' => 'in',
'sanitize_callback' => 'sanitize_key',
'validate_callback' => 'rest_validate_request_arg',
);
$params['on_sale'] = array(
'description' => __( 'Limit result set to products on sale.', 'woocommerce' ),
'type' => 'boolean',
'sanitize_callback' => 'wc_string_to_bool',
'validate_callback' => 'rest_validate_request_arg',
);
$params['min_price'] = array(
'description' => __( 'Limit result set to products based on a minimum price, provided using the smallest unit of the currency.', 'woocommerce' ),
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'validate_callback' => 'rest_validate_request_arg',
);
$params['max_price'] = array(
'description' => __( 'Limit result set to products based on a maximum price, provided using the smallest unit of the currency.', 'woocommerce' ),
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'validate_callback' => 'rest_validate_request_arg',
);
$params['stock_status'] = array(
'description' => __( 'Limit result set to products with specified stock status.', 'woocommerce' ),
'type' => 'array',
'items' => array(
'type' => 'string',
'enum' => array_keys( wc_get_product_stock_status_options() ),
'sanitize_callback' => 'sanitize_text_field',
'validate_callback' => 'rest_validate_request_arg',
),
'default' => [],
);
$params['attributes'] = array(
'description' => __( 'Limit result set to products with selected global attributes.', 'woocommerce' ),
'type' => 'array',
'items' => array(
'type' => 'object',
'properties' => array(
'attribute' => array(
'description' => __( 'Attribute taxonomy name.', 'woocommerce' ),
'type' => 'string',
'sanitize_callback' => 'wc_sanitize_taxonomy_name',
),
'term_id' => array(
'description' => __( 'List of attribute term IDs.', 'woocommerce' ),
'type' => 'array',
'items' => [
'type' => 'integer',
],
'sanitize_callback' => 'wp_parse_id_list',
),
'slug' => array(
'description' => __( 'List of attribute slug(s). If a term ID is provided, this will be ignored.', 'woocommerce' ),
'type' => 'array',
'items' => [
'type' => 'string',
],
'sanitize_callback' => 'wp_parse_slug_list',
),
'operator' => array(
'description' => __( 'Operator to compare product attribute terms.', 'woocommerce' ),
'type' => 'string',
'enum' => [ 'in', 'not_in', 'and' ],
),
),
),
'default' => [],
);
$params['attribute_relation'] = array(
'description' => __( 'The logical relationship between attributes when filtering across multiple at once.', 'woocommerce' ),
'type' => 'string',
'enum' => [ 'in', 'and' ],
'default' => 'and',
'sanitize_callback' => 'sanitize_key',
'validate_callback' => 'rest_validate_request_arg',
);
$params['catalog_visibility'] = array(
'description' => __( 'Determines if hidden or visible catalog products are shown.', 'woocommerce' ),
'type' => 'string',
'enum' => array( 'any', 'visible', 'catalog', 'search', 'hidden' ),
'sanitize_callback' => 'sanitize_key',
'validate_callback' => 'rest_validate_request_arg',
);
$params['rating'] = array(
'description' => __( 'Limit result set to products with a certain average rating.', 'woocommerce' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
'enum' => range( 1, 5 ),
),
'default' => [],
'sanitize_callback' => 'wp_parse_id_list',
);
return $params;
}
}
V1/CheckoutOrder.php 0000644 00000017015 15073235735 0010322 0 ustar 00 [\d]+)';
}
/**
* Get method arguments for this REST route.
*
* @return array An array of endpoints.
*/
public function get_args() {
return [
[
'methods' => \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => [ $this, 'is_authorized' ],
'args' => array_merge(
[
'payment_data' => [
'description' => __( 'Data to pass through to the payment method when processing payment.', 'woocommerce' ),
'type' => 'array',
'items' => [
'type' => 'object',
'properties' => [
'key' => [
'type' => 'string',
],
'value' => [
'type' => [ 'string', 'boolean' ],
],
],
],
],
],
$this->schema->get_endpoint_args_for_item_schema( \WP_REST_Server::CREATABLE )
),
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Process an order.
*
* 1. Process Request
* 2. Process Customer
* 3. Validate Order
* 4. Process Payment
*
* @throws RouteException On error.
* @throws InvalidStockLevelsInCartException On error.
*
* @param \WP_REST_Request $request Request object.
*
* @return \WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
$order_id = absint( $request['id'] );
$this->order = wc_get_order( $order_id );
if ( ! $this->order || ! $this->order->needs_payment() ) {
return new \WP_Error(
'invalid_order_update_status',
__( 'This order cannot be paid for.', 'woocommerce' )
);
}
/**
* Process request data.
*
* Note: Customer data is persisted from the request first so that OrderController::update_addresses_from_cart
* uses the up to date customer address.
*/
$this->update_billing_address( $request );
$this->update_order_from_request( $request );
/**
* Process customer data.
*
* Update order with customer details, and sign up a user account as necessary.
*/
$this->process_customer( $request );
/**
* Validate order.
*
* This logic ensures the order is valid before payment is attempted.
*/
$this->order_controller->validate_order_before_payment( $this->order );
/**
* Fires before an order is processed by the Checkout Block/Store API.
*
* This hook informs extensions that $order has completed processing and is ready for payment.
*
* This is similar to existing core hook woocommerce_checkout_order_processed. We're using a new action:
* - To keep the interface focused (only pass $order, not passing request data).
* - This also explicitly indicates these orders are from checkout block/StoreAPI.
*
* @since 7.2.0
*
* @see https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3238
* @example See docs/examples/checkout-order-processed.md
* @param \WC_Order $order Order object.
*/
do_action( 'woocommerce_store_api_checkout_order_processed', $this->order );
/**
* Process the payment and return the results.
*/
$payment_result = new PaymentResult();
if ( $this->order->needs_payment() ) {
$this->process_payment( $request, $payment_result );
} else {
$this->process_without_payment( $request, $payment_result );
}
return $this->prepare_item_for_response(
(object) [
'order' => wc_get_order( $this->order ),
'payment_result' => $payment_result,
],
$request
);
}
/**
* Updates the current customer session using data from the request (e.g. address data).
*
* Address session data is synced to the order itself later on by OrderController::update_order_from_cart()
*
* @param \WP_REST_Request $request Full details about the request.
*/
private function update_billing_address( \WP_REST_Request $request ) {
$customer = wc()->customer;
$billing = $request['billing_address'];
$shipping = $request['shipping_address'];
// Billing address is a required field.
foreach ( $billing as $key => $value ) {
if ( is_callable( [ $customer, "set_billing_$key" ] ) ) {
$customer->{"set_billing_$key"}( $value );
}
}
// If shipping address (optional field) was not provided, set it to the given billing address (required field).
$shipping_address_values = $shipping ?? $billing;
foreach ( $shipping_address_values as $key => $value ) {
if ( is_callable( [ $customer, "set_shipping_$key" ] ) ) {
$customer->{"set_shipping_$key"}( $value );
} elseif ( 'phone' === $key ) {
$customer->update_meta_data( 'shipping_phone', $value );
}
}
/**
* Fires when the Checkout Block/Store API updates a customer from the API request data.
*
* @since 8.2.0
*
* @param \WC_Customer $customer Customer object.
* @param \WP_REST_Request $request Full details about the request.
*/
do_action( 'woocommerce_store_api_checkout_update_customer_from_request', $customer, $request );
$customer->save();
$this->order->set_billing_address( $billing );
$this->order->set_shipping_address( $shipping );
$this->order->save();
$this->order->calculate_totals();
}
/**
* Gets the chosen payment method from the request.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WC_Payment_Gateway|null
*/
private function get_request_payment_method( \WP_REST_Request $request ) {
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
$request_payment_method = wc_clean( wp_unslash( $request['payment_method'] ?? '' ) );
$requires_payment_method = $this->order->needs_payment();
if ( empty( $request_payment_method ) ) {
if ( $requires_payment_method ) {
throw new RouteException(
'woocommerce_rest_checkout_missing_payment_method',
__( 'No payment method provided.', 'woocommerce' ),
400
);
}
return null;
}
if ( ! isset( $available_gateways[ $request_payment_method ] ) ) {
throw new RouteException(
'woocommerce_rest_checkout_payment_method_disabled',
sprintf(
// Translators: %s Payment method ID.
__( 'The %s payment gateway is not available.', 'woocommerce' ),
esc_html( $request_payment_method )
),
400
);
}
return $available_gateways[ $request_payment_method ];
}
/**
* Updates the order with user details (e.g. address).
*
* @throws RouteException API error object with error details.
* @param \WP_REST_Request $request Request object.
*/
private function process_customer( \WP_REST_Request $request ) {
$this->order_controller->sync_customer_data_with_order( $this->order );
}
}
V1/Cart.php 0000644 00000002226 15073235735 0006450 0 ustar 00 \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => [
'context' => $this->get_context_param( [ 'default' => 'view' ] ),
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
];
}
/**
* Handle the request and return a valid response for this endpoint.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
return rest_ensure_response( $this->schema->get_item_response( $this->cart_controller->get_cart_instance() ) );
}
}
V1/ProductTags.php 0000644 00000002054 15073235735 0010015 0 ustar 00 \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => $this->get_collection_params(),
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
];
}
/**
* Get a collection of terms.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
return $this->get_terms_response( 'product_tag', $request );
}
}
V1/ProductAttributesById.php 0000644 00000003475 15073235735 0012025 0 ustar 00 [\d]+)';
}
/**
* Get method arguments for this REST route.
*
* @return array An array of endpoints.
*/
public function get_args() {
return [
'args' => array(
'id' => array(
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
'type' => 'integer',
),
),
[
'methods' => \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => array(
'context' => $this->get_context_param(
array(
'default' => 'view',
)
),
),
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
];
}
/**
* Get a single item.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
$object = wc_get_attribute( (int) $request['id'] );
if ( ! $object || 0 === $object->id ) {
throw new RouteException( 'woocommerce_rest_attribute_invalid_id', __( 'Invalid attribute ID.', 'woocommerce' ), 404 );
}
$data = $this->prepare_item_for_response( $object, $request );
$response = rest_ensure_response( $data );
return $response;
}
}
V1/ProductReviews.php 0000644 00000015061 15073235735 0010545 0 ustar 00 \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => $this->get_collection_params(),
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
];
}
/**
* Get a collection of reviews.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
$prepared_args = array(
'type' => 'review',
'status' => 'approve',
'no_found_rows' => false,
'offset' => $request['offset'],
'order' => $request['order'],
'number' => $request['per_page'],
'post__in' => $request['product_id'],
);
/**
* Map category id to list of product ids.
*/
if ( ! empty( $request['category_id'] ) ) {
$category_ids = $request['category_id'];
$child_ids = [];
foreach ( $category_ids as $category_id ) {
$child_ids = array_merge( $child_ids, get_term_children( $category_id, 'product_cat' ) );
}
$category_ids = array_unique( array_merge( $category_ids, $child_ids ) );
$product_ids = get_objects_in_term( $category_ids, 'product_cat' );
$prepared_args['post__in'] = isset( $prepared_args['post__in'] ) ? array_merge( $prepared_args['post__in'], $product_ids ) : $product_ids;
}
if ( 'rating' === $request['orderby'] ) {
$prepared_args['meta_query'] = array( // phpcs:ignore
'relation' => 'OR',
array(
'key' => 'rating',
'compare' => 'EXISTS',
),
array(
'key' => 'rating',
'compare' => 'NOT EXISTS',
),
);
}
$prepared_args['orderby'] = $this->normalize_query_param( $request['orderby'] );
if ( empty( $request['offset'] ) ) {
$prepared_args['offset'] = $prepared_args['number'] * ( absint( $request['page'] ) - 1 );
}
$query = new WP_Comment_Query();
$query_result = $query->query( $prepared_args );
$response_objects = array();
foreach ( $query_result as $review ) {
$data = $this->prepare_item_for_response( $review, $request );
$response_objects[] = $this->prepare_response_for_collection( $data );
}
$total_reviews = (int) $query->found_comments;
$max_pages = (int) $query->max_num_pages;
if ( $total_reviews < 1 ) {
// Out-of-bounds, run the query again without LIMIT for total count.
unset( $prepared_args['number'], $prepared_args['offset'] );
$query = new WP_Comment_Query();
$prepared_args['count'] = true;
$total_reviews = $query->query( $prepared_args );
$max_pages = $request['per_page'] ? ceil( $total_reviews / $request['per_page'] ) : 1;
}
$response = rest_ensure_response( $response_objects );
$response = ( new Pagination() )->add_headers( $response, $request, $total_reviews, $max_pages );
return $response;
}
/**
* Prepends internal property prefix to query parameters to match our response fields.
*
* @param string $query_param Query parameter.
* @return string
*/
protected function normalize_query_param( $query_param ) {
$prefix = 'comment_';
switch ( $query_param ) {
case 'id':
$normalized = $prefix . 'ID';
break;
case 'product':
$normalized = $prefix . 'post_ID';
break;
case 'rating':
$normalized = 'meta_value_num';
break;
default:
$normalized = $prefix . $query_param;
break;
}
return $normalized;
}
/**
* Get the query params for collections of products.
*
* @return array
*/
public function get_collection_params() {
$params = array();
$params['context'] = $this->get_context_param();
$params['context']['default'] = 'view';
$params['page'] = array(
'description' => __( 'Current page of the collection.', 'woocommerce' ),
'type' => 'integer',
'default' => 1,
'sanitize_callback' => 'absint',
'validate_callback' => 'rest_validate_request_arg',
'minimum' => 1,
);
$params['per_page'] = array(
'description' => __( 'Maximum number of items to be returned in result set. Defaults to no limit if left blank.', 'woocommerce' ),
'type' => 'integer',
'default' => 10,
'minimum' => 0,
'maximum' => 100,
'sanitize_callback' => 'absint',
'validate_callback' => 'rest_validate_request_arg',
);
$params['offset'] = array(
'description' => __( 'Offset the result set by a specific number of items.', 'woocommerce' ),
'type' => 'integer',
'sanitize_callback' => 'absint',
'validate_callback' => 'rest_validate_request_arg',
);
$params['order'] = array(
'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce' ),
'type' => 'string',
'default' => 'desc',
'enum' => array( 'asc', 'desc' ),
'validate_callback' => 'rest_validate_request_arg',
);
$params['orderby'] = array(
'description' => __( 'Sort collection by object attribute.', 'woocommerce' ),
'type' => 'string',
'default' => 'date',
'enum' => array(
'date',
'date_gmt',
'id',
'rating',
'product',
),
'validate_callback' => 'rest_validate_request_arg',
);
$params['category_id'] = array(
'description' => __( 'Limit result set to reviews from specific category IDs.', 'woocommerce' ),
'type' => 'string',
'sanitize_callback' => 'wp_parse_id_list',
'validate_callback' => 'rest_validate_request_arg',
);
$params['product_id'] = array(
'description' => __( 'Limit result set to reviews from specific product IDs.', 'woocommerce' ),
'type' => 'string',
'sanitize_callback' => 'wp_parse_id_list',
'validate_callback' => 'rest_validate_request_arg',
);
return $params;
}
}
V1/ProductCategoriesById.php 0000644 00000003443 15073235735 0011757 0 ustar 00 [\d]+)';
}
/**
* Get method arguments for this REST route.
*
* @return array An array of endpoints.
*/
public function get_args() {
return [
'args' => array(
'id' => array(
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
'type' => 'integer',
),
),
[
'methods' => \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => array(
'context' => $this->get_context_param(
array(
'default' => 'view',
)
),
),
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
];
}
/**
* Get a single item.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
$object = get_term( (int) $request['id'], 'product_cat' );
if ( ! $object || 0 === $object->id ) {
throw new RouteException( 'woocommerce_rest_category_invalid_id', __( 'Invalid category ID.', 'woocommerce' ), 404 );
}
$data = $this->prepare_item_for_response( $object, $request );
return rest_ensure_response( $data );
}
}
V1/AbstractRoute.php 0000644 00000023435 15073235735 0010346 0 ustar 00 schema_controller = $schema_controller;
$this->schema = $schema;
}
/**
* Get the namespace for this route.
*
* @return string
*/
public function get_namespace() {
return $this->namespace;
}
/**
* Set the namespace for this route.
*
* @param string $namespace Given namespace.
*/
public function set_namespace( $namespace ) {
$this->namespace = $namespace;
}
/**
* Get item schema properties.
*
* @return array
*/
public function get_item_schema() {
return $this->schema->get_item_schema();
}
/**
* Get the route response based on the type of request.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
public function get_response( \WP_REST_Request $request ) {
$response = null;
try {
$response = $this->get_response_by_request_method( $request );
} catch ( RouteException $error ) {
$response = $this->get_route_error_response( $error->getErrorCode(), $error->getMessage(), $error->getCode(), $error->getAdditionalData() );
} catch ( InvalidCartException $error ) {
$response = $this->get_route_error_response_from_object( $error->getError(), $error->getCode(), $error->getAdditionalData() );
} catch ( \Exception $error ) {
$response = $this->get_route_error_response( 'woocommerce_rest_unknown_server_error', $error->getMessage(), 500 );
}
return is_wp_error( $response ) ? $this->error_to_response( $response ) : $response;
}
/**
* Get the route response based on the type of request.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_response_by_request_method( \WP_REST_Request $request ) {
switch ( $request->get_method() ) {
case 'POST':
return $this->get_route_post_response( $request );
case 'PUT':
case 'PATCH':
return $this->get_route_update_response( $request );
case 'DELETE':
return $this->get_route_delete_response( $request );
}
return $this->get_route_response( $request );
}
/**
* Converts an error to a response object. Based on \WP_REST_Server.
*
* @param \WP_Error $error WP_Error instance.
* @return \WP_REST_Response List of associative arrays with code and message keys.
*/
protected function error_to_response( $error ) {
$error_data = $error->get_error_data();
$status = isset( $error_data, $error_data['status'] ) ? $error_data['status'] : 500;
$errors = [];
foreach ( (array) $error->errors as $code => $messages ) {
foreach ( (array) $messages as $message ) {
$errors[] = array(
'code' => $code,
'message' => $message,
'data' => $error->get_error_data( $code ),
);
}
}
$data = array_shift( $errors );
if ( count( $errors ) ) {
$data['additional_errors'] = $errors;
}
return new \WP_REST_Response( $data, $status );
}
/**
* Get route response for GET requests.
*
* When implemented, should return a \WP_REST_Response.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
return $this->get_route_error_response( 'woocommerce_rest_invalid_endpoint', __( 'Method not implemented', 'woocommerce' ), 404 );
}
/**
* Get route response for POST requests.
*
* When implemented, should return a \WP_REST_Response.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
return $this->get_route_error_response( 'woocommerce_rest_invalid_endpoint', __( 'Method not implemented', 'woocommerce' ), 404 );
}
/**
* Get route response for PUT requests.
*
* When implemented, should return a \WP_REST_Response.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_update_response( \WP_REST_Request $request ) {
return $this->get_route_error_response( 'woocommerce_rest_invalid_endpoint', __( 'Method not implemented', 'woocommerce' ), 404 );
}
/**
* Get route response for DELETE requests.
*
* When implemented, should return a \WP_REST_Response.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_delete_response( \WP_REST_Request $request ) {
return $this->get_route_error_response( 'woocommerce_rest_invalid_endpoint', __( 'Method not implemented', 'woocommerce' ), 404 );
}
/**
* Get route response when something went wrong.
*
* @param string $error_code String based error code.
* @param string $error_message User facing error message.
* @param int $http_status_code HTTP status. Defaults to 500.
* @param array $additional_data Extra data (key value pairs) to expose in the error response.
* @return \WP_Error WP Error object.
*/
protected function get_route_error_response( $error_code, $error_message, $http_status_code = 500, $additional_data = [] ) {
return new \WP_Error( $error_code, $error_message, array_merge( $additional_data, [ 'status' => $http_status_code ] ) );
}
/**
* Get route response when something went wrong and the supplied error is a WP_Error. This currently only happens
* when an item in the cart is out of stock, partially out of stock, can only be bought individually, or when the
* item is not purchasable.
*
* @param WP_Error $error_object The WP_Error object containing the error.
* @param int $http_status_code HTTP status. Defaults to 500.
* @param array $additional_data Extra data (key value pairs) to expose in the error response.
* @return WP_Error WP Error object.
*/
protected function get_route_error_response_from_object( $error_object, $http_status_code = 500, $additional_data = [] ) {
$error_object->add_data( array_merge( $additional_data, [ 'status' => $http_status_code ] ) );
return $error_object;
}
/**
* Prepare a single item for response.
*
* @param mixed $item Item to format to schema.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response $response Response data.
*/
public function prepare_item_for_response( $item, \WP_REST_Request $request ) {
$response = rest_ensure_response( $this->schema->get_item_response( $item ) );
$response->add_links( $this->prepare_links( $item, $request ) );
return $response;
}
/**
* Retrieves the context param.
*
* Ensures consistent descriptions between endpoints, and populates enum from schema.
*
* @param array $args Optional. Additional arguments for context parameter. Default empty array.
* @return array Context parameter details.
*/
protected function get_context_param( $args = array() ) {
$param_details = array(
'description' => __( 'Scope under which the request is made; determines fields present in response.', 'woocommerce' ),
'type' => 'string',
'sanitize_callback' => 'sanitize_key',
'validate_callback' => 'rest_validate_request_arg',
);
$schema = $this->get_item_schema();
if ( empty( $schema['properties'] ) ) {
return array_merge( $param_details, $args );
}
$contexts = array();
foreach ( $schema['properties'] as $attributes ) {
if ( ! empty( $attributes['context'] ) ) {
$contexts = array_merge( $contexts, $attributes['context'] );
}
}
if ( ! empty( $contexts ) ) {
$param_details['enum'] = array_unique( $contexts );
rsort( $param_details['enum'] );
}
return array_merge( $param_details, $args );
}
/**
* Prepares a response for insertion into a collection.
*
* @param \WP_REST_Response $response Response object.
* @return array|mixed Response data, ready for insertion into collection data.
*/
protected function prepare_response_for_collection( \WP_REST_Response $response ) {
$data = (array) $response->get_data();
$server = rest_get_server();
$links = $server::get_compact_response_links( $response );
if ( ! empty( $links ) ) {
$data['_links'] = $links;
}
return $data;
}
/**
* Prepare links for the request.
*
* @param mixed $item Item to prepare.
* @param \WP_REST_Request $request Request object.
* @return array
*/
protected function prepare_links( $item, $request ) {
return [];
}
/**
* Retrieves the query params for the collections.
*
* @return array Query parameters for the collection.
*/
public function get_collection_params() {
return array(
'context' => $this->get_context_param(),
);
}
}
V1/ProductAttributes.php 0000644 00000002634 15073235735 0011251 0 ustar 00 \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => $this->get_collection_params(),
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
];
}
/**
* Get a collection of attributes.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
$ids = wc_get_attribute_taxonomy_ids();
$return = [];
foreach ( $ids as $id ) {
$object = wc_get_attribute( $id );
$data = $this->prepare_item_for_response( $object, $request );
$return[] = $this->prepare_response_for_collection( $data );
}
return rest_ensure_response( $return );
}
}
V1/CartRemoveCoupon.php 0000644 00000004424 15073235735 0011014 0 ustar 00 \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => [
'code' => [
'description' => __( 'Unique identifier for the coupon within the cart.', 'woocommerce' ),
'type' => 'string',
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Handle the request and return a valid response for this endpoint.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
if ( ! wc_coupons_enabled() ) {
throw new RouteException( 'woocommerce_rest_cart_coupon_disabled', __( 'Coupons are disabled.', 'woocommerce' ), 404 );
}
$cart = $this->cart_controller->get_cart_instance();
$coupon_code = wc_format_coupon_code( $request['code'] );
$coupon = new \WC_Coupon( $coupon_code );
if ( $coupon->get_code() !== $coupon_code || ! $coupon->is_valid() ) {
throw new RouteException( 'woocommerce_rest_cart_coupon_error', __( 'Invalid coupon code.', 'woocommerce' ), 400 );
}
if ( ! $this->cart_controller->has_coupon( $coupon_code ) ) {
throw new RouteException( 'woocommerce_rest_cart_coupon_invalid_code', __( 'Coupon cannot be removed because it is not already applied to the cart.', 'woocommerce' ), 409 );
}
$cart = $this->cart_controller->get_cart_instance();
$cart->remove_coupon( $coupon_code );
$cart->calculate_totals();
return rest_ensure_response( $this->schema->get_item_response( $cart ) );
}
}
V1/CartSelectShippingRate.php 0000644 00000006567 15073235735 0012142 0 ustar 00 \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => [
'package_id' => array(
'description' => __( 'The ID of the package being shipped. Leave blank to apply to all packages.', 'woocommerce' ),
'type' => [ 'integer', 'string', 'null' ],
'required' => false,
),
'rate_id' => [
'description' => __( 'The chosen rate ID for the package.', 'woocommerce' ),
'type' => 'string',
'required' => true,
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Handle the request and return a valid response for this endpoint.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
if ( ! wc_shipping_enabled() ) {
throw new RouteException( 'woocommerce_rest_shipping_disabled', __( 'Shipping is disabled.', 'woocommerce' ), 404 );
}
if ( ! isset( $request['rate_id'] ) ) {
throw new RouteException( 'woocommerce_rest_cart_missing_rate_id', __( 'Invalid Rate ID.', 'woocommerce' ), 400 );
}
$cart = $this->cart_controller->get_cart_instance();
$package_id = isset( $request['package_id'] ) ? sanitize_text_field( wp_unslash( $request['package_id'] ) ) : null;
$rate_id = sanitize_text_field( wp_unslash( $request['rate_id'] ) );
try {
if ( ! is_null( $package_id ) ) {
$this->cart_controller->select_shipping_rate( $package_id, $rate_id );
} else {
foreach ( $this->cart_controller->get_shipping_packages() as $package ) {
$this->cart_controller->select_shipping_rate( $package['package_id'], $rate_id );
}
}
} catch ( \WC_Rest_Exception $e ) {
throw new RouteException( $e->getErrorCode(), $e->getMessage(), $e->getCode() );
}
/**
* Fires an action after a shipping method has been chosen for package(s) via the Store API.
*
* This allows extensions to perform addition actions after a shipping method has been chosen, but before the
* cart totals are recalculated.
*
* @since 9.0.0
*
* @param string|null $package_id The sanitized ID of the package being updated. Null if all packages are being updated.
* @param string $rate_id The sanitized chosen rate ID for the package.
* @param \WP_REST_Request $request Full details about the request.
*/
do_action( 'woocommerce_store_api_cart_select_shipping_rate', $package_id, $rate_id, $request );
$cart->calculate_shipping();
$cart->calculate_totals();
return rest_ensure_response( $this->cart_schema->get_item_response( $cart ) );
}
}
V1/AbstractCartRoute.php 0000644 00000024442 15073235735 0011157 0 ustar 00 cart_schema = $this->schema_controller->get( CartSchema::IDENTIFIER );
$this->cart_item_schema = $this->schema_controller->get( CartItemSchema::IDENTIFIER );
$this->cart_controller = new CartController();
$this->additional_fields_controller = Package::container()->get( CheckoutFields::class );
$this->order_controller = new OrderController();
}
/**
* Are we updating data or getting data?
*
* @param \WP_REST_Request $request Request object.
* @return boolean
*/
protected function is_update_request( \WP_REST_Request $request ) {
return in_array( $request->get_method(), [ 'POST', 'PUT', 'PATCH', 'DELETE' ], true );
}
/**
* Get the route response based on the type of request.
*
* @param \WP_REST_Request $request Request object.
*
* @return \WP_REST_Response
*/
public function get_response( \WP_REST_Request $request ) {
$this->load_cart_session( $request );
$this->cart_controller->calculate_totals();
$response = null;
$nonce_check = $this->requires_nonce( $request ) ? $this->check_nonce( $request ) : null;
if ( is_wp_error( $nonce_check ) ) {
$response = $nonce_check;
}
if ( ! $response ) {
try {
$response = $this->get_response_by_request_method( $request );
} catch ( RouteException $error ) {
$response = $this->get_route_error_response( $error->getErrorCode(), $error->getMessage(), $error->getCode(), $error->getAdditionalData() );
} catch ( \Exception $error ) {
$response = $this->get_route_error_response( 'woocommerce_rest_unknown_server_error', $error->getMessage(), 500 );
}
}
// For update requests, this will recalculate cart totals and sync draft orders with the current cart.
if ( $this->is_update_request( $request ) ) {
$this->cart_updated( $request );
}
// Format error responses.
if ( is_wp_error( $response ) ) {
$response = $this->error_to_response( $response );
}
return $this->add_response_headers( rest_ensure_response( $response ) );
}
/**
* Add nonce headers to a response object.
*
* @param \WP_REST_Response $response The response object.
*
* @return \WP_REST_Response
*/
protected function add_response_headers( \WP_REST_Response $response ) {
$nonce = wp_create_nonce( 'wc_store_api' );
$response->header( 'Nonce', $nonce );
$response->header( 'Nonce-Timestamp', time() );
$response->header( 'User-ID', get_current_user_id() );
$response->header( 'Cart-Token', $this->get_cart_token() );
// The following headers are deprecated and should be removed in a future version.
$response->header( 'X-WC-Store-API-Nonce', $nonce );
return $response;
}
/**
* Load the cart session before handling responses.
*
* @param \WP_REST_Request $request Request object.
*/
protected function load_cart_session( \WP_REST_Request $request ) {
$cart_token = $request->get_header( 'Cart-Token' );
if ( $cart_token && JsonWebToken::validate( $cart_token, $this->get_cart_token_secret() ) ) {
// Overrides the core session class.
add_filter(
'woocommerce_session_handler',
function () {
return SessionHandler::class;
}
);
}
$this->cart_controller->load_cart();
}
/**
* Generates a cart token for the response headers.
*
* Current namespace is used as the token Issuer.
* *
*
* @return string
*/
protected function get_cart_token() {
return JsonWebToken::create(
[
'user_id' => wc()->session->get_customer_id(),
'exp' => $this->get_cart_token_expiration(),
'iss' => $this->namespace,
],
$this->get_cart_token_secret()
);
}
/**
* Gets the secret for the cart token using wp_salt.
*
* @return string
*/
protected function get_cart_token_secret() {
return '@' . wp_salt();
}
/**
* Gets the expiration of the cart token. Defaults to 48h.
*
* @return int
*/
protected function get_cart_token_expiration() {
/**
* Filters the session expiration.
*
* @since 8.7.0
*
* @param int $expiration Expiration in seconds.
*/
return time() + intval( apply_filters( 'wc_session_expiration', DAY_IN_SECONDS * 2 ) );
}
/**
* Checks if a nonce is required for the route.
*
* @param \WP_REST_Request $request Request.
*
* @return bool
*/
protected function requires_nonce( \WP_REST_Request $request ) {
return $this->is_update_request( $request );
}
/**
* Triggered after an update to cart data. Re-calculates totals and updates draft orders (if they already exist) to
* keep all data in sync.
*
* @param \WP_REST_Request $request Request object.
*/
protected function cart_updated( \WP_REST_Request $request ) {
$draft_order = $this->get_draft_order();
if ( $draft_order ) {
// This does not trigger a recalculation of the cart--endpoints should have already done so before returning
// the cart response.
$this->order_controller->update_order_from_cart( $draft_order, false );
wc_do_deprecated_action(
'woocommerce_blocks_cart_update_order_from_request',
array(
$draft_order,
$request,
),
'7.2.0',
'woocommerce_store_api_cart_update_order_from_request',
'This action was deprecated in WooCommerce Blocks version 7.2.0. Please use woocommerce_store_api_cart_update_order_from_request instead.'
);
/**
* Fires when the order is synced with cart data from a cart route.
*
* @since 7.2.0
*
* @param \WC_Order $draft_order Order object.
* @param \WC_Customer $customer Customer object.
* @param \WP_REST_Request $request Full details about the request.
*/
do_action( 'woocommerce_store_api_cart_update_order_from_request', $draft_order, $request );
}
}
/**
* For non-GET endpoints, require and validate a nonce to prevent CSRF attacks.
*
* Nonces will mismatch if the logged in session cookie is different! If using a client to test, set this cookie
* to match the logged in cookie in your browser.
*
* @param \WP_REST_Request $request Request object.
*
* @return \WP_Error|boolean
*/
protected function check_nonce( \WP_REST_Request $request ) {
$nonce = null;
if ( $request->get_header( 'Nonce' ) ) {
$nonce = $request->get_header( 'Nonce' );
} elseif ( $request->get_header( 'X-WC-Store-API-Nonce' ) ) {
$nonce = $request->get_header( 'X-WC-Store-API-Nonce' );
// @todo Remove handling and sending of deprecated X-WC-Store-API-Nonce Header (Blocks 7.5.0)
wc_deprecated_argument( 'X-WC-Store-API-Nonce', '7.2.0', 'Use the "Nonce" Header instead. This header will be removed after Blocks release 7.5' );
rest_handle_deprecated_argument( 'X-WC-Store-API-Nonce', 'Use the "Nonce" Header instead. This header will be removed after Blocks release 7.5', '7.2.0' );
}
/**
* Filters the Store API nonce check.
*
* This can be used to disable the nonce check when testing API endpoints via a REST API client.
*
* @since 4.5.0
*
* @param boolean $disable_nonce_check If true, nonce checks will be disabled.
*
* @return boolean
*/
if ( apply_filters( 'woocommerce_store_api_disable_nonce_check', false ) ) {
return true;
}
if ( null === $nonce ) {
return $this->get_route_error_response( 'woocommerce_rest_missing_nonce', __( 'Missing the Nonce header. This endpoint requires a valid nonce.', 'woocommerce' ), 401 );
}
if ( ! wp_verify_nonce( $nonce, 'wc_store_api' ) ) {
return $this->get_route_error_response( 'woocommerce_rest_invalid_nonce', __( 'Nonce is invalid.', 'woocommerce' ), 403 );
}
return true;
}
/**
* Get route response when something went wrong.
*
* @param string $error_code String based error code.
* @param string $error_message User facing error message.
* @param int $http_status_code HTTP status. Defaults to 500.
* @param array $additional_data Extra data (key value pairs) to expose in the error response.
*
* @return \WP_Error WP Error object.
*/
protected function get_route_error_response( $error_code, $error_message, $http_status_code = 500, $additional_data = [] ) {
switch ( $http_status_code ) {
case 409:
// If there was a conflict, return the cart so the client can resolve it.
$cart = $this->cart_controller->get_cart_instance();
return new \WP_Error(
$error_code,
$error_message,
array_merge(
$additional_data,
[
'status' => $http_status_code,
'cart' => $this->cart_schema->get_item_response( $cart ),
]
)
);
}
return new \WP_Error( $error_code, $error_message, [ 'status' => $http_status_code ] );
}
}
V1/CartCouponsByCode.php 0000644 00000005040 15073235735 0011102 0 ustar 00 [\w-]+)';
}
/**
* Get method arguments for this REST route.
*
* @return array An array of endpoints.
*/
public function get_args() {
return [
'args' => [
'code' => [
'description' => __( 'Unique identifier for the coupon within the cart.', 'woocommerce' ),
'type' => 'string',
],
],
[
'methods' => \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => [
'context' => $this->get_context_param( [ 'default' => 'view' ] ),
],
],
[
'methods' => \WP_REST_Server::DELETABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Get a single cart coupon.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
if ( ! $this->cart_controller->has_coupon( $request['code'] ) ) {
throw new RouteException( 'woocommerce_rest_cart_coupon_invalid_code', __( 'Coupon does not exist in the cart.', 'woocommerce' ), 404 );
}
return $this->prepare_item_for_response( $request['code'], $request );
}
/**
* Delete a single cart coupon.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_delete_response( \WP_REST_Request $request ) {
if ( ! $this->cart_controller->has_coupon( $request['code'] ) ) {
throw new RouteException( 'woocommerce_rest_cart_coupon_invalid_code', __( 'Coupon does not exist in the cart.', 'woocommerce' ), 404 );
}
$cart = $this->cart_controller->get_cart_instance();
$cart->remove_coupon( $request['code'] );
$cart->calculate_totals();
return new \WP_REST_Response( null, 204 );
}
}
V1/CartAddItem.php 0000644 00000007477 15073235735 0007715 0 ustar 00 \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => [
'id' => [
'description' => __( 'The cart item product or variation ID.', 'woocommerce' ),
'type' => 'integer',
'context' => [ 'view', 'edit' ],
'sanitize_callback' => 'absint',
],
'quantity' => [
'description' => __( 'Quantity of this item to add to the cart.', 'woocommerce' ),
'type' => 'integer',
'context' => [ 'view', 'edit' ],
'arg_options' => [
'sanitize_callback' => 'wc_stock_amount',
],
],
'variation' => [
'description' => __( 'Chosen attributes (for variations).', 'woocommerce' ),
'type' => 'array',
'context' => [ 'view', 'edit' ],
'items' => [
'type' => 'object',
'properties' => [
'attribute' => [
'description' => __( 'Variation attribute name.', 'woocommerce' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
],
'value' => [
'description' => __( 'Variation attribute value.', 'woocommerce' ),
'type' => 'string',
'context' => [ 'view', 'edit' ],
],
],
],
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Handle the request and return a valid response for this endpoint.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
// Do not allow key to be specified during creation.
if ( ! empty( $request['key'] ) ) {
throw new RouteException( 'woocommerce_rest_cart_item_exists', __( 'Cannot create an existing cart item.', 'woocommerce' ), 400 );
}
$cart = $this->cart_controller->get_cart_instance();
/**
* Filters cart item data sent via the API before it is passed to the cart controller.
*
* This hook filters cart items. It allows the request data to be changed, for example, quantity, or
* supplemental cart item data, before it is passed into CartController::add_to_cart and stored to session.
*
* CartController::add_to_cart only expects the keys id, quantity, variation, and cart_item_data, so other values
* may be ignored. CartController::add_to_cart (and core) do already have a filter hook called
* woocommerce_add_cart_item, but this does not have access to the original Store API request like this hook does.
*
* @since 8.8.0
*
* @param array $add_to_cart_data An array of cart item data.
* @return array
*/
$add_to_cart_data = apply_filters(
'woocommerce_store_api_add_to_cart_data',
array(
'id' => $request['id'],
'quantity' => $request['quantity'],
'variation' => $request['variation'],
'cart_item_data' => [],
),
$request
);
$this->cart_controller->add_to_cart( $add_to_cart_data );
$response = rest_ensure_response( $this->schema->get_item_response( $cart ) );
$response->set_status( 201 );
return $response;
}
}
V1/Checkout.php 0000644 00000057705 15073235735 0007340 0 ustar 00 \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => [
'context' => $this->get_context_param( [ 'default' => 'view' ] ),
],
],
[
'methods' => \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => array_merge(
[
'payment_data' => [
'description' => __( 'Data to pass through to the payment method when processing payment.', 'woocommerce' ),
'type' => 'array',
'items' => [
'type' => 'object',
'properties' => [
'key' => [
'type' => 'string',
],
'value' => [
'type' => [ 'string', 'boolean' ],
],
],
],
],
],
$this->schema->get_endpoint_args_for_item_schema( \WP_REST_Server::CREATABLE )
),
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Get the route response based on the type of request.
*
* @param \WP_REST_Request $request Request object.
*
* @return \WP_REST_Response
*/
public function get_response( \WP_REST_Request $request ) {
$this->load_cart_session( $request );
$this->cart_controller->calculate_totals();
$response = null;
$nonce_check = $this->requires_nonce( $request ) ? $this->check_nonce( $request ) : null;
if ( is_wp_error( $nonce_check ) ) {
$response = $nonce_check;
}
if ( ! $response ) {
try {
$response = $this->get_response_by_request_method( $request );
} catch ( InvalidCartException $error ) {
$response = $this->get_route_error_response_from_object( $error->getError(), $error->getCode(), $error->getAdditionalData() );
} catch ( RouteException $error ) {
$response = $this->get_route_error_response( $error->getErrorCode(), $error->getMessage(), $error->getCode(), $error->getAdditionalData() );
} catch ( \Exception $error ) {
$response = $this->get_route_error_response( 'woocommerce_rest_unknown_server_error', $error->getMessage(), 500 );
}
}
if ( is_wp_error( $response ) ) {
$response = $this->error_to_response( $response );
}
return $this->add_response_headers( $response );
}
/**
* Convert the cart into a new draft order, or update an existing draft order, and return an updated cart response.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
$this->create_or_update_draft_order( $request );
return $this->prepare_item_for_response(
(object) [
'order' => $this->order,
'payment_result' => new PaymentResult(),
],
$request
);
}
/**
* Process an order.
*
* 1. Obtain Draft Order
* 2. Process Request
* 3. Process Customer
* 4. Validate Order
* 5. Process Payment
*
* @throws RouteException On error.
* @throws InvalidStockLevelsInCartException On error.
*
* @param \WP_REST_Request $request Request object.
*
* @return \WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
/**
* Validate items etc are allowed in the order before the order is processed. This will fix violations and tell
* the customer.
*/
$this->cart_controller->validate_cart();
/**
* Obtain Draft Order and process request data.
*
* Note: Customer data is persisted from the request first so that OrderController::update_addresses_from_cart
* uses the up to date customer address.
*/
$this->update_customer_from_request( $request );
$this->create_or_update_draft_order( $request );
$this->update_order_from_request( $request );
/**
* Process customer data.
*
* Update order with customer details, and sign up a user account as necessary.
*/
$this->process_customer( $request );
/**
* Validate order.
*
* This logic ensures the order is valid before payment is attempted.
*/
$this->order_controller->validate_order_before_payment( $this->order );
wc_do_deprecated_action(
'__experimental_woocommerce_blocks_checkout_order_processed',
array(
$this->order,
),
'6.3.0',
'woocommerce_store_api_checkout_order_processed',
'This action was deprecated in WooCommerce Blocks version 6.3.0. Please use woocommerce_store_api_checkout_order_processed instead.'
);
wc_do_deprecated_action(
'woocommerce_blocks_checkout_order_processed',
array(
$this->order,
),
'7.2.0',
'woocommerce_store_api_checkout_order_processed',
'This action was deprecated in WooCommerce Blocks version 7.2.0. Please use woocommerce_store_api_checkout_order_processed instead.'
);
/**
* Fires before an order is processed by the Checkout Block/Store API.
*
* This hook informs extensions that $order has completed processing and is ready for payment.
*
* This is similar to existing core hook woocommerce_checkout_order_processed. We're using a new action:
* - To keep the interface focused (only pass $order, not passing request data).
* - This also explicitly indicates these orders are from checkout block/StoreAPI.
*
* @since 7.2.0
*
* @see https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3238
* @example See docs/examples/checkout-order-processed.md
* @param \WC_Order $order Order object.
*/
do_action( 'woocommerce_store_api_checkout_order_processed', $this->order );
/**
* Process the payment and return the results.
*/
$payment_result = new PaymentResult();
if ( $this->order->needs_payment() ) {
$this->process_payment( $request, $payment_result );
} else {
$this->process_without_payment( $request, $payment_result );
}
return $this->prepare_item_for_response(
(object) [
'order' => wc_get_order( $this->order ),
'payment_result' => $payment_result,
],
$request
);
}
/**
* Get route response when something went wrong.
*
* @param string $error_code String based error code.
* @param string $error_message User facing error message.
* @param int $http_status_code HTTP status. Defaults to 500.
* @param array $additional_data Extra data (key value pairs) to expose in the error response.
* @return \WP_Error WP Error object.
*/
protected function get_route_error_response( $error_code, $error_message, $http_status_code = 500, $additional_data = [] ) {
$error_from_message = new \WP_Error(
$error_code,
$error_message
);
// 409 is when there was a conflict, so we return the cart so the client can resolve it.
if ( 409 === $http_status_code ) {
return $this->add_data_to_error_object( $error_from_message, $additional_data, $http_status_code, true );
}
return $this->add_data_to_error_object( $error_from_message, $additional_data, $http_status_code );
}
/**
* Get route response when something went wrong.
*
* @param \WP_Error $error_object User facing error message.
* @param int $http_status_code HTTP status. Defaults to 500.
* @param array $additional_data Extra data (key value pairs) to expose in the error response.
* @return \WP_Error WP Error object.
*/
protected function get_route_error_response_from_object( $error_object, $http_status_code = 500, $additional_data = [] ) {
// 409 is when there was a conflict, so we return the cart so the client can resolve it.
if ( 409 === $http_status_code ) {
return $this->add_data_to_error_object( $error_object, $additional_data, $http_status_code, true );
}
return $this->add_data_to_error_object( $error_object, $additional_data, $http_status_code );
}
/**
* Adds additional data to the \WP_Error object.
*
* @param \WP_Error $error The error object to add the cart to.
* @param array $data The data to add to the error object.
* @param int $http_status_code The HTTP status code this error should return.
* @param bool $include_cart Whether the cart should be included in the error data.
* @returns \WP_Error The \WP_Error with the cart added.
*/
private function add_data_to_error_object( $error, $data, $http_status_code, bool $include_cart = false ) {
$data = array_merge( $data, [ 'status' => $http_status_code ] );
if ( $include_cart ) {
$data = array_merge( $data, [ 'cart' => wc()->api->get_endpoint_data( '/wc/store/v1/cart' ) ] );
}
$error->add_data( $data );
return $error;
}
/**
* Create or update a draft order based on the cart.
*
* @param \WP_REST_Request $request Full details about the request.
* @throws RouteException On error.
*/
private function create_or_update_draft_order( \WP_REST_Request $request ) {
$this->order = $this->get_draft_order();
if ( ! $this->order ) {
$this->order = $this->order_controller->create_order_from_cart();
} else {
$this->order_controller->update_order_from_cart( $this->order, true );
}
wc_do_deprecated_action(
'__experimental_woocommerce_blocks_checkout_update_order_meta',
array(
$this->order,
),
'6.3.0',
'woocommerce_store_api_checkout_update_order_meta',
'This action was deprecated in WooCommerce Blocks version 6.3.0. Please use woocommerce_store_api_checkout_update_order_meta instead.'
);
wc_do_deprecated_action(
'woocommerce_blocks_checkout_update_order_meta',
array(
$this->order,
),
'7.2.0',
'woocommerce_store_api_checkout_update_order_meta',
'This action was deprecated in WooCommerce Blocks version 7.2.0. Please use woocommerce_store_api_checkout_update_order_meta instead.'
);
/**
* Fires when the Checkout Block/Store API updates an order's meta data.
*
* This hook gives extensions the chance to add or update meta data on the $order.
* Throwing an exception from a callback attached to this action will make the Checkout Block render in a warning state, effectively preventing checkout.
*
* This is similar to existing core hook woocommerce_checkout_update_order_meta.
* We're using a new action:
* - To keep the interface focused (only pass $order, not passing request data).
* - This also explicitly indicates these orders are from checkout block/StoreAPI.
*
* @since 7.2.0
*
* @see https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3686
*
* @param \WC_Order $order Order object.
*/
do_action( 'woocommerce_store_api_checkout_update_order_meta', $this->order );
// Confirm order is valid before proceeding further.
if ( ! $this->order instanceof \WC_Order ) {
throw new RouteException(
'woocommerce_rest_checkout_missing_order',
__( 'Unable to create order', 'woocommerce' ),
500
);
}
// Store order ID to session.
$this->set_draft_order_id( $this->order->get_id() );
/**
* Try to reserve stock for the order.
*
* If creating a draft order on checkout entry, set the timeout to 10 mins.
* If POSTing to the checkout (attempting to pay), set the timeout to 60 mins (using the woocommerce_hold_stock_minutes option).
*/
try {
$reserve_stock = new ReserveStock();
$duration = $request->get_method() === 'POST' ? (int) get_option( 'woocommerce_hold_stock_minutes', 60 ) : 10;
$reserve_stock->reserve_stock_for_order( $this->order, $duration );
} catch ( ReserveStockException $e ) {
throw new RouteException(
$e->getErrorCode(),
$e->getMessage(),
$e->getCode()
);
}
}
/**
* Updates the current customer session using data from the request (e.g. address data).
*
* Address session data is synced to the order itself later on by OrderController::update_order_from_cart()
*
* @param \WP_REST_Request $request Full details about the request.
*/
private function update_customer_from_request( \WP_REST_Request $request ) {
$customer = wc()->customer;
// Billing address is a required field.
foreach ( $request['billing_address'] as $key => $value ) {
if ( is_callable( [ $customer, "set_billing_$key" ] ) ) {
$customer->{"set_billing_$key"}( $value );
} elseif ( $this->additional_fields_controller->is_field( $key, 'address' ) ) {
$this->additional_fields_controller->persist_field_for_customer( "/billing/$key", $value, $customer );
}
}
// If shipping address (optional field) was not provided, set it to the given billing address (required field).
$shipping_address_values = $request['shipping_address'] ?? $request['billing_address'];
foreach ( $shipping_address_values as $key => $value ) {
if ( is_callable( [ $customer, "set_shipping_$key" ] ) ) {
$customer->{"set_shipping_$key"}( $value );
} elseif ( 'phone' === $key ) {
$customer->update_meta_data( 'shipping_phone', $value );
} elseif ( $this->additional_fields_controller->is_field( $key, 'address' ) ) {
$this->additional_fields_controller->persist_field_for_customer( "/shipping/$key", $value, $customer );
}
}
/**
* Fires when the Checkout Block/Store API updates a customer from the API request data.
*
* @since 8.2.0
*
* @param \WC_Customer $customer Customer object.
* @param \WP_REST_Request $request Full details about the request.
*/
do_action( 'woocommerce_store_api_checkout_update_customer_from_request', $customer, $request );
$customer->save();
}
/**
* Gets the chosen payment method from the request.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WC_Payment_Gateway|null
*/
private function get_request_payment_method( \WP_REST_Request $request ) {
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
$request_payment_method = wc_clean( wp_unslash( $request['payment_method'] ?? '' ) );
$requires_payment_method = $this->order->needs_payment();
if ( empty( $request_payment_method ) ) {
if ( $requires_payment_method ) {
throw new RouteException(
'woocommerce_rest_checkout_missing_payment_method',
__( 'No payment method provided.', 'woocommerce' ),
400
);
}
return null;
}
if ( ! isset( $available_gateways[ $request_payment_method ] ) ) {
$all_payment_gateways = WC()->payment_gateways->payment_gateways();
$gateway_title = isset( $all_payment_gateways[ $request_payment_method ] ) ? $all_payment_gateways[ $request_payment_method ]->get_title() : $request_payment_method;
throw new RouteException(
'woocommerce_rest_checkout_payment_method_disabled',
sprintf(
// Translators: %s Payment method ID.
__( '%s is not available for this order—please choose a different payment method', 'woocommerce' ),
esc_html( $gateway_title )
),
400
);
}
return $available_gateways[ $request_payment_method ];
}
/**
* Order processing relating to customer account.
*
* Creates a customer account as needed (based on request & store settings) and updates the order with the new customer ID.
* Updates the order with user details (e.g. address).
*
* @throws RouteException API error object with error details.
* @param \WP_REST_Request $request Request object.
*/
private function process_customer( \WP_REST_Request $request ) {
try {
if ( $this->should_create_customer_account( $request ) ) {
$customer_id = $this->create_customer_account(
$request['billing_address']['email'],
$request['billing_address']['first_name'],
$request['billing_address']['last_name']
);
// Associate customer with the order. This is done before login to ensure the order is associated with
// the correct customer if login fails.
$this->order->set_customer_id( $customer_id );
$this->order->save();
// Log the customer in to WordPress. Doing this inline instead of using `wc_set_customer_auth_cookie`
// because wc_set_customer_auth_cookie forces the use of session cookie.
wp_set_current_user( $customer_id );
wp_set_auth_cookie( $customer_id, true );
// Init session cookie if the session cookie handler exists.
if ( is_callable( [ WC()->session, 'init_session_cookie' ] ) ) {
WC()->session->init_session_cookie();
}
}
} catch ( \Exception $error ) {
switch ( $error->getMessage() ) {
case 'registration-error-invalid-email':
throw new RouteException(
'registration-error-invalid-email',
__( 'Please provide a valid email address.', 'woocommerce' ),
400
);
case 'registration-error-email-exists':
throw new RouteException(
'registration-error-email-exists',
__( 'An account is already registered with your email address. Please log in before proceeding.', 'woocommerce' ),
400
);
}
}
// Persist customer address data to account.
$this->order_controller->sync_customer_data_with_order( $this->order );
}
/**
* Check request options and store (shop) config to determine if a user account should be created as part of order
* processing.
*
* @param \WP_REST_Request $request The current request object being handled.
* @return boolean True if a new user account should be created.
*/
private function should_create_customer_account( \WP_REST_Request $request ) {
if ( is_user_logged_in() ) {
return false;
}
// Return false if registration is not enabled for the store.
if ( false === filter_var( wc()->checkout()->is_registration_enabled(), FILTER_VALIDATE_BOOLEAN ) ) {
return false;
}
// Return true if the store requires an account for all purchases. Note - checkbox is not displayed to shopper in this case.
if ( true === filter_var( wc()->checkout()->is_registration_required(), FILTER_VALIDATE_BOOLEAN ) ) {
return true;
}
// Create an account if requested via the endpoint.
if ( true === filter_var( $request['create_account'], FILTER_VALIDATE_BOOLEAN ) ) {
// User has requested an account as part of checkout processing.
return true;
}
return false;
}
/**
* Create a new account for a customer.
*
* The account is created with a generated username. The customer is sent
* an email notifying them about the account and containing a link to set
* their (initial) password.
*
* Intended as a replacement for wc_create_new_customer in WC core.
*
* @throws \Exception If an error is encountered when creating the user account.
*
* @param string $user_email The email address to use for the new account.
* @param string $first_name The first name to use for the new account.
* @param string $last_name The last name to use for the new account.
*
* @return int User id if successful
*/
private function create_customer_account( $user_email, $first_name, $last_name ) {
if ( empty( $user_email ) || ! is_email( $user_email ) ) {
throw new \Exception( 'registration-error-invalid-email' );
}
if ( email_exists( $user_email ) ) {
throw new \Exception( 'registration-error-email-exists' );
}
$username = wc_create_new_customer_username( $user_email );
// Handle password creation.
$password = wp_generate_password();
$password_generated = true;
// Use WP_Error to handle registration errors.
$errors = new \WP_Error();
/**
* Fires before a customer account is registered.
*
* This hook fires before customer accounts are created and passes the form data (username, email) and an array
* of errors.
*
* This could be used to add extra validation logic and append errors to the array.
*
* @since 7.2.0
*
* @internal Matches filter name in WooCommerce core.
*
* @param string $username Customer username.
* @param string $user_email Customer email address.
* @param \WP_Error $errors Error object.
*/
do_action( 'woocommerce_register_post', $username, $user_email, $errors );
/**
* Filters registration errors before a customer account is registered.
*
* This hook filters registration errors. This can be used to manipulate the array of errors before
* they are displayed.
*
* @since 7.2.0
*
* @internal Matches filter name in WooCommerce core.
*
* @param \WP_Error $errors Error object.
* @param string $username Customer username.
* @param string $user_email Customer email address.
* @return \WP_Error
*/
$errors = apply_filters( 'woocommerce_registration_errors', $errors, $username, $user_email );
if ( is_wp_error( $errors ) && $errors->get_error_code() ) {
throw new \Exception( $errors->get_error_code() );
}
/**
* Filters customer data before a customer account is registered.
*
* This hook filters customer data. It allows user data to be changed, for example, username, password, email,
* first name, last name, and role.
*
* @since 7.2.0
*
* @param array $customer_data An array of customer (user) data.
* @return array
*/
$new_customer_data = apply_filters(
'woocommerce_new_customer_data',
array(
'user_login' => $username,
'user_pass' => $password,
'user_email' => $user_email,
'first_name' => $first_name,
'last_name' => $last_name,
'role' => 'customer',
'source' => 'store-api',
)
);
$customer_id = wp_insert_user( $new_customer_data );
if ( is_wp_error( $customer_id ) ) {
throw $this->map_create_account_error( $customer_id );
}
// Set account flag to remind customer to update generated password.
update_user_option( $customer_id, 'default_password_nag', true, true );
/**
* Fires after a customer account has been registered.
*
* This hook fires after customer accounts are created and passes the customer data.
*
* @since 7.2.0
*
* @internal Matches filter name in WooCommerce core.
*
* @param integer $customer_id New customer (user) ID.
* @param array $new_customer_data Array of customer (user) data.
* @param string $password_generated The generated password for the account.
*/
do_action( 'woocommerce_created_customer', $customer_id, $new_customer_data, $password_generated );
return $customer_id;
}
/**
* Convert an account creation error to an exception.
*
* @param \WP_Error $error An error object.
* @return \Exception.
*/
private function map_create_account_error( \WP_Error $error ) {
switch ( $error->get_error_code() ) {
// WordPress core error codes.
case 'empty_username':
case 'invalid_username':
case 'empty_email':
case 'invalid_email':
case 'email_exists':
case 'registerfail':
return new \Exception( 'woocommerce_rest_checkout_create_account_failure' );
}
return new \Exception( 'woocommerce_rest_checkout_create_account_failure' );
}
}
V1/AI/Patterns.php 0000644 00000005561 15073235735 0007655 0 ustar 00 \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => [ Middleware::class, 'is_authorized' ],
'args' => [
'business_description' => [
'description' => __( 'The business description for a given store.', 'woocommerce' ),
'type' => 'string',
],
'images' => [
'description' => __( 'The images for a given store.', 'woocommerce' ),
'type' => 'object',
],
],
],
[
'methods' => \WP_REST_Server::DELETABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => [ Middleware::class, 'is_authorized' ],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Update patterns with the content and images powered by AI.
*
* @param \WP_REST_Request $request Request object.
*
* @return bool|string|\WP_Error|\WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
$business_description = sanitize_text_field( wp_unslash( $request['business_description'] ) );
$ai_connection = new Connection();
$site_id = $ai_connection->get_site_id();
if ( is_wp_error( $site_id ) ) {
return $this->error_to_response( $site_id );
}
$token = $ai_connection->get_jwt_token( $site_id );
$images = $request['images'];
try {
( new PatternUpdater() )->generate_content( $ai_connection, $token, $images, $business_description );
return rest_ensure_response( array( 'ai_content_generated' => true ) );
} catch ( \WP_Error $e ) {
return $this->error_to_response( $e );
}
}
/**
* Remove patterns generated by AI.
*
* @param \WP_REST_Request $request Request object.
*
* @return bool|string|\WP_Error|\WP_REST_Response
*/
protected function get_route_delete_response( \WP_REST_Request $request ) {
PatternsHelper::delete_patterns_ai_data_post();
return rest_ensure_response( array( 'removed' => true ) );
}
}
V1/AI/Images.php 0000644 00000005265 15073235735 0007263 0 ustar 00 \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => [ Middleware::class, 'is_authorized' ],
'args' => [
'business_description' => [
'description' => __( 'The business description for a given store.', 'woocommerce' ),
'type' => 'string',
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Generate Images from Pexels
*
* @param \WP_REST_Request $request Request object.
*
* @return bool|string|\WP_Error|\WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
$business_description = sanitize_text_field( wp_unslash( $request['business_description'] ) );
if ( empty( $business_description ) ) {
$business_description = get_option( 'woo_ai_describe_store_description' );
}
$last_business_description = get_option( 'last_business_description_with_ai_content_generated' );
if ( $last_business_description === $business_description ) {
return rest_ensure_response(
$this->prepare_item_for_response(
[
'ai_content_generated' => true,
'images' => array(),
],
$request
)
);
}
$ai_connection = new Connection();
$site_id = $ai_connection->get_site_id();
if ( is_wp_error( $site_id ) ) {
return $this->error_to_response( $site_id );
}
$token = $ai_connection->get_jwt_token( $site_id );
if ( is_wp_error( $token ) ) {
return $this->error_to_response( $token );
}
$images = ( new Pexels() )->get_images( $ai_connection, $token, $business_description );
if ( is_wp_error( $images ) ) {
return $this->error_to_response( $images );
}
return rest_ensure_response(
$this->prepare_item_for_response(
[
'ai_content_generated' => true,
'images' => $images,
],
$request
)
);
}
}
V1/AI/Products.php 0000644 00000007401 15073235735 0007653 0 ustar 00 \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => [ Middleware::class, 'is_authorized' ],
'args' => [
'business_description' => [
'description' => __( 'The business description for a given store.', 'woocommerce' ),
'type' => 'string',
],
'images' => [
'description' => __( 'The images for a given store.', 'woocommerce' ),
'type' => 'object',
],
],
],
[
'methods' => \WP_REST_Server::DELETABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => [ Middleware::class, 'is_authorized' ],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Generate the content for the products.
*
* @param \WP_REST_Request $request Request object.
*
* @return bool|string|\WP_Error|\WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
$allow_ai_connection = get_option( 'woocommerce_blocks_allow_ai_connection' );
if ( ! $allow_ai_connection ) {
return rest_ensure_response(
$this->error_to_response(
new \WP_Error(
'ai_connection_not_allowed',
__( 'AI content generation is not allowed on this store. Update your store settings if you wish to enable this feature.', 'woocommerce' )
)
)
);
}
$business_description = sanitize_text_field( wp_unslash( $request['business_description'] ) );
if ( empty( $business_description ) ) {
$business_description = get_option( 'woo_ai_describe_store_description' );
}
$ai_connection = new Connection();
$site_id = $ai_connection->get_site_id();
if ( is_wp_error( $site_id ) ) {
return $this->error_to_response( $site_id );
}
$token = $ai_connection->get_jwt_token( $site_id );
if ( is_wp_error( $token ) ) {
return $this->error_to_response( $token );
}
$images = $request['images'];
$populate_products = ( new ProductUpdater() )->generate_content( $ai_connection, $token, $images, $business_description );
if ( is_wp_error( $populate_products ) ) {
return $this->error_to_response( $populate_products );
}
if ( ! isset( $populate_products['product_content'] ) ) {
return $this->error_to_response( new \WP_Error( 'product_content_not_found', __( 'Product content not found.', 'woocommerce' ) ) );
}
$product_content = $populate_products['product_content'];
$item = array(
'ai_content_generated' => true,
'product_content' => $product_content,
);
return rest_ensure_response( $item );
}
/**
* Remove products generated by AI.
*
* @param \WP_REST_Request $request Request object.
*
* @return bool|string|\WP_Error|\WP_REST_Response
*/
protected function get_route_delete_response( \WP_REST_Request $request ) {
( new ProductUpdater() )->reset_products_content();
return rest_ensure_response( array( 'removed' => true ) );
}
}
V1/AI/BusinessDescription.php 0000644 00000003631 15073235735 0012050 0 ustar 00 \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => [ Middleware::class, 'is_authorized' ],
'args' => [
'business_description' => [
'description' => __( 'The business description for a given store.', 'woocommerce' ),
'type' => 'string',
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Update the last business description.
*
* @param \WP_REST_Request $request Request object.
*
* @return bool|string|\WP_Error|\WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
$business_description = $request->get_param( 'business_description' );
if ( ! $business_description ) {
return $this->error_to_response(
new \WP_Error(
'invalid_business_description',
__( 'Invalid business description.', 'woocommerce' )
)
);
}
update_option( 'last_business_description_with_ai_content_generated', $business_description );
return rest_ensure_response(
array(
'ai_content_generated' => true,
)
);
}
}
V1/AI/Product.php 0000644 00000004266 15073235735 0007476 0 ustar 00 \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => [ Middleware::class, 'is_authorized' ],
'args' => [
'products_information' => [
'description' => __( 'Data generated by AI for updating dummy products.', 'woocommerce' ),
'type' => 'object',
],
'last_product' => [
'description' => __( 'Whether the product being updated is the last one in the loop', 'woocommerce' ),
'type' => 'boolean',
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Update product with the content and image powered by AI.
*
* @param \WP_REST_Request $request Request object.
*
* @return bool|string|\WP_Error|\WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
$product_updater = new ProductUpdater();
$product_information = $request['products_information'] ?? array();
if ( empty( $product_information ) ) {
return rest_ensure_response(
array(
'ai_content_generated' => true,
)
);
}
$product_updater->update_product_content( $product_information );
$last_product_to_update = $request['last_product'] ?? false;
if ( $last_product_to_update ) {
flush_rewrite_rules();
}
return rest_ensure_response(
array(
'ai_content_generated' => true,
)
);
}
}
V1/AI/Middleware.php 0000644 00000002477 15073235735 0010135 0 ustar 00 getErrorCode(),
$error->getMessage(),
array( 'status' => $error->getCode() )
);
}
$allow_ai_connection = get_option( 'woocommerce_blocks_allow_ai_connection' );
if ( ! $allow_ai_connection ) {
try {
throw new RouteException( 'ai_connection_not_allowed', __( 'AI content generation is not allowed on this store. Update your store settings if you wish to enable this feature.', 'woocommerce' ), 403 );
} catch ( RouteException $error ) {
return new \WP_Error(
$error->getErrorCode(),
$error->getMessage(),
array( 'status' => $error->getCode() )
);
}
}
return true;
}
}
V1/AI/StoreTitle.php 0000644 00000007074 15073235735 0010154 0 ustar 00 \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => [ Middleware::class, 'is_authorized' ],
'args' => [
'business_description' => [
'description' => __( 'The business description for a given store.', 'woocommerce' ),
'type' => 'string',
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Update the store title powered by AI.
*
* @param \WP_REST_Request $request Request object.
*
* @return bool|string|\WP_Error|\WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
$business_description = $request->get_param( 'business_description' );
if ( ! $business_description ) {
return $this->error_to_response(
new \WP_Error(
'invalid_business_description',
__( 'Invalid business description.', 'woocommerce' )
)
);
}
$store_title = get_option( 'blogname' );
if ( ! ( empty( $store_title ) || self::DEFAULT_TITLE === $store_title ) ) {
return rest_ensure_response( array( 'ai_content_generated' => false ) );
}
$ai_generated_title = $this->generate_ai_title( $business_description );
if ( is_wp_error( $ai_generated_title ) ) {
return $this->error_to_response( $ai_generated_title );
}
update_option( self::STORE_TITLE_OPTION_NAME, $ai_generated_title );
return rest_ensure_response(
array(
'ai_content_generated' => true,
)
);
}
/**
* Generate the store title powered by AI.
*
* @param string $business_description The business description for a given store.
*
* @return string|\WP_Error|\WP_REST_Response The store title generated by AI.
*/
private function generate_ai_title( $business_description ) {
$ai_connection = new Connection();
$site_id = $ai_connection->get_site_id();
if ( is_wp_error( $site_id ) ) {
return $this->error_to_response( $site_id );
}
$token = $ai_connection->get_jwt_token( $site_id );
if ( is_wp_error( $token ) ) {
return $this->error_to_response( $token );
}
$prompt = "Generate a store title for a store that has the following: '$business_description'. The length of the title should be 1 and 3 words. The result should include only the store title without any other explanation, number or punctuation marks";
$ai_response = $ai_connection->fetch_ai_response( $token, $prompt );
if ( is_wp_error( $ai_response ) ) {
return $this->error_to_response( $ai_response );
}
if ( ! isset( $ai_response['completion'] ) ) {
return '';
}
return $ai_response['completion'];
}
}
V1/AI/StoreInfo.php 0000644 00000003322 15073235735 0007756 0 ustar 00 \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => [ Middleware::class, 'is_authorized' ],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Update the store title powered by AI.
*
* @param \WP_REST_Request $request Request object.
*
* @return bool|string|\WP_Error|\WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
$product_updater = new ProductUpdater();
$patterns = PatternsHelper::get_patterns_ai_data_post();
$products = $product_updater->fetch_product_ids( 'dummy' );
if ( empty( $products ) && ! isset( $patterns ) ) {
return rest_ensure_response(
array(
'is_ai_generated' => false,
)
);
}
return rest_ensure_response(
array(
'is_ai_generated' => true,
)
);
}
}
V1/ProductsBySlug.php 0000644 00000005021 15073235735 0010504 0 ustar 00 [\S]+)';
}
/**
* Get method arguments for this REST route.
*
* @return array An array of endpoints.
*/
public function get_args() {
return [
'args' => array(
'slug' => array(
'description' => __( 'Slug of the resource.', 'woocommerce' ),
'type' => 'string',
),
),
[
'methods' => \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => array(
'context' => $this->get_context_param(
array(
'default' => 'view',
)
),
),
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
];
}
/**
* Get a single item.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
$slug = sanitize_title( $request['slug'] );
$object = $this->get_product_by_slug( $slug );
if ( ! $object ) {
$object = $this->get_product_variation_by_slug( $slug );
}
if ( ! $object || 0 === $object->get_id() ) {
throw new RouteException( 'woocommerce_rest_product_invalid_slug', __( 'Invalid product slug.', 'woocommerce' ), 404 );
}
return rest_ensure_response( $this->schema->get_item_response( $object ) );
}
/**
* Get a product by slug.
*
* @param string $slug The slug of the product.
*/
public function get_product_by_slug( $slug ) {
return wc_get_product( get_page_by_path( $slug, OBJECT, 'product' ) );
}
/**
* Get a product variation by slug.
*
* @param string $slug The slug of the product variation.
*/
private function get_product_variation_by_slug( $slug ) {
global $wpdb;
$result = $wpdb->get_results(
$wpdb->prepare(
"SELECT ID, post_name, post_parent, post_type
FROM $wpdb->posts
WHERE post_name = %s
AND post_type = 'product_variation'",
$slug
)
);
if ( ! $result ) {
return null;
}
return wc_get_product( $result[0]->ID );
}
}
V1/CartCoupons.php 0000644 00000007430 15073235735 0010021 0 ustar 00 \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => [
'context' => $this->get_context_param( [ 'default' => 'view' ] ),
],
],
[
'methods' => \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => $this->schema->get_endpoint_args_for_item_schema( \WP_REST_Server::CREATABLE ),
],
[
'methods' => \WP_REST_Server::DELETABLE,
'permission_callback' => '__return_true',
'callback' => [ $this, 'get_response' ],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Get a collection of cart coupons.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
$cart_coupons = $this->cart_controller->get_cart_coupons();
$items = [];
foreach ( $cart_coupons as $coupon_code ) {
$response = rest_ensure_response( $this->schema->get_item_response( $coupon_code ) );
$response->add_links( $this->prepare_links( $coupon_code, $request ) );
$response = $this->prepare_response_for_collection( $response );
$items[] = $response;
}
$response = rest_ensure_response( $items );
return $response;
}
/**
* Add a coupon to the cart and return the result.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
if ( ! wc_coupons_enabled() ) {
throw new RouteException( 'woocommerce_rest_cart_coupon_disabled', __( 'Coupons are disabled.', 'woocommerce' ), 404 );
}
try {
$this->cart_controller->apply_coupon( $request['code'] );
} catch ( \WC_REST_Exception $e ) {
throw new RouteException( $e->getErrorCode(), $e->getMessage(), $e->getCode() );
}
$response = $this->prepare_item_for_response( $request['code'], $request );
$response->set_status( 201 );
return $response;
}
/**
* Deletes all coupons in the cart.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_delete_response( \WP_REST_Request $request ) {
$cart = $this->cart_controller->get_cart_instance();
$cart->remove_coupons();
$cart->calculate_totals();
return new \WP_REST_Response( [], 200 );
}
/**
* Prepare links for the request.
*
* @param string $coupon_code Coupon code.
* @param \WP_REST_Request $request Request object.
* @return array
*/
protected function prepare_links( $coupon_code, $request ) {
$base = $this->get_namespace() . $this->get_path();
$links = array(
'self' => array(
'href' => rest_url( trailingslashit( $base ) . $coupon_code ),
),
'collection' => array(
'href' => rest_url( $base ),
),
);
return $links;
}
}
V1/CartUpdateCustomer.php 0000644 00000026415 15073235735 0011343 0 ustar 00 \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => [
'billing_address' => [
'description' => __( 'Billing address.', 'woocommerce' ),
'type' => 'object',
'context' => [ 'view', 'edit' ],
'properties' => $this->schema->billing_address_schema->get_properties(),
'sanitize_callback' => null,
],
'shipping_address' => [
'description' => __( 'Shipping address.', 'woocommerce' ),
'type' => 'object',
'context' => [ 'view', 'edit' ],
'properties' => $this->schema->shipping_address_schema->get_properties(),
'sanitize_callback' => null,
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Validate address params now they are populated.
*
* @param \WP_REST_Request $request Request object.
* @param array $billing Billing address.
* @param array $shipping Shipping address.
* @return \WP_Error|true
*/
protected function validate_address_params( $request, $billing, $shipping ) {
$posted_billing = isset( $request['billing_address'] );
$posted_shipping = isset( $request['shipping_address'] );
$invalid_params = array();
$invalid_details = array();
if ( $posted_billing ) {
$billing_validation_check = $this->schema->billing_address_schema->validate_callback( $billing, $request, 'billing_address' );
if ( false === $billing_validation_check ) {
$invalid_params['billing_address'] = __( 'Invalid parameter.', 'woocommerce' );
} elseif ( is_wp_error( $billing_validation_check ) ) {
$invalid_params['billing_address'] = implode( ' ', $billing_validation_check->get_error_messages() );
$invalid_details['billing_address'] = \rest_convert_error_to_response( $billing_validation_check )->get_data();
}
}
if ( $posted_shipping ) {
$shipping_validation_check = $this->schema->shipping_address_schema->validate_callback( $shipping, $request, 'shipping_address' );
if ( false === $shipping_validation_check ) {
$invalid_params['shipping_address'] = __( 'Invalid parameter.', 'woocommerce' );
} elseif ( is_wp_error( $shipping_validation_check ) ) {
$invalid_params['shipping_address'] = implode( ' ', $shipping_validation_check->get_error_messages() );
$invalid_details['shipping_address'] = \rest_convert_error_to_response( $shipping_validation_check )->get_data();
}
}
if ( $invalid_params ) {
return new \WP_Error(
'rest_invalid_param',
/* translators: %s: List of invalid parameters. */
sprintf( __( 'Invalid parameter(s): %s', 'woocommerce' ), implode( ', ', array_keys( $invalid_params ) ) ),
[
'status' => 400,
'params' => $invalid_params,
'details' => $invalid_details,
]
);
}
return true;
}
/**
* Handle the request and return a valid response for this endpoint.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
$cart = $this->cart_controller->get_cart_instance();
$customer = wc()->customer;
// Get data from request object and merge with customer object, then sanitize.
$billing = $this->schema->billing_address_schema->sanitize_callback(
wp_parse_args(
$request['billing_address'] ?? [],
$this->get_customer_billing_address( $customer )
),
$request,
'billing_address'
);
$shipping = $this->schema->billing_address_schema->sanitize_callback(
wp_parse_args(
$request['shipping_address'] ?? [],
$this->get_customer_shipping_address( $customer )
),
$request,
'shipping_address'
);
// If the cart does not need shipping, shipping address is forced to match billing address unless defined.
if ( ! $cart->needs_shipping() && ! isset( $request['shipping_address'] ) ) {
$shipping = $billing;
}
// Run validation and sanitization now that the cart and customer data is loaded.
$billing = $this->schema->billing_address_schema->sanitize_callback( $billing, $request, 'billing_address' );
$shipping = $this->schema->shipping_address_schema->sanitize_callback( $shipping, $request, 'shipping_address' );
// Validate data now everything is clean..
$validation_check = $this->validate_address_params( $request, $billing, $shipping );
if ( is_wp_error( $validation_check ) ) {
return rest_ensure_response( $validation_check );
}
$customer->set_props(
array(
'billing_first_name' => $billing['first_name'] ?? null,
'billing_last_name' => $billing['last_name'] ?? null,
'billing_company' => $billing['company'] ?? null,
'billing_address_1' => $billing['address_1'] ?? null,
'billing_address_2' => $billing['address_2'] ?? null,
'billing_city' => $billing['city'] ?? null,
'billing_state' => $billing['state'] ?? null,
'billing_postcode' => $billing['postcode'] ?? null,
'billing_country' => $billing['country'] ?? null,
'billing_phone' => $billing['phone'] ?? null,
'billing_email' => $billing['email'] ?? null,
'shipping_first_name' => $shipping['first_name'] ?? null,
'shipping_last_name' => $shipping['last_name'] ?? null,
'shipping_company' => $shipping['company'] ?? null,
'shipping_address_1' => $shipping['address_1'] ?? null,
'shipping_address_2' => $shipping['address_2'] ?? null,
'shipping_city' => $shipping['city'] ?? null,
'shipping_state' => $shipping['state'] ?? null,
'shipping_postcode' => $shipping['postcode'] ?? null,
'shipping_country' => $shipping['country'] ?? null,
'shipping_phone' => $shipping['phone'] ?? null,
)
);
// We want to only get additional fields passed, since core ones are already saved.
$core_fields = array_keys( $this->additional_fields_controller->get_core_fields() );
$additional_shipping_values = array_diff_key( $shipping, array_flip( $core_fields ) );
$additional_billing_values = array_diff_key( $billing, array_flip( $core_fields ) );
// We save them one by one, and we add the group prefix.
foreach ( $additional_shipping_values as $key => $value ) {
$this->additional_fields_controller->persist_field_for_customer( "/shipping/{$key}", $value, $customer );
}
foreach ( $additional_billing_values as $key => $value ) {
$this->additional_fields_controller->persist_field_for_customer( "/billing/{$key}", $value, $customer );
}
wc_do_deprecated_action(
'woocommerce_blocks_cart_update_customer_from_request',
array(
$customer,
$request,
),
'7.2.0',
'woocommerce_store_api_cart_update_customer_from_request',
'This action was deprecated in WooCommerce Blocks version 7.2.0. Please use woocommerce_store_api_cart_update_customer_from_request instead.'
);
/**
* Fires when the Checkout Block/Store API updates a customer from the API request data.
*
* @since 7.2.0
*
* @param \WC_Customer $customer Customer object.
* @param \WP_REST_Request $request Full details about the request.
*/
do_action( 'woocommerce_store_api_cart_update_customer_from_request', $customer, $request );
$customer->save();
$this->cart_controller->calculate_totals();
return rest_ensure_response( $this->schema->get_item_response( $cart ) );
}
/**
* Get full customer billing address.
*
* @param \WC_Customer $customer Customer object.
* @return array
*/
protected function get_customer_billing_address( \WC_Customer $customer ) {
$validation_util = new ValidationUtils();
$billing_country = $customer->get_billing_country();
$billing_state = $customer->get_billing_state();
$additional_fields = $this->additional_fields_controller->get_all_fields_from_customer( $customer );
$additional_fields = array_reduce(
array_keys( $additional_fields ),
function( $carry, $key ) use ( $additional_fields ) {
if ( 0 === strpos( $key, '/billing/' ) ) {
$value = $additional_fields[ $key ];
$key = str_replace( '/billing/', '', $key );
$carry[ $key ] = $value;
}
return $carry;
},
array()
);
/**
* There's a bug in WooCommerce core in which not having a state ("") would result in us validating against the store's state.
* This resets the state to an empty string if it doesn't match the country.
*
* @todo Removing this handling once we fix the issue with the state value always being the store one.
*/
if ( ! $validation_util->validate_state( $billing_state, $billing_country ) ) {
$billing_state = '';
}
return array_merge(
[
'first_name' => $customer->get_billing_first_name(),
'last_name' => $customer->get_billing_last_name(),
'company' => $customer->get_billing_company(),
'address_1' => $customer->get_billing_address_1(),
'address_2' => $customer->get_billing_address_2(),
'city' => $customer->get_billing_city(),
'state' => $billing_state,
'postcode' => $customer->get_billing_postcode(),
'country' => $billing_country,
'phone' => $customer->get_billing_phone(),
'email' => $customer->get_billing_email(),
],
$additional_fields
);
}
/**
* Get full customer shipping address.
*
* @param \WC_Customer $customer Customer object.
* @return array
*/
protected function get_customer_shipping_address( \WC_Customer $customer ) {
$additional_fields = $this->additional_fields_controller->get_all_fields_from_customer( $customer );
$additional_fields = array_reduce(
array_keys( $additional_fields ),
function( $carry, $key ) use ( $additional_fields ) {
if ( 0 === strpos( $key, '/shipping/' ) ) {
$value = $additional_fields[ $key ];
$key = str_replace( '/shipping/', '', $key );
$carry[ $key ] = $value;
}
return $carry;
},
array()
);
return array_merge(
[
'first_name' => $customer->get_shipping_first_name(),
'last_name' => $customer->get_shipping_last_name(),
'company' => $customer->get_shipping_company(),
'address_1' => $customer->get_shipping_address_1(),
'address_2' => $customer->get_shipping_address_2(),
'city' => $customer->get_shipping_city(),
'state' => $customer->get_shipping_state(),
'postcode' => $customer->get_shipping_postcode(),
'country' => $customer->get_shipping_country(),
'phone' => $customer->get_shipping_phone(),
],
$additional_fields
);
}
}
V1/AbstractTermsRoute.php 0000644 00000011306 15073235735 0011353 0 ustar 00 get_context_param();
$params['context']['default'] = 'view';
$params['page'] = array(
'description' => __( 'Current page of the collection.', 'woocommerce' ),
'type' => 'integer',
'default' => 1,
'sanitize_callback' => 'absint',
'validate_callback' => 'rest_validate_request_arg',
'minimum' => 1,
);
$params['per_page'] = array(
'description' => __( 'Maximum number of items to be returned in result set. Defaults to no limit if left blank.', 'woocommerce' ),
'type' => 'integer',
'minimum' => 0,
'maximum' => 100,
'sanitize_callback' => 'absint',
'validate_callback' => 'rest_validate_request_arg',
);
$params['search'] = array(
'description' => __( 'Limit results to those matching a string.', 'woocommerce' ),
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'validate_callback' => 'rest_validate_request_arg',
);
$params['exclude'] = array(
'description' => __( 'Ensure result set excludes specific IDs.', 'woocommerce' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',
);
$params['include'] = array(
'description' => __( 'Limit result set to specific ids.', 'woocommerce' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',
);
$params['order'] = array(
'description' => __( 'Sort ascending or descending.', 'woocommerce' ),
'type' => 'string',
'default' => 'asc',
'enum' => array( 'asc', 'desc' ),
'validate_callback' => 'rest_validate_request_arg',
);
$params['orderby'] = array(
'description' => __( 'Sort by term property.', 'woocommerce' ),
'type' => 'string',
'default' => 'name',
'enum' => array(
'name',
'slug',
'count',
),
'validate_callback' => 'rest_validate_request_arg',
);
$params['hide_empty'] = array(
'description' => __( 'If true, empty terms will not be returned.', 'woocommerce' ),
'type' => 'boolean',
'default' => true,
);
return $params;
}
/**
* Get terms matching passed in args.
*
* @param string $taxonomy Taxonomy to get terms from.
* @param \WP_REST_Request $request Request object.
*
* @return \WP_REST_Response
*/
protected function get_terms_response( $taxonomy, $request ) {
$page = (int) $request['page'];
$per_page = $request['per_page'] ? (int) $request['per_page'] : 0;
$prepared_args = array(
'taxonomy' => $taxonomy,
'exclude' => $request['exclude'],
'include' => $request['include'],
'order' => $request['order'],
'orderby' => $request['orderby'],
'hide_empty' => (bool) $request['hide_empty'],
'number' => $per_page,
'offset' => $per_page > 0 ? ( $page - 1 ) * $per_page : 0,
'search' => $request['search'],
);
$term_query = new WP_Term_Query();
$objects = $term_query->query( $prepared_args );
$return = [];
foreach ( $objects as $object ) {
$data = $this->prepare_item_for_response( $object, $request );
$return[] = $this->prepare_response_for_collection( $data );
}
$response = rest_ensure_response( $return );
// See if pagination is needed before calculating.
if ( $per_page > 0 && ( count( $objects ) === $per_page || $page > 1 ) ) {
$term_count = $this->get_term_count( $taxonomy, $prepared_args );
$response = ( new Pagination() )->add_headers( $response, $request, $term_count, ceil( $term_count / $per_page ) );
}
return $response;
}
/**
* Get count of terms for current query.
*
* @param string $taxonomy Taxonomy to get terms from.
* @param array $args Array of args to pass to wp_count_terms.
* @return int
*/
protected function get_term_count( $taxonomy, $args ) {
$count_args = $args;
unset( $count_args['number'], $count_args['offset'] );
return (int) wp_count_terms( $taxonomy, $count_args );
}
}
V1/CartExtensions.php 0000644 00000003437 15073235735 0010535 0 ustar 00 \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => [
'namespace' => [
'description' => __( 'Extension\'s name - this will be used to ensure the data in the request is routed appropriately.', 'woocommerce' ),
'type' => 'string',
],
'data' => [
'description' => __( 'Additional data to pass to the extension', 'woocommerce' ),
'type' => 'object',
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Handle the request and return a valid response for this endpoint.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
try {
return $this->schema->get_item_response( $request );
} catch ( \WC_REST_Exception $e ) {
throw new RouteException( $e->getErrorCode(), $e->getMessage(), $e->getCode() );
}
}
}
V1/Order.php 0000644 00000004135 15073235735 0006633 0 ustar 00 order_controller = new OrderController();
}
/**
* Get the path of this REST route.
*
* @return string
*/
public function get_path() {
return '/order/(?P[\d]+)';
}
/**
* Get method arguments for this REST route.
*
* @return array An array of endpoints.
*/
public function get_args() {
return [
[
'methods' => \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => [ $this, 'is_authorized' ],
'args' => [
'context' => $this->get_context_param( [ 'default' => 'view' ] ),
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
];
}
/**
* Handle the request and return a valid response for this endpoint.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
$order_id = absint( $request['id'] );
return rest_ensure_response( $this->schema->get_item_response( wc_get_order( $order_id ) ) );
}
}
V1/ProductAttributeTerms.php 0000644 00000003636 15073235735 0012104 0 ustar 00 [\d]+)/terms';
}
/**
* Get method arguments for this REST route.
*
* @return array An array of endpoints.
*/
public function get_args() {
return [
'args' => array(
'attribute_id' => array(
'description' => __( 'Unique identifier for the attribute.', 'woocommerce' ),
'type' => 'integer',
),
),
[
'methods' => \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => $this->get_collection_params(),
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
];
}
/**
* Get the query params for collections of attributes.
*
* @return array
*/
public function get_collection_params() {
$params = parent::get_collection_params();
$params['orderby']['enum'][] = 'menu_order';
return $params;
}
/**
* Get a collection of attribute terms.
*
* @throws RouteException On error.
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
$attribute = wc_get_attribute( $request['attribute_id'] );
if ( ! $attribute || ! taxonomy_exists( $attribute->slug ) ) {
throw new RouteException( 'woocommerce_rest_taxonomy_invalid', __( 'Attribute does not exist.', 'woocommerce' ), 404 );
}
return $this->get_terms_response( $attribute->slug, $request );
}
}
V1/ProductCategories.php 0000644 00000002243 15073235735 0011204 0 ustar 00 \WP_REST_Server::READABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => '__return_true',
'args' => $this->get_collection_params(),
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
];
}
/**
* Get a collection of terms.
*
* @param \WP_REST_Request $request Request object.
* @return \WP_REST_Response
*/
protected function get_route_response( \WP_REST_Request $request ) {
return $this->get_terms_response( 'product_cat', $request );
}
}