Completed
Push — master ( 7f2ea5...5630d2 )
by Mike
09:46
created

Products   B

Complexity

Total Complexity 52

Size/Duplication

Total Lines 596
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 276
dl 0
loc 596
rs 7.44
c 0
b 0
f 0
wmc 52

11 Methods

Rating   Name   Duplication   Size   Complexity  
F prepare_objects_query() 0 121 20
B get_items_query_clauses() 0 42 9
A append_product_sorting_table_join() 0 7 2
C delete_item() 0 119 11
A prepare_links() 0 17 2
A prepare_object_for_response() 0 19 2
A prepare_object_for_database() 0 14 1
A get_items() 0 5 1
B get_collection_params() 0 130 2
A get_object() 0 2 1
A get_item_schema() 0 2 1

How to fix   Complexity   

Complex Class

Complex classes like Products often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Products, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * REST API Products controller
4
 *
5
 * Handles requests to the /products endpoint.
6
 *
7
 * @package WooCommerce/RestApi
8
 */
9
10
namespace WooCommerce\RestApi\Controllers\Version4;
11
12
defined( 'ABSPATH' ) || exit;
13
14
use WooCommerce\RestApi\Controllers\Version4\Schema\ProductSchema;
15
16
/**
17
 * REST API Products controller class.
18
 */
