AbstractTermsContoller   F
last analyzed

Complexity

Total Complexity 65

Size/Duplication

Total Lines 640
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 307
dl 0
loc 640
rs 3.2
c 0
b 0
f 0
wmc 65

13 Methods

Rating   Name   Duplication   Size   Complexity  
B create_item() 0 67 10
A get_hook_suffix() 0 2 1
B get_collection_params() 0 92 5
B get_terms_for_product() 0 34 9
A get_taxonomy() 0 14 3
A register_routes() 0 73 1
A update_term_meta_fields() 0 2 1
A compare_terms() 0 10 3
B update_item() 0 52 10
A prepare_links() 0 26 4
B get_items() 0 83 11
A get_item() 0 11 2
A delete_item() 0 36 5

How to fix   Complexity   

Complex Class

Complex classes like AbstractTermsContoller 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 AbstractTermsContoller, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Abstract Rest Terms Controller
4
 *
5
 * @package Automattic/WooCommerce/RestApi
6
 */
7
8
namespace Automattic\WooCommerce\RestApi\Controllers\Version4;
9
10
defined( 'ABSPATH' ) || exit;
11
12
use Automattic\WooCommerce\RestApi\Controllers\Version4\Utilities\Permissions;
13
use Automattic\WooCommerce\RestApi\Controllers\Version4\Utilities\Pagination;
14
15
/**
16
 * Terms controller class.
17
 */
18
abstract class AbstractTermsContoller extends AbstractController {
19
20
	/**
21
	 * Route base.
22
	 *
23
	 * @var string
24
	 */
25
	protected $rest_base = '';
26
27
	/**
28
	 * Taxonomy.
29
	 *
30
	 * @var string
31
	 */
32
	protected $taxonomy = '';
33
34
	/**
35
	 * Store total terms.
36
	 *
37
	 * @var integer
38
	 */
39
	protected $total_terms = 0;
40
41
	/**
42
	 * Store sort column.
43
	 *
44
	 * @var string
45
	 */
46
	protected $sort_column = '';
47
48
	/**
49
	 * Register the routes for terms.
50
	 */
51
	public function register_routes() {
52
		register_rest_route(
53
			$this->namespace,
54
			'/' . $this->rest_base,
55
			array(
56
				array(
57
					'methods'             => \WP_REST_Server::READABLE,
58
					'callback'            => array( $this, 'get_items' ),
59
					'permission_callback' => array( $this, 'get_items_permissions_check' ),
60
					'args'                => $this->get_collection_params(),
61
				),
62
				array(
63
					'methods'             => \WP_REST_Server::CREATABLE,
64
					'callback'            => array( $this, 'create_item' ),
65
					'permission_callback' => array( $this, 'create_item_permissions_check' ),
66
					'args'                => array_merge(
67
						$this->get_endpoint_args_for_item_schema( \WP_REST_Server::CREATABLE ),
68
						array(
69
							'name' => array(
70
								'type'        => 'string',
71
								'description' => __( 'Name for the resource.', 'woocommerce-rest-api' ),
72
								'required'    => true,
73
							),
74
						)
75
					),
76
				),
77
				'schema' => array( $this, 'get_public_item_schema' ),
78
			),
79
			true
80
		);
81
82
		register_rest_route(
83
			$this->namespace,
84
			'/' . $this->rest_base . '/(?P<id>[\d]+)',
85
			array(
86
				'args'   => array(
87
					'id' => array(
88
						'description' => __( 'Unique identifier for the resource.', 'woocommerce-rest-api' ),
89
						'type'        => 'integer',
90
					),
91
				),
92
				array(
93
					'methods'             => \WP_REST_Server::READABLE,
94
					'callback'            => array( $this, 'get_item' ),
95
					'permission_callback' => array( $this, 'get_item_permissions_check' ),
96
					'args'                => array(
97
						'context' => $this->get_context_param( array( 'default' => 'view' ) ),
98
					),
99
				),
100
				array(
101
					'methods'             => \WP_REST_Server::EDITABLE,
102
					'callback'            => array( $this, 'update_item' ),
103
					'permission_callback' => array( $this, 'update_item_permissions_check' ),
104
					'args'                => $this->get_endpoint_args_for_item_schema( \WP_REST_Server::EDITABLE ),
105
				),
106
				array(
107
					'methods'             => \WP_REST_Server::DELETABLE,
108
					'callback'            => array( $this, 'delete_item' ),
109
					'permission_callback' => array( $this, 'delete_item_permissions_check' ),
110
					'args'                => array(
111
						'force' => array(
112
							'default'     => false,
113
							'type'        => 'boolean',
114
							'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce-rest-api' ),
115
						),
116
					),
117
				),
118
				'schema' => array( $this, 'get_public_item_schema' ),
119
			),
120
			true
121
		);
122
123
		$this->register_batch_route();
124
	}
