Completed
Push — master ( 15aa29...17da96 )
by Claudio
18:39 queued 11s
created

abstracts/abstract-wc-rest-crud-controller.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Abstract Rest CRUD Controller Class
4
 *
5
 * @class    WC_REST_CRUD_Controller
6
 * @package  WooCommerce/Abstracts
7
 * @version  3.0.0
8
 */
9
10 1
if ( ! defined( 'ABSPATH' ) ) {
11
	exit;
12
}
13
14
/**
15
 * WC_REST_CRUD_Controller class.
16
 *
17
 * @extends WC_REST_Posts_Controller
18
 */
19
abstract class WC_REST_CRUD_Controller extends WC_REST_Posts_Controller {
20
21
	/**
22
	 * Endpoint namespace.
23
	 *
24
	 * @var string
25
	 */
26
	protected $namespace = 'wc/v2';
27
28
	/**
29
	 * If object is hierarchical.
30
	 *
31
	 * @var bool
32
	 */
33
	protected $hierarchical = false;
34
35
	/**
36
	 * Get object.
37
	 *
38
	 * @param  int $id Object ID.
39
	 * @return object WC_Data object or WP_Error object.
40
	 */
41
	protected function get_object( $id ) {
42
		// translators: %s: Class method name.
43
		return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass.", 'woocommerce' ), __METHOD__ ), array( 'status' => 405 ) );
44
	}
45
46
	/**
47
	 * Check if a given request has access to read an item.
48
	 *
49
	 * @param  WP_REST_Request $request Full details about the request.
50
	 * @return WP_Error|boolean
51
	 */
52 86 View Code Duplication
	public function get_item_permissions_check( $request ) {
53 86
		$object = $this->get_object( (int) $request['id'] );
54
55 86
		if ( $object && 0 !== $object->get_id() && ! wc_rest_check_post_permissions( $this->post_type, 'read', $object->get_id() ) ) {
56 24
			return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
57
		}
58
59 62
		return true;
60
	}
61
62
	/**
63
	 * Check if a given request has access to update an item.
64
	 *
65
	 * @param  WP_REST_Request $request Full details about the request.
66
	 * @return WP_Error|boolean
67
	 */
68 68 View Code Duplication
	public function update_item_permissions_check( $request ) {
69 68
		$object = $this->get_object( (int) $request['id'] );
70
71 68
		if ( $object && 0 !== $object->get_id() && ! wc_rest_check_post_permissions( $this->post_type, 'edit', $object->get_id() ) ) {
72 18
			return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
73
		}
74
75 50
		return true;
76
	}
77
78
	/**
79
	 * Check if a given request has access to delete an item.
80
	 *
81
	 * @param  WP_REST_Request $request Full details about the request.
82
	 * @return bool|WP_Error
83
	 */
84 86 View Code Duplication
	public function delete_item_permissions_check( $request ) {
85 86
		$object = $this->get_object( (int) $request['id'] );
86
87 86
		if ( $object && 0 !== $object->get_id() && ! wc_rest_check_post_permissions( $this->post_type, 'delete', $object->get_id() ) ) {
88 26
			return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
89
		}
90
91 62
		return true;
92
	}
93
94
	/**
95
	 * Get object permalink.
96
	 *
97
	 * @param  object $object Object.
98
	 * @return string
99
	 */
100
	protected function get_permalink( $object ) {
101
		return '';
102
	}
103
104
	/**
105
	 * Prepares the object for the REST response.
106
	 *
107
	 * @since  3.0.0
108
	 * @param  WC_Data         $object  Object data.
109
	 * @param  WP_REST_Request $request Request object.
110
	 * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
111
	 */
112
	protected function prepare_object_for_response( $object, $request ) {
113
		// translators: %s: Class method name.
114
		return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass.", 'woocommerce' ), __METHOD__ ), array( 'status' => 405 ) );
115
	}
116
117
	/**
118
	 * Prepares one object for create or update operation.
119
	 *
120
	 * @since  3.0.0
121
	 * @param  WP_REST_Request $request Request object.
122
	 * @param  bool            $creating If is creating a new object.
123
	 * @return WP_Error|WC_Data The prepared item, or WP_Error object on failure.
124
	 */
125
	protected function prepare_object_for_database( $request, $creating = false ) {
126
		// translators: %s: Class method name.
127
		return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass.", 'woocommerce' ), __METHOD__ ), array( 'status' => 405 ) );
128
	}
129
130
	/**
131
	 * Get a single item.
132
	 *
133
	 * @param WP_REST_Request $request Full details about the request.
134
	 * @return WP_Error|WP_REST_Response
135
	 */
136 21
	public function get_item( $request ) {
137 21
		$object = $this->get_object( (int) $request['id'] );
138
139 21
		if ( ! $object || 0 === $object->get_id() ) {
140 6
			return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce' ), array( 'status' => 404 ) );
141
		}
142
143 15
		$data     = $this->prepare_object_for_response( $object, $request );
144 15
		$response = rest_ensure_response( $data );
145
146 15
		if ( $this->public ) {
147
			$response->link_header( 'alternate', $this->get_permalink( $object ), array( 'type' => 'text/html' ) );
148
		}
149
150 15
		return $response;
151
	}
152
153
	/**
154
	 * Save an object data.
155
	 *
156
	 * @since  3.0.0
157
	 * @param  WP_REST_Request $request  Full details about the request.
158
	 * @param  bool            $creating If is creating a new object.
159
	 * @return WC_Data|WP_Error
160
	 */
161 20 View Code Duplication
	protected function save_object( $request, $creating = false ) {
162
		try {
163 20
			$object = $this->prepare_object_for_database( $request, $creating );
164
165 20
			if ( is_wp_error( $object ) ) {
166
				return $object;
167
			}
168
169 20
			$object->save();
170
171 20
			return $this->get_object( $object->get_id() );
172
		} catch ( WC_Data_Exception $e ) {
173
			return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() );
174
		} catch ( WC_REST_Exception $e ) {
175
			return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
176
		}
177
	}