19
class Products extends AbstractObjectsController {
20
21
	/**
22
	 * Route base.
23
	 *
24
	 * @var string
25
	 */
26
	protected $rest_base = 'products';
27
28
	/**
29
	 * Post type.
30
	 *
31
	 * @var string
32
	 */
33
	protected $post_type = 'product';
34
35
	/**
36
	 * If object is hierarchical.
37
	 *
38
	 * @var bool
39
	 */
40
	protected $hierarchical = true;
41
42
	/**
43
	 * Get the Product's schema, conforming to JSON Schema.
44
	 *
45
	 * @return array
46
	 */
47
	public function get_item_schema() {
48
		return $this->add_additional_fields_schema( ProductSchema::get_schema() );
49
	}
50
51
	/**
52
	 * Get the query params for collections of attachments.
53
	 *
54
	 * @return array
55
	 */
56
	public function get_collection_params() {
57
		$params = parent::get_collection_params();
58
59
		$params['slug'] = array(
60
			'description'       => __( 'Limit result set to products with a specific slug.', 'woocommerce' ),
61
			'type'              => 'string',
62
			'validate_callback' => 'rest_validate_request_arg',
63
		);
64
65
		$params['status'] = array(
66
			'default'           => 'any',
67
			'description'       => __( 'Limit result set to products assigned a specific status.', 'woocommerce' ),
68
			'type'              => 'string',
69
			'enum'              => array_merge( array( 'any', 'future' ), array_keys( get_post_statuses() ) ),
70
			'sanitize_callback' => 'sanitize_key',
71
			'validate_callback' => 'rest_validate_request_arg',
72
		);
73
74
		$params['type'] = array(
75
			'description'       => __( 'Limit result set to products assigned a specific type.', 'woocommerce' ),
76
			'type'              => 'string',
77
			'enum'              => array_keys( wc_get_product_types() ),
78
			'sanitize_callback' => 'sanitize_key',
79
			'validate_callback' => 'rest_validate_request_arg',
80
		);
81
82
		$params['sku'] = array(
83
			'description'       => __( 'Limit result set to products with specific SKU(s). Use commas to separate.', 'woocommerce' ),
84
			'type'              => 'string',
85
			'sanitize_callback' => 'sanitize_text_field',
86
			'validate_callback' => 'rest_validate_request_arg',
87
		);
88
89
		$params['featured'] = array(
90
			'description'       => __( 'Limit result set to featured products.', 'woocommerce' ),
91
			'type'              => 'boolean',
92
			'sanitize_callback' => 'wc_string_to_bool',
93
			'validate_callback' => 'rest_validate_request_arg',
94
		);
95
96
		$params['category'] = array(
97
			'description'       => __( 'Limit result set to products assigned a specific category ID.', 'woocommerce' ),
98
			'type'              => 'string',
99
			'sanitize_callback' => 'wp_parse_id_list',
100
			'validate_callback' => 'rest_validate_request_arg',
101
		);
102
103
		$params['tag'] = array(
104
			'description'       => __( 'Limit result set to products assigned a specific tag ID.', 'woocommerce' ),
105
			'type'              => 'string',
106
			'sanitize_callback' => 'wp_parse_id_list',
107
			'validate_callback' => 'rest_validate_request_arg',
108
		);
109
110
		$params['shipping_class'] = array(
111
			'description'       => __( 'Limit result set to products assigned a specific shipping class ID.', 'woocommerce' ),
112
			'type'              => 'string',
113
			'sanitize_callback' => 'wp_parse_id_list',
114
			'validate_callback' => 'rest_validate_request_arg',
115
		);
116
117
		$params['attribute'] = array(
118
			'description'       => __( 'Limit result set to products with a specific attribute. Use the taxonomy name/attribute slug.', 'woocommerce' ),
119
			'type'              => 'string',
120
			'sanitize_callback' => 'sanitize_text_field',
121
			'validate_callback' => 'rest_validate_request_arg',
122
		);
123
124
		$params['attribute_term'] = array(
125
			'description'       => __( 'Limit result set to products with a specific attribute term ID (required an assigned attribute).', 'woocommerce' ),
126
			'type'              => 'string',
127
			'sanitize_callback' => 'wp_parse_id_list',
128
			'validate_callback' => 'rest_validate_request_arg',
129
		);
130
131
		if ( wc_tax_enabled() ) {
132
			$params['tax_class'] = array(
133
				'description'       => __( 'Limit result set to products with a specific tax class.', 'woocommerce' ),
134
				'type'              => 'string',
135
				'enum'              => array_merge( array( 'standard' ), \WC_Tax::get_tax_class_slugs() ),
136
				'sanitize_callback' => 'sanitize_text_field',
137
				'validate_callback' => 'rest_validate_request_arg',
138
			);
139
		}
140
141
		$params['on_sale'] = array(
142
			'description'       => __( 'Limit result set to products on sale.', 'woocommerce' ),
143
			'type'              => 'boolean',
144
			'sanitize_callback' => 'wc_string_to_bool',
145
			'validate_callback' => 'rest_validate_request_arg',
146
		);
147
148
		$params['min_price'] = array(
149
			'description'       => __( 'Limit result set to products based on a minimum price.', 'woocommerce' ),
150
			'type'              => 'string',
151
			'sanitize_callback' => 'sanitize_text_field',
152
			'validate_callback' => 'rest_validate_request_arg',
153
		);
154
155
		$params['max_price'] = array(
156
			'description'       => __( 'Limit result set to products based on a maximum price.', 'woocommerce' ),
157
			'type'              => 'string',
158
			'sanitize_callback' => 'sanitize_text_field',
159
			'validate_callback' => 'rest_validate_request_arg',
160
		);
161
162
		$params['stock_status'] = array(
163
			'description'       => __( 'Limit result set to products with specified stock status.', 'woocommerce' ),
164
			'type'              => 'string',
165
			'enum'              => array_keys( wc_get_product_stock_status_options() ),
166
			'sanitize_callback' => 'sanitize_text_field',
167
			'validate_callback' => 'rest_validate_request_arg',
168
		);
169
170
		$params['low_in_stock'] = array(
171
			'description'       => __( 'Limit result set to products that are low or out of stock.', 'woocommerce' ),
172
			'type'              => 'boolean',
173
			'default'           => false,
174
			'sanitize_callback' => 'wc_string_to_bool',
175
		);
176
177
		$params['search'] = array(
178
			'description'       => __( 'Search by similar product name or sku.', 'woocommerce' ),
179
			'type'              => 'string',
180
			'validate_callback' => 'rest_validate_request_arg',
181
		);
182
183
		$params['orderby']['enum'] = array_merge( $params['orderby']['enum'], array( 'price', 'popularity', 'rating' ) );
184
185
		return $params;
186
	}
187
188
	/**
189
	 * Get object.
190
	 *
191
	 * @param int $id Object ID.
192
	 *
193
	 * @since  3.0.0
194
	 * @return \WC_Data|bool
195
	 */
196
	protected function get_object( $id ) {
197
		return wc_get_product( $id );
198
	}
199
200
	/**
201
	 * Prepare a single product output for response.
202
	 *
203
	 * @param \WC_Data         $object  Object data.
204
	 * @param \WP_REST_Request $request Request object.
205
	 *
206
	 * @since  3.0.0
207
	 * @return \WP_REST_Response
208
	 */
209
	public function prepare_object_for_response( $object, $request ) {
210
		$context  = ! empty( $request['context'] ) ? $request['context'] : 'view';
211
		$data     = ProductSchema::object_to_schema( $object, $context );
212
		$data     = $this->add_additional_fields_to_object( $data, $request );
213
		$data     = $this->filter_response_by_context( $data, $context );
214
		$response = rest_ensure_response( $data );
215
		$response->add_links( $this->prepare_links( $object, $request ) );
216
217
		/**
218
		 * Filter the data for a response.
219
		 *
220
		 * The dynamic portion of the hook name, $this->post_type,
221
		 * refers to object type being prepared for the response.
222
		 *
223
		 * @param \WP_REST_Response $response The response object.
224
		 * @param \WC_Data          $object   Object data.
225
		 * @param \WP_REST_Request  $request  Request object.
226
		 */
227
		return apply_filters( "woocommerce_rest_prepare_{$this->post_type}_object", $response, $object, $request );
228
	}
229
230
	/**
231
	 * Prepare a single product for create or update.
232
	 *
233
	 * @param  \WP_REST_Request $request Request object.
234
	 * @param  bool             $creating If is creating a new object.
235
	 * @return \WP_Error|\WC_Data
236
	 */
237
	protected function prepare_object_for_database( $request, $creating = false ) {
238
		$product = ProductSchema::schema_to_object( $request );
239
240
		/**
241
		 * Filters an object before it is inserted via the REST API.
242
		 *
243
		 * The dynamic portion of the hook name, `$this->post_type`,
244
		 * refers to the object type slug.
245
		 *
246
		 * @param \WC_Data         $product  Object object.
247
		 * @param \WP_REST_Request $request  Request object.
248
		 * @param bool            $creating If is creating a new object.
249
		 */
250
		return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}_object", $product, $request, $creating );
251
	}