125
126
	/**
127
	 * Get terms associated with a taxonomy.
128
	 *
129
	 * @param \WP_REST_Request $request Full details about the request.
130
	 * @return \WP_REST_Response|\WP_Error
131
	 */
132
	public function get_items( $request ) {
133
		$taxonomy      = $this->get_taxonomy( $request );
134
		$prepared_args = array(
135
			'exclude'    => $request['exclude'],
136
			'include'    => $request['include'],
137
			'order'      => $request['order'],
138
			'orderby'    => $request['orderby'],
139
			'product'    => $request['product'],
140
			'hide_empty' => $request['hide_empty'],
141
			'number'     => $request['per_page'],
142
			'search'     => $request['search'],
143
			'slug'       => $request['slug'],
144
		);
145
146
		if ( ! empty( $request['offset'] ) ) {
147
			$prepared_args['offset'] = $request['offset'];
148
		} else {
149
			$prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number'];
150
		}
151
152
		$taxonomy_obj = get_taxonomy( $taxonomy );
153
154
		if ( $taxonomy_obj->hierarchical && isset( $request['parent'] ) ) {
155
			if ( 0 === $request['parent'] ) {
156
				// Only query top-level terms.
157
				$prepared_args['parent'] = 0;
158
			} else {
159
				if ( $request['parent'] ) {
160
					$prepared_args['parent'] = $request['parent'];
161
				}
162
			}
163
		}
164
165
		/**
166
		 * Filter the query arguments, before passing them to `get_terms()`.
167
		 *
168
		 * Enables adding extra arguments or setting defaults for a terms
169
		 * collection request.
170
		 *
171
		 * @see https://developer.wordpress.org/reference/functions/get_terms/
172
		 *
173
		 * @param array           $prepared_args Array of arguments to be
174
		 *                                       passed to get_terms.
175
		 * @param \WP_REST_Request $request       The current request.
176
		 */
177
		$prepared_args = apply_filters( "woocommerce_rest_{$taxonomy}_query", $prepared_args, $request );
178
179
		if ( ! empty( $prepared_args['product'] ) ) {
180
			$query_result = $this->get_terms_for_product( $prepared_args, $request );
181
			$total_terms  = $this->total_terms;
182
		} else {
183
			$query_result = get_terms( $taxonomy, $prepared_args );
184
185
			$count_args = $prepared_args;
186
			unset( $count_args['number'] );
187
			unset( $count_args['offset'] );
188
			$total_terms = wp_count_terms( $taxonomy, $count_args );
189
190
			// Ensure we don't return results when offset is out of bounds.
191
			// See https://core.trac.wordpress.org/ticket/35935.
192
			if ( $prepared_args['offset'] && $prepared_args['offset'] >= $total_terms ) {
193
				$query_result = array();
194
			}
195
196
			// wp_count_terms can return a falsy value when the term has no children.
197
			if ( ! $total_terms ) {
198
				$total_terms = 0;
199
			}
200
		}
201
		$response = array();
202
		foreach ( $query_result as $term ) {
203
			$data       = $this->prepare_item_for_response( $term, $request );
204
			$response[] = $this->prepare_response_for_collection( $data );
205
		}
206
207
		// Store pagination values for headers then unset for count query.
208
		$per_page  = (int) $prepared_args['number'];
209
		$max_pages = ceil( $total_terms / $per_page );
210
211
		$response = rest_ensure_response( $response );
212
		$response = Pagination::add_pagination_headers( $response, $request, $total_terms, $max_pages );
0 ignored issues
show
Bug introduced by
It seems like $response can also be of type array and array<mixed,array>; however, parameter $response of Automattic\WooCommerce\R...dd_pagination_headers() does only seem to accept WP_REST_Response, maybe add an additional type check? ( Ignorable by Annotation )

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

212
		$response = Pagination::add_pagination_headers( /** @scrutinizer ignore-type */ $response, $request, $total_terms, $max_pages );
Loading history...
213
214
		return $response;
215
	}