178
179
	/**
180
	 * Create a single item.
181
	 *
182
	 * @param WP_REST_Request $request Full details about the request.
183
	 * @return WP_Error|WP_REST_Response
184
	 */
185 16
	public function create_item( $request ) {
186 16
		if ( ! empty( $request['id'] ) ) {
187
			/* translators: %s: post type */
188
			return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce' ), $this->post_type ), array( 'status' => 400 ) );
189
		}
190
191 16
		$object = $this->save_object( $request, true );
192
193 16
		if ( is_wp_error( $object ) ) {
194
			return $object;
195
		}
196
197
		try {
198 16
			$this->update_additional_fields_for_object( $object, $request );
199
200
			/**
201
			 * Fires after a single object is created or updated via the REST API.
202
			 *
203
			 * @param WC_Data         $object    Inserted object.
204
			 * @param WP_REST_Request $request   Request object.
205
			 * @param boolean         $creating  True when creating object, false when updating.
206
			 */
207 16
			do_action( "woocommerce_rest_insert_{$this->post_type}_object", $object, $request, true );
208
		} catch ( WC_Data_Exception $e ) {
209
			$object->delete();
210
			return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() );
211
		} catch ( WC_REST_Exception $e ) {
212
			$object->delete();
213
			return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
214
		}
215
216 16
		$request->set_param( 'context', 'edit' );
217 16
		$response = $this->prepare_object_for_response( $object, $request );
218 16
		$response = rest_ensure_response( $response );
219 16
		$response->set_status( 201 );
220 16
		$response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $object->get_id() ) ) );
221
222 16
		return $response;
223
	}
224
225
	/**
226
	 * Update a single post.
227
	 *
228
	 * @param WP_REST_Request $request Full details about the request.
229
	 * @return WP_Error|WP_REST_Response
230
	 */