252
253
	/**
254
	 * Get a collection of posts and add the post title filter option to \WP_Query.
255
	 *
256
	 * @param \WP_REST_Request $request Full details about the request.
257
	 * @return \WP_Error|\WP_REST_Response
258
	 */
259
	public function get_items( $request ) {
260
		add_filter( 'posts_clauses', array( $this, 'get_items_query_clauses' ), 10, 2 );
261
		$response = parent::get_items( $request );
262
		remove_filter( 'posts_clauses', array( $this, 'get_items_query_clauses' ), 10 );
263
		return $response;
264
	}
265
266
	/**
267
	 * Add in conditional search filters for products.
268
	 *
269
	 * @param array     $args Query args.
270
	 * @param \WC_Query $wp_query WC_Query object.
271
	 * @return array
272
	 */
273
	public function get_items_query_clauses( $args, $wp_query ) {
274
		global $wpdb;
275
276
		if ( $wp_query->get( 'search' ) ) {
0 ignored issues
show
Bug introduced by
The method get() does not exist on WC_Query. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

276
		if ( $wp_query->/** @scrutinizer ignore-call */ get( 'search' ) ) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
277
			$search         = "'%" . $wpdb->esc_like( $wp_query->get( 'search' ) ) . "%'";
278
			$args['join']   = $this->append_product_sorting_table_join( $args['join'] );
279
			$args['where'] .= " AND ({$wpdb->posts}.post_title LIKE {$search}";
280
			$args['where'] .= wc_product_sku_enabled() ? ' OR wc_product_meta_lookup.sku LIKE ' . $search . ')' : ')';
281
		}
282
283
		if ( $wp_query->get( 'sku' ) ) {
284
			$skus = explode( ',', $wp_query->get( 'sku' ) );
285
			// Include the current string as a SKU too.
286
			if ( 1 < count( $skus ) ) {
287
				$skus[] = $wp_query->get( 'sku' );
288
			}
289
			$args['join']   = $this->append_product_sorting_table_join( $args['join'] );
290
			$args['where'] .= ' AND wc_product_meta_lookup.sku IN ("' . implode( '","', array_map( 'esc_sql', $skus ) ) . '")';
291
		}
292
293
		if ( $wp_query->get( 'min_price' ) ) {
294
			$args['join']   = $this->append_product_sorting_table_join( $args['join'] );
295
			$args['where'] .= $wpdb->prepare( ' AND wc_product_meta_lookup.min_price >= %f ', floatval( $wp_query->get( 'min_price' ) ) );
296
		}
297
298
		if ( $wp_query->get( 'max_price' ) ) {
299
			$args['join']   = $this->append_product_sorting_table_join( $args['join'] );
300
			$args['where'] .= $wpdb->prepare( ' AND wc_product_meta_lookup.max_price <= %f ', floatval( $wp_query->get( 'max_price' ) ) );
301
		}
302
303
		if ( $wp_query->get( 'stock_status' ) ) {
304
			$args['join']   = $this->append_product_sorting_table_join( $args['join'] );
305
			$args['where'] .= $wpdb->prepare( ' AND wc_product_meta_lookup.stock_status = %s ', $wp_query->get( 'stock_status' ) );
306
		}
307
308
		if ( $wp_query->get( 'low_in_stock' ) ) {
309
			$low_stock      = absint( max( get_option( 'woocommerce_notify_low_stock_amount' ), 1 ) );
310
			$args['join']   = $this->append_product_sorting_table_join( $args['join'] );
311
			$args['where'] .= $wpdb->prepare( ' AND wc_product_meta_lookup.stock_quantity <= %d', $low_stock );
312
		}
313
314
		return $args;
315
	}