216
217
	/**
218
	 * Create a single term for a taxonomy.
219
	 *
220
	 * @param \WP_REST_Request $request Full details about the request.
221
	 * @return \WP_REST_Request|\WP_Error
222
	 */
223
	public function create_item( $request ) {
224
		$taxonomy = $this->get_taxonomy( $request );
225
		$name     = $request['name'];
226
		$args     = array();
227
		$schema   = $this->get_item_schema();
228
229
		if ( ! empty( $schema['properties']['description'] ) && isset( $request['description'] ) ) {
230
			$args['description'] = $request['description'];
231
		}
232
		if ( isset( $request['slug'] ) ) {
233
			$args['slug'] = $request['slug'];
234
		}
235
		if ( isset( $request['parent'] ) ) {
236
			if ( ! is_taxonomy_hierarchical( $taxonomy ) ) {
237
				return new \WP_Error( 'woocommerce_rest_taxonomy_not_hierarchical', __( 'Can not set resource parent, taxonomy is not hierarchical.', 'woocommerce-rest-api' ), array( 'status' => 400 ) );
238
			}
239
			$args['parent'] = $request['parent'];
240
		}
241
242
		$term = wp_insert_term( $name, $taxonomy, $args );
243
		if ( is_wp_error( $term ) ) {
244
			$error_data = array( 'status' => 400 );
245
246
			// If we're going to inform the client that the term exists,
247
			// give them the identifier they can actually use.
248
			$term_id = $term->get_error_data( 'term_exists' );
249
			if ( $term_id ) {
250
				$error_data['resource_id'] = $term_id;
251
			}
252
253
			return new \WP_Error( $term->get_error_code(), $term->get_error_message(), $error_data );
254
		}
255
256
		$term = get_term( $term['term_id'], $taxonomy );
257
258
		$this->update_additional_fields_for_object( $term, $request );
0 ignored issues
show
Bug introduced by
It seems like $term can also be of type WP_Error and WP_Term; however, parameter $object of WP_REST_Controller::upda...nal_fields_for_object() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

258
		$this->update_additional_fields_for_object( /** @scrutinizer ignore-type */ $term, $request );
Loading history...
259
260
		// Add term data.
261
		$meta_fields = $this->update_term_meta_fields( $term, $request );
262
		if ( is_wp_error( $meta_fields ) ) {
263
			wp_delete_term( $term->term_id, $taxonomy );
0 ignored issues
show
Bug introduced by
The property term_id does not seem to exist on WP_Error.
Loading history...
264
265
			return $meta_fields;
266
		}
267
268
		/**
269
		 * Fires after a single term is created or updated via the REST API.
270
		 *
271
		 * @param WP_Term         $term      Inserted Term object.
272
		 * @param \WP_REST_Request $request   Request object.
273
		 * @param boolean         $creating  True when creating term, false when updating.
274
		 */
275
		do_action( "woocommerce_rest_insert_{$taxonomy}", $term, $request, true );
276
277
		$request->set_param( 'context', 'edit' );
278
		$response = $this->prepare_item_for_response( $term, $request );
279
		$response = rest_ensure_response( $response );
280
		$response->set_status( 201 );
281
282
		$base = '/' . $this->namespace . '/' . $this->rest_base;
283
		if ( ! empty( $request['attribute_id'] ) ) {
284
			$base = str_replace( '(?P<attribute_id>[\d]+)', (int) $request['attribute_id'], $base );
285
		}
286
287
		$response->header( 'Location', rest_url( $base . '/' . $term->term_id ) );
288
289
		return $response;
290
	}