231 35
	public function update_item( $request ) {
232 35
		$object = $this->get_object( (int) $request['id'] );
233
234 35
		if ( ! $object || 0 === $object->get_id() ) {
235 8
			return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce' ), array( 'status' => 400 ) );
236
		}
237
238 27
		$object = $this->save_object( $request, false );
239
240 27
		if ( is_wp_error( $object ) ) {
241 1
			return $object;
242
		}
243
244
		try {
245 26
			$this->update_additional_fields_for_object( $object, $request );
246
247
			/**
248
			 * Fires after a single object is created or updated via the REST API.
249
			 *
250
			 * @param WC_Data         $object    Inserted object.
251
			 * @param WP_REST_Request $request   Request object.
252
			 * @param boolean         $creating  True when creating object, false when updating.
253
			 */
254 26
			do_action( "woocommerce_rest_insert_{$this->post_type}_object", $object, $request, false );
255
		} catch ( WC_Data_Exception $e ) {
256
			return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() );
257
		} catch ( WC_REST_Exception $e ) {
258
			return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
259
		}
260
261 26
		$request->set_param( 'context', 'edit' );
262 26
		$response = $this->prepare_object_for_response( $object, $request );
263 26
		return rest_ensure_response( $response );
264
	}
265
266
	/**
267
	 * Prepare objects query.
268
	 *
269
	 * @since  3.0.0
270
	 * @param  WP_REST_Request $request Full details about the request.
271
	 * @return array
272
	 */
273 39
	protected function prepare_objects_query( $request ) {
274 39
		$args                        = array();
275 39
		$args['offset']              = $request['offset'];
276 39
		$args['order']               = $request['order'];
277 39
		$args['orderby']             = $request['orderby'];
278 39
		$args['paged']               = $request['page'];
279 39
		$args['post__in']            = $request['include'];
280 39
		$args['post__not_in']        = $request['exclude'];
281 39
		$args['posts_per_page']      = $request['per_page'];
282 39
		$args['name']                = $request['slug'];
283 39
		$args['post_parent__in']     = $request['parent'];
284 39
		$args['post_parent__not_in'] = $request['parent_exclude'];
285 39
		$args['s']                   = $request['search'];
286
287 39
		if ( 'date' === $args['orderby'] ) {
288 38
			$args['orderby'] = 'date ID';
289
		}
290
291 39
		$args['date_query'] = array();
292
		// Set before into date query. Date query must be specified as an array of an array.
293 39 View Code Duplication
		if ( isset( $request['before'] ) ) {
294
			$args['date_query'][0]['before'] = $request['before'];
295
		}
296
297
		// Set after into date query. Date query must be specified as an array of an array.
298 39 View Code Duplication
		if ( isset( $request['after'] ) ) {
299
			$args['date_query'][0]['after'] = $request['after'];
300
		}
301
302
		// Force the post_type argument, since it's not a user input variable.
303 39
		$args['post_type'] = $this->post_type;
304
305
		/**
306
		 * Filter the query arguments for a request.
307
		 *
308
		 * Enables adding extra arguments or setting defaults for a post
309
		 * collection request.
310
		 *
311
		 * @param array           $args    Key value array of query var to query value.
312
		 * @param WP_REST_Request $request The request used.
313
		 */
314 39
		$args = apply_filters( "woocommerce_rest_{$this->post_type}_object_query", $args, $request );
315
316 39
		return $this->prepare_items_query( $args, $request );
317
	}
318
319
	/**
320
	 * Get objects.
321
	 *
322
	 * @since  3.0.0
323
	 * @param  array $query_args Query args.
324
	 * @return array
325
	 */
326 39
	protected function get_objects( $query_args ) {
327 39
		$query  = new WP_Query();
328 39
		$result = $query->query( $query_args );
329
330 39
		$total_posts = $query->found_posts;
331 39 View Code Duplication
		if ( $total_posts < 1 ) {
332
			// Out-of-bounds, run the query again without LIMIT for total count.
333 2
			unset( $query_args['paged'] );
334 2
			$count_query = new WP_Query();
335 2
			$count_query->query( $query_args );
336 2
			$total_posts = $count_query->found_posts;
337
		}
338
339
		return array(
340 39
			'objects' => array_map( array( $this, 'get_object' ), $result ),
341 39
			'total'   => (int) $total_posts,
342 39
			'pages'   => (int) ceil( $total_posts / (int) $query->query_vars['posts_per_page'] ),
343
		);
344
	}