316
317
	/**
318
	 * Join wc_product_meta_lookup to posts if not already joined.
319
	 *
320
	 * @param string $sql SQL join.
321
	 * @return string
322
	 */
323
	protected function append_product_sorting_table_join( $sql ) {
324
		global $wpdb;
325
326
		if ( ! strstr( $sql, 'wc_product_meta_lookup' ) ) {
327
			$sql .= " LEFT JOIN {$wpdb->wc_product_meta_lookup} wc_product_meta_lookup ON $wpdb->posts.ID = wc_product_meta_lookup.product_id ";
328
		}
329
		return $sql;
330
	}
331
332
	/**
333
	 * Make extra product orderby features supported by WooCommerce available to the WC API.
334
	 * This includes 'price', 'popularity', and 'rating'.
335
	 *
336
	 * @param \WP_REST_Request $request Request data.
337
	 * @return array
338
	 */
339
	protected function prepare_objects_query( $request ) {
340
		$args = parent::prepare_objects_query( $request );
341
342
		// Set post_status.
343
		$args['post_status'] = $request['status'];
344
345
		// Set custom args to handle later during clauses.
346
		$custom_keys = array(
347
			'sku',
348
			'min_price',
349
			'max_price',
350
			'stock_status',
351
			'low_in_stock',
352
		);
353
		foreach ( $custom_keys as $key ) {
354
			if ( ! empty( $request[ $key ] ) ) {
355
				$args[ $key ] = $request[ $key ];
356
			}
357
		}
358
359
		// Taxonomy query to filter products by type, category,
360
		// tag, shipping class, and attribute.
361
		$tax_query = array();
362
363
		// Map between taxonomy name and arg's key.
364
		$taxonomies = array(
365
			'product_cat'            => 'category',
366
			'product_tag'            => 'tag',
367
			'product_shipping_class' => 'shipping_class',
368
		);
369
370
		// Set tax_query for each passed arg.
371
		foreach ( $taxonomies as $taxonomy => $key ) {
372
			if ( ! empty( $request[ $key ] ) ) {
373
				$tax_query[] = array(
374
					'taxonomy' => $taxonomy,
375
					'field'    => 'term_id',
376
					'terms'    => $request[ $key ],
377
				);
378
			}
379
		}
380
381
		// Filter product type by slug.
382
		if ( ! empty( $request['type'] ) ) {
383
			$tax_query[] = array(
384
				'taxonomy' => 'product_type',
385
				'field'    => 'slug',
386
				'terms'    => $request['type'],
387
			);
388
		}
389
390
		// Filter by attribute and term.
391
		if ( ! empty( $request['attribute'] ) && ! empty( $request['attribute_term'] ) ) {
392
			if ( in_array( $request['attribute'], wc_get_attribute_taxonomy_names(), true ) ) {
393
				$tax_query[] = array(
394
					'taxonomy' => $request['attribute'],
395
					'field'    => 'term_id',
396
					'terms'    => $request['attribute_term'],
397
				);
398
			}
399
		}
400
401
		// Build tax_query if taxonomies are set.
402
		if ( ! empty( $tax_query ) ) {
403
			if ( ! empty( $args['tax_query'] ) ) {
404
				$args['tax_query'] = array_merge( $tax_query, $args['tax_query'] ); // WPCS: slow query ok.
405
			} else {
406
				$args['tax_query'] = $tax_query; // WPCS: slow query ok.
407
			}
408
		}
409
410
		// Filter featured.
411
		if ( is_bool( $request['featured'] ) ) {
412
			$args['tax_query'][] = array(
413
				'taxonomy' => 'product_visibility',
414
				'field'    => 'name',
415
				'terms'    => 'featured',
416
				'operator' => true === $request['featured'] ? 'IN' : 'NOT IN',
417
			);
418
		}
419
420
		// Filter by tax class.
421
		if ( ! empty( $request['tax_class'] ) ) {
422
			$args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok.
423
				$args,
424
				array(
425
					'key'   => '_tax_class',
426
					'value' => 'standard' !== $request['tax_class'] ? $request['tax_class'] : '',
427
				)
428
			);
429
		}