291
292
	/**
293
	 * Get a single term from a taxonomy.
294
	 *
295
	 * @param \WP_REST_Request $request Full details about the request.
296
	 * @return \WP_REST_Request|\WP_Error
297
	 */
298
	public function get_item( $request ) {
299
		$taxonomy = $this->get_taxonomy( $request );
300
		$term     = get_term( (int) $request['id'], $taxonomy );
301
302
		if ( is_wp_error( $term ) ) {
303
			return $term;
304
		}
305
306
		$response = $this->prepare_item_for_response( $term, $request );
307
308
		return rest_ensure_response( $response );
309
	}
310
311
	/**
312
	 * Update a single term from a taxonomy.
313
	 *
314
	 * @param \WP_REST_Request $request Full details about the request.
315
	 * @return \WP_REST_Request|\WP_Error
316
	 */
317
	public function update_item( $request ) {
318
		$taxonomy      = $this->get_taxonomy( $request );
319
		$term          = get_term( (int) $request['id'], $taxonomy );
320
		$schema        = $this->get_item_schema();
321
		$prepared_args = array();
322
323
		if ( isset( $request['name'] ) ) {
324
			$prepared_args['name'] = $request['name'];
325
		}
326
		if ( ! empty( $schema['properties']['description'] ) && isset( $request['description'] ) ) {
327
			$prepared_args['description'] = $request['description'];
328
		}
329
		if ( isset( $request['slug'] ) ) {
330
			$prepared_args['slug'] = $request['slug'];
331
		}
332
		if ( isset( $request['parent'] ) ) {
333
			if ( ! is_taxonomy_hierarchical( $taxonomy ) ) {
334
				return new \WP_Error( 'woocommerce_rest_taxonomy_not_hierarchical', __( 'Can not set resource parent, taxonomy is not hierarchical.', 'woocommerce-rest-api' ), array( 'status' => 400 ) );
335
			}
336
			$prepared_args['parent'] = $request['parent'];
337
		}
338
339
		// Only update the term if we haz something to update.
340
		if ( ! empty( $prepared_args ) ) {
341
			$update = wp_update_term( $term->term_id, $term->taxonomy, $prepared_args );
0 ignored issues
show
Bug introduced by
The property term_id does not seem to exist on WP_Error.
Loading history...
Bug introduced by
The property taxonomy does not seem to exist on WP_Error.
Loading history...
342
			if ( is_wp_error( $update ) ) {
343
				return $update;
344
			}
345
		}
346
347
		$term = get_term( (int) $request['id'], $taxonomy );
348
349
		$this->update_additional_fields_for_object( $term, $request );
0 ignored issues
show
Bug introduced by
It seems like $term can also be of type WP_Error and WP_Term; however, parameter $object of WP_REST_Controller::upda...nal_fields_for_object() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

349
		$this->update_additional_fields_for_object( /** @scrutinizer ignore-type */ $term, $request );
Loading history...
350
351
		// Update term data.
352
		$meta_fields = $this->update_term_meta_fields( $term, $request );
353
		if ( is_wp_error( $meta_fields ) ) {
354
			return $meta_fields;
355
		}
356
357
		/**
358
		 * Fires after a single term is created or updated via the REST API.
359
		 *
360
		 * @param WP_Term         $term      Inserted Term object.
361
		 * @param \WP_REST_Request $request   Request object.
362
		 * @param boolean         $creating  True when creating term, false when updating.
363
		 */
364
		do_action( "woocommerce_rest_insert_{$taxonomy}", $term, $request, false );
365
366
		$request->set_param( 'context', 'edit' );
367
		$response = $this->prepare_item_for_response( $term, $request );
368
		return rest_ensure_response( $response );
369
	}