345
346
	/**
347
	 * Get a collection of posts.
348
	 *
349
	 * @param WP_REST_Request $request Full details about the request.
350
	 * @return WP_Error|WP_REST_Response
351
	 */
352 32 View Code Duplication
	public function get_items( $request ) {
353 32
		$query_args    = $this->prepare_objects_query( $request );
354 32
		$query_results = $this->get_objects( $query_args );
355
356 32
		$objects = array();
357 32
		foreach ( $query_results['objects'] as $object ) {
358 30
			if ( ! wc_rest_check_post_permissions( $this->post_type, 'read', $object->get_id() ) ) {
359
				continue;
360
			}
361
362 30
			$data = $this->prepare_object_for_response( $object, $request );
363 30
			$objects[] = $this->prepare_response_for_collection( $data );
364
		}
365
366 32
		$page      = (int) $query_args['paged'];
367 32
		$max_pages = $query_results['pages'];
368
369 32
		$response = rest_ensure_response( $objects );
370 32
		$response->header( 'X-WP-Total', $query_results['total'] );
371 32
		$response->header( 'X-WP-TotalPages', (int) $max_pages );
372
373 32
		$base          = $this->rest_base;
374 32
		$attrib_prefix = '(?P<';
375 32
		if ( strpos( $base, $attrib_prefix ) !== false ) {
0 ignored issues
show
Found "!== false". Use Yoda Condition checks, you must
Loading history...
376 8
			$attrib_names = array();
377 8
			preg_match( '/\(\?P<[^>]+>.*\)/', $base, $attrib_names, PREG_OFFSET_CAPTURE );
378 8
			foreach ( $attrib_names as $attrib_name_match ) {
379 8
				$beginning_offset = strlen( $attrib_prefix );
380 8
				$attrib_name_end  = strpos( $attrib_name_match[0], '>', $attrib_name_match[1] );
381 8
				$attrib_name      = substr( $attrib_name_match[0], $beginning_offset, $attrib_name_end - $beginning_offset );
382 8
				if ( isset( $request[ $attrib_name ] ) ) {
383 8
					$base  = str_replace( "(?P<$attrib_name>[\d]+)", $request[ $attrib_name ], $base );
384
				}
385
			}
386
		}
387 32
		$base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $base ) ) );
388
389 32
		if ( $page > 1 ) {
390
			$prev_page = $page - 1;
391
			if ( $prev_page > $max_pages ) {
392
				$prev_page = $max_pages;
393
			}
394
			$prev_link = add_query_arg( 'page', $prev_page, $base );
395
			$response->link_header( 'prev', $prev_link );
396
		}
397 32
		if ( $max_pages > $page ) {
398
			$next_page = $page + 1;
399
			$next_link = add_query_arg( 'page', $next_page, $base );
400
			$response->link_header( 'next', $next_link );
401
		}
402
403 32
		return $response;
404
	}
405
406
	/**
407
	 * Delete a single item.
408
	 *
409
	 * @param WP_REST_Request $request Full details about the request.
410
	 * @return WP_REST_Response|WP_Error
411
	 */