430
431
		// Filter by on sale products.
432
		if ( is_bool( $request['on_sale'] ) ) {
433
			$on_sale_key = $request['on_sale'] ? 'post__in' : 'post__not_in';
434
			$on_sale_ids = wc_get_product_ids_on_sale();
435
436
			// Use 0 when there's no on sale products to avoid return all products.
437
			$on_sale_ids = empty( $on_sale_ids ) ? array( 0 ) : $on_sale_ids;
438
439
			$args[ $on_sale_key ] += $on_sale_ids;
440
		}
441
442
		// Force the post_type argument, since it's not a user input variable.
443
		if ( ! empty( $request['sku'] ) ) {
444
			$args['post_type'] = array( 'product', 'product_variation' );
445
		} else {
446
			$args['post_type'] = $this->post_type;
447
		}
448
449
		$orderby = $request->get_param( 'orderby' );
450
		$order   = $request->get_param( 'order' );
451
452
		$ordering_args   = WC()->query->get_catalog_ordering_args( $orderby, $order );
453
		$args['orderby'] = $ordering_args['orderby'];
454
		$args['order']   = $ordering_args['order'];
455
		if ( $ordering_args['meta_key'] ) {
456
			$args['meta_key'] = $ordering_args['meta_key']; // WPCS: slow query ok.
457
		}
458
459
		return $args;
460
	}
461
462
	/**
463
	 * Prepare links for the request.
464
	 *
465
	 * @param \WC_Data         $object  Object data.
466
	 * @param \WP_REST_Request $request Request object.
467
	 *
468
	 * @return array                   Links for the given post.
469
	 */