370
371
	/**
372
	 * Delete a single term from a taxonomy.
373
	 *
374
	 * @param \WP_REST_Request $request Full details about the request.
375
	 * @return \WP_REST_Response|\WP_Error
376
	 */
377
	public function delete_item( $request ) {
378
		$taxonomy = $this->get_taxonomy( $request );
379
		$force    = isset( $request['force'] ) ? (bool) $request['force'] : false;
380
381
		// We don't support trashing for this type, error out.
382
		if ( ! $force ) {
383
			return new \WP_Error( 'woocommerce_rest_trash_not_supported', __( 'Resource does not support trashing.', 'woocommerce-rest-api' ), array( 'status' => 501 ) );
384
		}
385
386
		$term = get_term( (int) $request['id'], $taxonomy );
387
		// Get default category id.
388
		$default_category_id = absint( get_option( 'default_product_cat', 0 ) );
389
390
		// Prevent deleting the default product category.
391
		if ( $default_category_id === (int) $request['id'] ) {
392
			return new \WP_Error( 'woocommerce_rest_cannot_delete', __( 'Default product category cannot be deleted.', 'woocommerce-rest-api' ), array( 'status' => 500 ) );
393
		}
394
395
		$request->set_param( 'context', 'edit' );
396
		$response = $this->prepare_item_for_response( $term, $request );
397
398
		$retval = wp_delete_term( $term->term_id, $term->taxonomy );
0 ignored issues
show
Bug introduced by
The property taxonomy does not seem to exist on WP_Error.
Loading history...
Bug introduced by
The property term_id does not seem to exist on WP_Error.
Loading history...
399
		if ( ! $retval ) {
400
			return new \WP_Error( 'woocommerce_rest_cannot_delete', __( 'The resource cannot be deleted.', 'woocommerce-rest-api' ), array( 'status' => 500 ) );
401
		}
402
403
		/**
404
		 * Fires after a single term is deleted via the REST API.
405
		 *
406
		 * @param WP_Term          $term     The deleted term.
407
		 * @param \WP_REST_Response $response The response data.
408
		 * @param \WP_REST_Request  $request  The request sent to the API.
409
		 */
410
		do_action( "woocommerce_rest_delete_{$taxonomy}", $term, $response, $request );
411
412
		return $response;
413
	}
414
415
	/**
416
	 * Prepare links for the request.
417
	 *
418
	 * @param mixed            $item Object to prepare.
419
	 * @param \WP_REST_Request $request Request object.
420
	 * @return array
421
	 */
422
	protected function prepare_links( $item, $request ) {
423
		$base = '/' . $this->namespace . '/' . $this->rest_base;
424
425
		if ( ! empty( $request['attribute_id'] ) ) {
426
			$base = str_replace( '(?P<attribute_id>[\d]+)', (int) $request['attribute_id'], $base );
427
		}
428
429
		$links = array(
430
			'self'       => array(
431
				'href' => rest_url( trailingslashit( $base ) . $item->term_id ),
432
			),
433
			'collection' => array(
434
				'href' => rest_url( $base ),
435
			),
436
		);
437
438
		if ( $item->parent ) {
439
			$parent_term = get_term( (int) $item->parent, $item->taxonomy );
440
			if ( $parent_term ) {
441
				$links['up'] = array(
442
					'href' => rest_url( trailingslashit( $base ) . $parent_term->term_id ),
0 ignored issues
show
Bug introduced by
The property term_id does not seem to exist on WP_Error.
Loading history...
443
				);
444
			}
445
		}
446
447
		return $links;
448
	}
449
450
	/**
451
	 * Update term meta fields.
452
	 *
453
	 * @param \WP_Term         $term    Term object.
454
	 * @param \WP_REST_Request $request Full details about the request.
455
	 * @return bool|\WP_Error
456
	 */