412 12
	public function delete_item( $request ) {
413 12
		$force  = (bool) $request['force'];
414 12
		$object = $this->get_object( (int) $request['id'] );
415 12
		$result = false;
416
417 12
		if ( ! $object || 0 === $object->get_id() ) {
418 4
			return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce' ), array( 'status' => 404 ) );
419
		}
420
421 8
		$supports_trash = EMPTY_TRASH_DAYS > 0 && is_callable( array( $object, 'get_status' ) );
422
423
		/**
424
		 * Filter whether an object is trashable.
425
		 *
426
		 * Return false to disable trash support for the object.
427
		 *
428
		 * @param boolean $supports_trash Whether the object type support trashing.
429
		 * @param WC_Data $object         The object being considered for trashing support.
430
		 */
431 8
		$supports_trash = apply_filters( "woocommerce_rest_{$this->post_type}_object_trashable", $supports_trash, $object );
432
433 8 View Code Duplication
		if ( ! wc_rest_check_post_permissions( $this->post_type, 'delete', $object->get_id() ) ) {
434
			/* translators: %s: post type */
435
			return new WP_Error( "woocommerce_rest_user_cannot_delete_{$this->post_type}", sprintf( __( 'Sorry, you are not allowed to delete %s.', 'woocommerce' ), $this->post_type ), array( 'status' => rest_authorization_required_code() ) );
436
		}
437
438 8
		$request->set_param( 'context', 'edit' );
439 8
		$response = $this->prepare_object_for_response( $object, $request );
440
441
		// If we're forcing, then delete permanently.
442 8 View Code Duplication
		if ( $force ) {
443 8
			$object->delete( true );
444 8
			$result = 0 === $object->get_id();
445
		} else {
446
			// If we don't support trashing for this type, error out.
447
			if ( ! $supports_trash ) {
448
				/* translators: %s: post type */
449
				return new WP_Error( 'woocommerce_rest_trash_not_supported', sprintf( __( 'The %s does not support trashing.', 'woocommerce' ), $this->post_type ), array( 'status' => 501 ) );
450
			}
451
452
			// Otherwise, only trash if we haven't already.
453
			if ( is_callable( array( $object, 'get_status' ) ) ) {
454
				if ( 'trash' === $object->get_status() ) {
455
					/* translators: %s: post type */
456
					return new WP_Error( 'woocommerce_rest_already_trashed', sprintf( __( 'The %s has already been deleted.', 'woocommerce' ), $this->post_type ), array( 'status' => 410 ) );
457
				}
458
459
				$object->delete();
460
				$result = 'trash' === $object->get_status();
461
			}
462
		}
463
464 8
		if ( ! $result ) {
465
			/* translators: %s: post type */
466
			return new WP_Error( 'woocommerce_rest_cannot_delete', sprintf( __( 'The %s cannot be deleted.', 'woocommerce' ), $this->post_type ), array( 'status' => 500 ) );
467
		}
468
469
		/**
470
		 * Fires after a single object is deleted or trashed via the REST API.
471
		 *
472
		 * @param WC_Data          $object   The deleted or trashed object.
473
		 * @param WP_REST_Response $response The response data.
474
		 * @param WP_REST_Request  $request  The request sent to the API.
475
		 */
476 8
		do_action( "woocommerce_rest_delete_{$this->post_type}_object", $object, $response, $request );
477
478 8
		return $response;
479
	}
480
481
	/**
482
	 * Prepare links for the request.
483
	 *
484
	 * @param WC_Data         $object  Object data.
485
	 * @param WP_REST_Request $request Request object.
486
	 * @return array                   Links for the given post.
487
	 */
488 12
	protected function prepare_links( $object, $request ) {
489
		$links = array(
490
			'self' => array(
491 12
				'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $object->get_id() ) ),
492
			),
493
			'collection' => array(
494 12
				'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
495
			),
496
		);
497
498 12
		return $links;
499
	}
500
501
	/**
502
	 * Get the query params for collections of attachments.
503
	 *
504
	 * @return array
505
	 */