470
	protected function prepare_links( $object, $request ) {
471
		$links = array(
472
			'self'       => array(
473
				'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $object->get_id() ) ),  // @codingStandardsIgnoreLine.
474
			),
475
			'collection' => array(
476
				'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),  // @codingStandardsIgnoreLine.
477
			),
478
		);
479
480
		if ( $object->get_parent_id() ) {
0 ignored issues
show
Bug introduced by
The method get_parent_id() does not exist on WC_Data. It seems like you code against a sub-type of WC_Data such as WC_Product or WC_Abstract_Order. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

480
		if ( $object->/** @scrutinizer ignore-call */ get_parent_id() ) {
Loading history...
481
			$links['up'] = array(
482
				'href' => rest_url( sprintf( '/%s/products/%d', $this->namespace, $object->get_parent_id() ) ),  // @codingStandardsIgnoreLine.
483
			);
484
		}
485
486
		return $links;
487
	}
488
489
	/**
490
	 * Delete a single item.
491
	 *
492
	 * @param \WP_REST_Request $request Full details about the request.
493
	 *
494
	 * @return \WP_REST_Response|\WP_Error
495
	 */
496
	public function delete_item( $request ) {
497
		$id     = (int) $request['id'];
498
		$force  = (bool) $request['force'];
499
		$object = $this->get_object( (int) $request['id'] );
500
		$result = false;
501
502
		if ( ! $object || 0 === $object->get_id() ) {
0 ignored issues
show
introduced by
$object is of type WC_Product, thus it always evaluated to true.
Loading history...
503
			return new \WP_Error(
504
				"woocommerce_rest_{$this->post_type}_invalid_id",
505
				__( 'Invalid ID.', 'woocommerce' ),
506
				array(
507
					'status' => 404,
508
				)
509
			);
510
		}
511
512
		if ( 'variation' === $object->get_type() ) {
513
			return new \WP_Error(
514
				"woocommerce_rest_invalid_{$this->post_type}_id",
515
				__( 'To manipulate product variations you should use the /products/&lt;product_id&gt;/variations/&lt;id&gt; endpoint.', 'woocommerce' ),
516
				array(
517
					'status' => 404,
518
				)
519
			);
520
		}
521
522
		$supports_trash = EMPTY_TRASH_DAYS > 0 && is_callable( array( $object, 'get_status' ) );
523
524
		/**
525
		 * Filter whether an object is trashable.
526
		 *
527
		 * Return false to disable trash support for the object.
528
		 *
529
		 * @param boolean $supports_trash Whether the object type support trashing.
530
		 * @param \WC_Data $object         The object being considered for trashing support.
531
		 */
532
		$supports_trash = apply_filters( "woocommerce_rest_{$this->post_type}_object_trashable", $supports_trash, $object );
533
534
		if ( ! wc_rest_check_post_permissions( $this->post_type, 'delete', $object->get_id() ) ) {
535
			return new \WP_Error(
536
				"woocommerce_rest_user_cannot_delete_{$this->post_type}",
537
				/* translators: %s: post type */
538
				sprintf( __( 'Sorry, you are not allowed to delete %s.', 'woocommerce' ), $this->post_type ),
539
				array(
540
					'status' => rest_authorization_required_code(),
541
				)
542
			);
543
		}
544
545
		$request->set_param( 'context', 'edit' );
546
547
		// If we're forcing, then delete permanently.
548
		if ( $force ) {
549
			$previous = $this->prepare_object_for_response( $object, $request );
550
551
			$object->delete( true );
552
			$result = 0 === $object->get_id();
553
554
			$response = new \WP_REST_Response();
555
			$response->set_data(
556
				array(
557
					'deleted'  => true,
558
					'previous' => $previous->get_data(),
559
				)
560
			);
561
		} else {
562
			// If we don't support trashing for this type, error out.
563
			if ( ! $supports_trash ) {
564
				return new \WP_Error(
565
					'woocommerce_rest_trash_not_supported',
566
					/* translators: %s: post type */
567
					sprintf( __( 'The %s does not support trashing.', 'woocommerce' ), $this->post_type ),
568
					array(
569
						'status' => 501,
570
					)
571
				);
572
			}
573
574
			// Otherwise, only trash if we haven't already.
575
			if ( is_callable( array( $object, 'get_status' ) ) ) {
576
				if ( 'trash' === $object->get_status() ) {
577
					return new \WP_Error(
578
						'woocommerce_rest_already_trashed',
579
						/* translators: %s: post type */
580
						sprintf( __( 'The %s has already been deleted.', 'woocommerce' ), $this->post_type ),
581
						array(
582
							'status' => 410,
583
						)
584
					);
585
				}
586
587
				$object->delete();
588
				$result = 'trash' === $object->get_status();
589
			}
590
591
			$response = $this->prepare_object_for_response( $object, $request );
592
		}
593
594
		if ( ! $result ) {
595
			return new \WP_Error(
596
				'woocommerce_rest_cannot_delete',
597
				/* translators: %s: post type */
598
				sprintf( __( 'The %s cannot be deleted.', 'woocommerce' ), $this->post_type ),
599
				array(
600
					'status' => 500,
601
				)
602
			);
603
		}
604
605
		/**
606
		 * Fires after a single object is deleted or trashed via the REST API.
607
		 *
608
		 * @param \WC_Data          $object   The deleted or trashed object.
609
		 * @param \WP_REST_Response $response The response data.
610
		 * @param \WP_REST_Request  $request  The request sent to the API.
611
		 */
612
		do_action( "woocommerce_rest_delete_{$this->post_type}_object", $object, $response, $request );
613
614
		return $response;
615
	}
616
}
617