457
	protected function update_term_meta_fields( $term, $request ) {
0 ignored issues
show
Unused Code introduced by
The parameter $term is not used and could be removed. ( Ignorable by Annotation )

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

457
	protected function update_term_meta_fields( /** @scrutinizer ignore-unused */ $term, $request ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
458
		return true;
459
	}
460
461
	/**
462
	 * Get the terms attached to a product.
463
	 *
464
	 * This is an alternative to `get_terms()` that uses `get_the_terms()`
465
	 * instead, which hits the object cache. There are a few things not
466
	 * supported, notably `include`, `exclude`. In `self::get_items()` these
467
	 * are instead treated as a full query.
468
	 *
469
	 * @param array            $prepared_args Arguments for `get_terms()`.
470
	 * @param \WP_REST_Request $request       Full details about the request.
471
	 * @return array List of term objects. (Total count in `$this->total_terms`).
472
	 */
473
	protected function get_terms_for_product( $prepared_args, $request ) {
474
		$taxonomy = $this->get_taxonomy( $request );
475
476
		$query_result = get_the_terms( $prepared_args['product'], $taxonomy );
477
		if ( empty( $query_result ) ) {
478
			$this->total_terms = 0;
479
			return array();
480
		}
481
482
		// get_items() verifies that we don't have `include` set, and default.
483
		// ordering is by `name`.
484
		if ( ! in_array( $prepared_args['orderby'], array( 'name', 'none', 'include' ), true ) ) {
485
			switch ( $prepared_args['orderby'] ) {
486
				case 'id':
487
					$this->sort_column = 'term_id';
488
					break;
489
				case 'slug':
490
				case 'term_group':
491
				case 'description':
492
				case 'count':
493
					$this->sort_column = $prepared_args['orderby'];
494
					break;
495
			}
496
			usort( $query_result, array( $this, 'compare_terms' ) );
497
		}
498
		if ( strtolower( $prepared_args['order'] ) !== 'asc' ) {
499
			$query_result = array_reverse( $query_result );
500
		}
501
502
		// Pagination.
503
		$this->total_terms = count( $query_result );
504
		$query_result      = array_slice( $query_result, $prepared_args['offset'], $prepared_args['number'] );
505
506
		return $query_result;
507
	}
508
509
	/**
510
	 * Comparison function for sorting terms by a column.
511
	 *
512
	 * Uses `$this->sort_column` to determine field to sort by.
513
	 *
514
	 * @param \stdClass $left Term object.
515
	 * @param \stdClass $right Term object.
516
	 * @return int <0 if left is higher "priority" than right, 0 if equal, >0 if right is higher "priority" than left.
517
	 */
518
	protected function compare_terms( $left, $right ) {
519
		$col       = $this->sort_column;
520
		$left_val  = $left->$col;
521
		$right_val = $right->$col;
522
523
		if ( is_int( $left_val ) && is_int( $right_val ) ) {
524
			return $left_val - $right_val;
525
		}
526
527
		return strcmp( $left_val, $right_val );
528
	}
529
530
	/**
531
	 * Get the query params for collections
532
	 *
533
	 * @return array
534
	 */
535
	public function get_collection_params() {
536
		$params = parent::get_collection_params();
537
538
		if ( '' !== $this->taxonomy && taxonomy_exists( $this->taxonomy ) ) {
539
			$taxonomy = get_taxonomy( $this->taxonomy );
540
		} else {
541
			$taxonomy               = new \stdClass();
542
			$taxonomy->hierarchical = true;
543
		}
544
545
		$params['context']['default'] = 'view';
546
547
		$params['exclude'] = array(
548
			'description'       => __( 'Ensure result set excludes specific IDs.', 'woocommerce-rest-api' ),
549
			'type'              => 'array',
550
			'items'             => array(
551
				'type' => 'integer',
552
			),
553
			'default'           => array(),
554
			'sanitize_callback' => 'wp_parse_id_list',
555
		);
556
		$params['include'] = array(
557
			'description'       => __( 'Limit result set to specific ids.', 'woocommerce-rest-api' ),
558
			'type'              => 'array',
559
			'items'             => array(
560
				'type' => 'integer',
561
			),
562
			'default'           => array(),
563
			'sanitize_callback' => 'wp_parse_id_list',
564
		);
565
		if ( ! $taxonomy->hierarchical ) {
566
			$params['offset'] = array(
567
				'description'       => __( 'Offset the result set by a specific number of items.', 'woocommerce-rest-api' ),
568
				'type'              => 'integer',
569
				'sanitize_callback' => 'absint',
570
				'validate_callback' => 'rest_validate_request_arg',
571
			);
572
		}
573
		$params['order']      = array(
574
			'description'       => __( 'Order sort attribute ascending or descending.', 'woocommerce-rest-api' ),
575
			'type'              => 'string',
576
			'sanitize_callback' => 'sanitize_key',
577
			'default'           => 'asc',
578
			'enum'              => array(
579
				'asc',
580
				'desc',
581
			),
582
			'validate_callback' => 'rest_validate_request_arg',
583
		);
584
		$params['orderby']    = array(
585
			'description'       => __( 'Sort collection by resource attribute.', 'woocommerce-rest-api' ),
586
			'type'              => 'string',
587
			'sanitize_callback' => 'sanitize_key',
588
			'default'           => 'name',
589
			'enum'              => array(
590
				'id',
591
				'include',
592
				'name',
593
				'slug',
594
				'term_group',
595
				'description',
596
				'count',
597
			),
598
			'validate_callback' => 'rest_validate_request_arg',
599
		);
600
		$params['hide_empty'] = array(
601
			'description'       => __( 'Whether to hide resources not assigned to any products.', 'woocommerce-rest-api' ),
602
			'type'              => 'boolean',
603
			'default'           => false,
604
			'validate_callback' => 'rest_validate_request_arg',
605
		);
606
		if ( $taxonomy->hierarchical ) {
607
			$params['parent'] = array(
608
				'description'       => __( 'Limit result set to resources assigned to a specific parent.', 'woocommerce-rest-api' ),
609
				'type'              => 'integer',
610
				'sanitize_callback' => 'absint',
611
				'validate_callback' => 'rest_validate_request_arg',
612
			);
613
		}
614
		$params['product'] = array(
615
			'description'       => __( 'Limit result set to resources assigned to a specific product.', 'woocommerce-rest-api' ),
616
			'type'              => 'integer',
617
			'default'           => null,
618
			'validate_callback' => 'rest_validate_request_arg',
619
		);
620
		$params['slug']    = array(
621
			'description'       => __( 'Limit result set to resources with a specific slug.', 'woocommerce-rest-api' ),
622
			'type'              => 'string',
623
			'validate_callback' => 'rest_validate_request_arg',
624
		);
625
626
		return $params;
627
	}
628
629
	/**
630
	 * Get taxonomy.
631
	 *
632
	 * @param \WP_REST_Request $request Full details about the request.
633
	 * @return string
634
	 */
635
	protected function get_taxonomy( $request ) {
636
		// Check if taxonomy is defined.
637
		// Prevents check for attribute taxonomy more than one time for each query.
638
		if ( '' !== $this->taxonomy ) {
639
			return $this->taxonomy;
640
		}
641
642
		if ( ! empty( $request['attribute_id'] ) ) {
643
			$taxonomy = wc_attribute_taxonomy_name_by_id( (int) $request['attribute_id'] );
644
645
			$this->taxonomy = $taxonomy;
646
		}
647
648
		return $this->taxonomy;
649
	}
650
651
	/**
652
	 * Return suffix for item action hooks.
653
	 *
654
	 * @return string
655
	 */
656
	protected function get_hook_suffix() {
657
		return $this->taxonomy;
658
	}
659
}
660