506 426
	public function get_collection_params() {
507 426
		$params                       = array();
508 426
		$params['context']            = $this->get_context_param();
509 426
		$params['context']['default'] = 'view';
510
511 426
		$params['page'] = array(
512 426
			'description'        => __( 'Current page of the collection.', 'woocommerce' ),
513 426
			'type'               => 'integer',
514 426
			'default'            => 1,
515 426
			'sanitize_callback'  => 'absint',
516 426
			'validate_callback'  => 'rest_validate_request_arg',
517 426
			'minimum'            => 1,
518
		);
519 426
		$params['per_page'] = array(
520 426
			'description'        => __( 'Maximum number of items to be returned in result set.', 'woocommerce' ),
521 426
			'type'               => 'integer',
522 426
			'default'            => 10,
523 426
			'minimum'            => 1,
524 426
			'maximum'            => 100,
525 426
			'sanitize_callback'  => 'absint',
526 426
			'validate_callback'  => 'rest_validate_request_arg',
527
		);
528 426
		$params['search'] = array(
529 426
			'description'        => __( 'Limit results to those matching a string.', 'woocommerce' ),
530 426
			'type'               => 'string',
531 426
			'sanitize_callback'  => 'sanitize_text_field',
532 426
			'validate_callback'  => 'rest_validate_request_arg',
533
		);
534 426
		$params['after'] = array(
535 426
			'description'        => __( 'Limit response to resources published after a given ISO8601 compliant date.', 'woocommerce' ),
536 426
			'type'               => 'string',
537 426
			'format'             => 'date-time',
538 426
			'validate_callback'  => 'rest_validate_request_arg',
539
		);
540 426
		$params['before'] = array(
541 426
			'description'        => __( 'Limit response to resources published before a given ISO8601 compliant date.', 'woocommerce' ),
542 426
			'type'               => 'string',
543 426
			'format'             => 'date-time',
544 426
			'validate_callback'  => 'rest_validate_request_arg',
545
		);
546 426
		$params['exclude'] = array(
547 426
			'description'       => __( 'Ensure result set excludes specific IDs.', 'woocommerce' ),
548 426
			'type'              => 'array',
549
			'items'             => array(
550
				'type'          => 'integer',
551
			),
552
			'default'           => array(),
553 426
			'sanitize_callback' => 'wp_parse_id_list',
554
		);
555 426
		$params['include'] = array(
556 426
			'description'       => __( 'Limit result set to specific ids.', 'woocommerce' ),
557 426
			'type'              => 'array',
558
			'items'             => array(
559
				'type'          => 'integer',
560
			),
561
			'default'           => array(),
562 426
			'sanitize_callback' => 'wp_parse_id_list',
563
		);
564 426
		$params['offset'] = array(
565 426
			'description'        => __( 'Offset the result set by a specific number of items.', 'woocommerce' ),
566 426
			'type'               => 'integer',
567 426
			'sanitize_callback'  => 'absint',
568 426
			'validate_callback'  => 'rest_validate_request_arg',
569
		);
570 426
		$params['order'] = array(
571 426
			'description'        => __( 'Order sort attribute ascending or descending.', 'woocommerce' ),
572 426
			'type'               => 'string',
573 426
			'default'            => 'desc',
574
			'enum'               => array( 'asc', 'desc' ),
575 426
			'validate_callback'  => 'rest_validate_request_arg',
576
		);
577 426
		$params['orderby'] = array(
578 426
			'description'        => __( 'Sort collection by object attribute.', 'woocommerce' ),
579 426
			'type'               => 'string',
580 426
			'default'            => 'date',
581
			'enum'               => array(
582
				'date',
583
				'id',
584
				'include',
585
				'title',
586
				'slug',
587
			),
588 426
			'validate_callback'  => 'rest_validate_request_arg',
589
		);
590
591 426 View Code Duplication
		if ( $this->hierarchical ) {
592 426
			$params['parent'] = array(
593 426
				'description'       => __( 'Limit result set to those of particular parent IDs.', 'woocommerce' ),
594 426
				'type'              => 'array',
595
				'items'             => array(
596
					'type'          => 'integer',
597
				),
598 426
				'sanitize_callback' => 'wp_parse_id_list',
599
				'default'           => array(),
600
			);
601 426
			$params['parent_exclude'] = array(
602 426
				'description'       => __( 'Limit result set to all items except those of a particular parent ID.', 'woocommerce' ),
603 426
				'type'              => 'array',
604
				'items'             => array(
605
					'type'          => 'integer',
606
				),
607 426
				'sanitize_callback' => 'wp_parse_id_list',
608
				'default'           => array(),
609
			);
610
		}
611
612
		/**
613
		 * Filter collection parameters for the posts controller.
614
		 *
615
		 * The dynamic part of the filter `$this->post_type` refers to the post
616
		 * type slug for the controller.
617
		 *
618
		 * This filter registers the collection parameter, but does not map the
619
		 * collection parameter to an internal WP_Query parameter. Use the
620
		 * `rest_{$this->post_type}_query` filter to set WP_Query parameters.
621
		 *
622
		 * @param array        $query_params JSON Schema-formatted collection parameters.
623
		 * @param WP_Post_Type $post_type    Post type object.
624
		 */
625 426
		return apply_filters( "rest_{$this->post_type}_collection_params", $params, $this->post_type );
626
	}
627
}
628