Issues (1182)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

includes/api/class-wc-rest-webhooks-controller.php (4 issues)

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
 * REST API Webhooks controller
4
 *
5
 * Handles requests to the /webhooks endpoint.
6
 *
7
 * @author   WooThemes
8
 * @category API
9
 * @package  WooCommerce/API
10
 * @since    2.6.0
11
 */
12
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * REST API Webhooks controller class.
19
 *
20
 * @package WooCommerce/API
21
 * @extends WC_REST_Posts_Controller
22
 */
23
class WC_REST_Webhooks_Controller extends WC_REST_Posts_Controller {
24
25
	/**
26
	 * Endpoint namespace.
27
	 *
28
	 * @var string
29
	 */
30
	protected $namespace = 'wc/v1';
31
32
	/**
33
	 * Route base.
34
	 *
35
	 * @var string
36
	 */
37
	protected $rest_base = 'webhooks';
38
39
	/**
40
	 * Post type.
41
	 *
42
	 * @var string
43
	 */
44
	protected $post_type = 'shop_webhook';
45
46
	/**
47
	 * Initialize Webhooks actions.
48
	 */
49
	public function __construct() {
50
		add_filter( "woocommerce_rest_{$this->post_type}_query", array( $this, 'query_args' ), 10, 2 );
51
	}
52
53
	/**
54
	 * Register the routes for webhooks.
55
	 */
56
	public function register_routes() {
57
		register_rest_route( $this->namespace, '/' . $this->rest_base, array(
58
			array(
59
				'methods'             => WP_REST_Server::READABLE,
60
				'callback'            => array( $this, 'get_items' ),
61
				'permission_callback' => array( $this, 'get_items_permissions_check' ),
62
				'args'                => $this->get_collection_params(),
63
			),
64
			array(
65
				'methods'             => WP_REST_Server::CREATABLE,
66
				'callback'            => array( $this, 'create_item' ),
67
				'permission_callback' => array( $this, 'create_item_permissions_check' ),
68
				'args'                => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array(
69
					'topic' => array(
70
						'required' => true,
71
					),
72
					'delivery_url' => array(
73
						'required' => true,
74
					),
75
				) ),
76
			),
77
			'schema' => array( $this, 'get_public_item_schema' ),
78
		) );
79
80
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array(
81
			array(
82
				'methods'             => WP_REST_Server::READABLE,
83
				'callback'            => array( $this, 'get_item' ),
84
				'permission_callback' => array( $this, 'get_item_permissions_check' ),
85
				'args'                => array(
86
					'context' => $this->get_context_param( array( 'default' => 'view' ) ),
87
				),
88
			),
89
			array(
90
				'methods'             => WP_REST_Server::EDITABLE,
91
				'callback'            => array( $this, 'update_item' ),
92
				'permission_callback' => array( $this, 'update_item_permissions_check' ),
93
				'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
94
			),
95
			array(
96
				'methods'             => WP_REST_Server::DELETABLE,
97
				'callback'            => array( $this, 'delete_item' ),
98
				'permission_callback' => array( $this, 'delete_item_permissions_check' ),
99
				'args'                => array(
100
					'force' => array(
101
						'default'     => false,
102
						'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce' ),
103
					),
104
				),
105
			),
106
			'schema' => array( $this, 'get_public_item_schema' ),
107
		) );
108
109
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array(
110
			array(
111
				'methods'             => WP_REST_Server::EDITABLE,
112
				'callback'            => array( $this, 'batch_items' ),
113
				'permission_callback' => array( $this, 'batch_items_permissions_check' ),
114
				'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
115
			),
116
			'schema' => array( $this, 'get_public_batch_schema' ),
117
		) );
118
	}
119
120
	/**
121
	 * Create a single webhook.
122
	 *
123
	 * @param WP_REST_Request $request Full details about the request.
124
	 * @return WP_Error|WP_REST_Response
125
	 */
126
	public function create_item( $request ) {
127
		if ( ! empty( $request['id'] ) ) {
128
			return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce' ), $this->post_type ), array( 'status' => 400 ) );
129
		}
130
131
		// Validate topic.
132
		if ( empty( $request['topic'] ) || ! wc_is_webhook_valid_topic( strtolower( $request['topic'] ) ) ) {
133
			return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_topic", __( 'Webhook topic is required and must be valid.', 'woocommerce' ), array( 'status' => 400 ) );
134
		}
135
136
		// Validate delivery URL.
137
		if ( empty( $request['delivery_url'] ) || ! wc_is_valid_url( $request['delivery_url'] ) ) {
138
			return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_delivery_url", __( 'Webhook delivery URL must be a valid URL starting with http:// or https://.', 'woocommerce' ), array( 'status' => 400 ) );
139
		}
140
141
		$post = $this->prepare_item_for_database( $request );
142
		if ( is_wp_error( $post ) ) {
143
			return $post;
144
		}
145
146
		$post->post_type = $this->post_type;
147
		$post_id = wp_insert_post( $post, true );
148
149 View Code Duplication
		if ( is_wp_error( $post_id ) ) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
150
151
			if ( in_array( $post_id->get_error_code(), array( 'db_insert_error' ) ) ) {
152
				$post_id->add_data( array( 'status' => 500 ) );
153
			} else {
154
				$post_id->add_data( array( 'status' => 400 ) );
155
			}
156
			return $post_id;
157
		}
158
		$post->ID = $post_id;
159
160
		$webhook = new WC_Webhook( $post_id );
161
162
		// Set topic.
163
		$webhook->set_topic( $request['topic'] );
164
165
		// Set delivery URL.
166
		$webhook->set_delivery_url( $request['delivery_url'] );
167
168
		// Set secret.
169
		$webhook->set_secret( ! empty( $request['secret'] ) ? $request['secret'] : wc_webhook_generate_secret() );
170
171
		// Set status.
172
		if ( ! empty( $request['status'] ) ) {
173
			$webhook->update_status( $request['status'] );
174
		}
175
176
		$post = get_post( $post_id );
177
		$this->update_additional_fields_for_object( $post, $request );
178
179
		/**
180
		 * Fires after a single item is created or updated via the REST API.
181
		 *
182
		 * @param WP_Post         $post      Inserted object.
183
		 * @param WP_REST_Request $request   Request object.
184
		 * @param boolean         $creating  True when creating item, false when updating.
185
		 */
186
		do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, true );
187
188
		$request->set_param( 'context', 'edit' );
189
		$response = $this->prepare_item_for_response( $post, $request );
190
		$response = rest_ensure_response( $response );
191
		$response->set_status( 201 );
192
		$response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $post_id ) ) );
193
194
		// Send ping.
195
		$webhook->deliver_ping();
196
197
		// Clear cache.
198
		delete_transient( 'woocommerce_webhook_ids' );
199
200
		return $response;
201
	}
202
203
	/**
204
	 * Update a single webhook.
205
	 *
206
	 * @param WP_REST_Request $request Full details about the request.
207
	 * @return WP_Error|WP_REST_Response
208
	 */
209
	public function update_item( $request ) {
210
		$id   = (int) $request['id'];
211
		$post = get_post( $id );
212
213
		if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
214
			return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce' ), array( 'status' => 400 ) );
215
		}
216
217
		$webhook = new WC_Webhook( $id );
218
219
		// Update topic.
220 View Code Duplication
		if ( ! empty( $request['topic'] ) ) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
221
			if ( wc_is_webhook_valid_topic( strtolower( $request['topic'] ) ) ) {
222
				$webhook->set_topic( $request['topic'] );
223
			} else {
224
				return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_topic", __( 'Webhook topic must be valid.', 'woocommerce' ), array( 'status' => 400 ) );
225
			}
226
		}
227
228
		// Update delivery URL.
229 View Code Duplication
		if ( ! empty( $request['delivery_url'] ) ) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
230
			if ( wc_is_valid_url( $request['delivery_url'] ) ) {
231
				$webhook->set_delivery_url( $request['delivery_url'] );
232
			} else {
233
				return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_delivery_url", __( 'Webhook delivery URL must be a valid URL starting with http:// or https://.', 'woocommerce' ), array( 'status' => 400 ) );
234
			}
235
		}
236
237
		// Update secret.
238
		if ( ! empty( $request['secret'] ) ) {
239
			$webhook->set_secret( $request['secret'] );
240
		}
241
242
		// Update status.
243
		if ( ! empty( $request['status'] ) ) {
244
			$webhook->update_status( $request['status'] );
245
		}
246
247
		$post = $this->prepare_item_for_database( $request );
248
		if ( is_wp_error( $post ) ) {
249
			return $post;
250
		}
251
252
		// Convert the post object to an array, otherwise wp_update_post will expect non-escaped input.
253
		$post_id = wp_update_post( (array) $post, true );
254 View Code Duplication
		if ( is_wp_error( $post_id ) ) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
255
			if ( in_array( $post_id->get_error_code(), array( 'db_update_error' ) ) ) {
256
				$post_id->add_data( array( 'status' => 500 ) );
257
			} else {
258
				$post_id->add_data( array( 'status' => 400 ) );
259
			}
260
			return $post_id;
261
		}
262
263
		$post = get_post( $post_id );
264
		$this->update_additional_fields_for_object( $post, $request );
265
266
		/**
267
		 * Fires after a single item is created or updated via the REST API.
268
		 *
269
		 * @param WP_Post         $post      Inserted object.
270
		 * @param WP_REST_Request $request   Request object.
271
		 * @param boolean         $creating  True when creating item, false when updating.
272
		 */
273
		do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, false );
274
275
		$request->set_param( 'context', 'edit' );
276
		$response = $this->prepare_item_for_response( $post, $request );
277
278
		// Clear cache.
279
		delete_transient( 'woocommerce_webhook_ids' );
280
281
		return rest_ensure_response( $response );
282
	}
283
284
	/**
285
	 * Delete a single webhook.
286
	 *
287
	 * @param WP_REST_Request $request Full details about the request.
288
	 * @return WP_REST_Response|WP_Error
289
	 */
290
	public function delete_item( $request ) {
291
		$id    = (int) $request['id'];
292
		$force = isset( $request['force'] ) ? (bool) $request['force'] : false;
293
294
		// We don't support trashing for this type, error out.
295
		if ( ! $force ) {
296
			return new WP_Error( 'woocommerce_rest_trash_not_supported', __( 'Webhooks do not support trashing.', 'woocommerce' ), array( 'status' => 501 ) );
297
		}
298
299
		$post = get_post( $id );
300
301
		if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
302
			return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid post id.', 'woocommerce' ), array( 'status' => 404 ) );
303
		}
304
305
		$request->set_param( 'context', 'edit' );
306
		$response = $this->prepare_item_for_response( $post, $request );
307
308
		$result = wp_delete_post( $id, true );
309
310
		if ( ! $result ) {
311
			return new WP_Error( 'woocommerce_rest_cannot_delete', sprintf( __( 'The %s cannot be deleted.', 'woocommerce' ), $this->post_type ), array( 'status' => 500 ) );
312
		}
313
314
		/**
315
		 * Fires after a single item is deleted or trashed via the REST API.
316
		 *
317
		 * @param object           $post     The deleted or trashed item.
318
		 * @param WP_REST_Response $response The response data.
319
		 * @param WP_REST_Request  $request  The request sent to the API.
320
		 */
321
		do_action( "woocommerce_rest_delete_{$this->post_type}", $post, $response, $request );
322
323
		// Clear cache.
324
		delete_transient( 'woocommerce_webhook_ids' );
325
326
		return $response;
327
	}
328
329
	/**
330
	 * Prepare a single webhook for create or update.
331
	 *
332
	 * @param WP_REST_Request $request Request object.
333
	 * @return WP_Error|stdClass $data Post object.
334
	 */
335
	protected function prepare_item_for_database( $request ) {
336
		global $wpdb;
337
338
		$data = new stdClass;
339
340
		// Post ID.
341
		if ( isset( $request['id'] ) ) {
342
			$data->ID = absint( $request['id'] );
343
		}
344
345
		// Validate required POST fields.
346
		if ( 'POST' === $request->get_method() && empty( $data->ID ) ) {
347
			$data->post_title = ! empty( $request['name'] ) ? $request['name'] : sprintf( __( 'Webhook created on %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Webhook created on date parsed by strftime', 'woocommerce' ) ) );
348
349
			// Post author.
350
			$data->post_author = get_current_user_id();
351
352
			// Post password.
353
			$password = strlen( uniqid( 'webhook_' ) );
354
			$data->post_password = $password > 20 ? substr( $password, 0, 20 ) : $password;
355
356
			// Post status.
357
			$data->post_status = 'publish';
358
		} else {
359
360
			// Allow edit post title.
361
			if ( ! empty( $request['name'] ) ) {
362
				$data->post_title = $request['name'];
363
			}
364
		}
365
366
		// Comment status.
367
		$data->comment_status = 'closed';
368
369
		// Ping status.
370
		$data->ping_status = 'closed';
371
372
		/**
373
		 * Filter the query_vars used in `get_items` for the constructed query.
374
		 *
375
		 * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being
376
		 * prepared for insertion.
377
		 *
378
		 * @param stdClass        $data An object representing a single item prepared
379
		 *                                       for inserting or updating the database.
380
		 * @param WP_REST_Request $request       Request object.
381
		 */
382
		return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}", $data, $request );
383
	}
384
385
	/**
386
	 * Prepare a single webhook output for response.
387
	 *
388
	 * @param WP_REST_Request $request Request object.
389
	 * @return WP_REST_Response $response Response data.
390
	 */
391
	public function prepare_item_for_response( $post, $request ) {
392
		$id      = (int) $post->ID;
393
		$webhook = new WC_Webhook( $id );
394
		$data    = array(
395
			'id'            => $webhook->id,
396
			'name'          => $webhook->get_name(),
397
			'status'        => $webhook->get_status(),
398
			'topic'         => $webhook->get_topic(),
399
			'resource'      => $webhook->get_resource(),
400
			'event'         => $webhook->get_event(),
401
			'hooks'         => $webhook->get_hooks(),
402
			'delivery_url'  => $webhook->get_delivery_url(),
403
			'date_created'  => wc_rest_prepare_date_response( $webhook->get_post_data()->post_date_gmt ),
404
			'date_modified' => wc_rest_prepare_date_response( $webhook->get_post_data()->post_modified_gmt ),
405
		);
406
407
		$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
408
		$data    = $this->add_additional_fields_to_object( $data, $request );
409
		$data    = $this->filter_response_by_context( $data, $context );
410
411
		// Wrap the data in a response object.
412
		$response = rest_ensure_response( $data );
413
414
		$response->add_links( $this->prepare_links( $post ) );
415
416
		/**
417
		 * Filter webhook object returned from the REST API.
418
		 *
419
		 * @param WP_REST_Response $response The response object.
420
		 * @param WC_Webhook       $webhook  Webhook object used to create response.
421
		 * @param WP_REST_Request  $request  Request object.
422
		 */
423
		return apply_filters( "woocommerce_rest_prepare_{$this->post_type}", $response, $webhook, $request );
424
	}
425
426
	/**
427
	 * Query args.
428
	 *
429
	 * @param array $args
430
	 * @param WP_REST_Request $request
431
	 * @return array
432
	 */
433
	public function query_args( $args, $request ) {
434
		// Set post_status.
435
		switch ( $request['status'] ) {
436
			case 'active' :
437
				$args['post_status'] = 'publish';
438
				break;
439
			case 'paused' :
440
				$args['post_status'] = 'draft';
441
				break;
442
			case 'disabled' :
443
				$args['post_status'] = 'pending';
444
				break;
445
			default :
446
				$args['post_status'] = 'any';
447
				break;
448
		}
449
450
		return $args;
451
	}
452
453
	/**
454
	 * Get the Webhook's schema, conforming to JSON Schema.
455
	 *
456
	 * @return array
457
	 */
458
	public function get_item_schema() {
459
		$schema = array(
460
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
461
			'title'      => 'webhook',
462
			'type'       => 'object',
463
			'properties' => array(
464
				'id' => array(
465
					'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
466
					'type'        => 'integer',
467
					'context'     => array( 'view', 'edit' ),
468
					'readonly'    => true,
469
				),
470
				'name' => array(
471
					'description' => __( 'A friendly name for the webhook.', 'woocommerce' ),
472
					'type'        => 'string',
473
					'context'     => array( 'view', 'edit' ),
474
				),
475
				'status' => array(
476
					'description' => __( 'Webhook status.', 'woocommerce' ),
477
					'type'        => 'string',
478
					'default'     => 'active',
479
					'enum'        => array( 'active', 'paused', 'disabled' ),
480
					'context'     => array( 'view', 'edit' ),
481
					'arg_options' => array(
482
						'sanitize_callback' => 'wc_is_webhook_valid_topic',
483
					),
484
				),
485
				'topic' => array(
486
					'description' => __( 'Webhook topic.', 'woocommerce' ),
487
					'type'        => 'string',
488
					'context'     => array( 'view', 'edit' ),
489
				),
490
				'resource' => array(
491
					'description' => __( 'Webhook resource.', 'woocommerce' ),
492
					'type'        => 'string',
493
					'context'     => array( 'view', 'edit' ),
494
					'readonly'    => true,
495
				),
496
				'event' => array(
497
					'description' => __( 'Webhook event.', 'woocommerce' ),
498
					'type'        => 'string',
499
					'context'     => array( 'view', 'edit' ),
500
					'readonly'    => true,
501
				),
502
				'hooks' => array(
503
					'description' => __( 'WooCommerce action names associated with the webhook.', 'woocommerce' ),
504
					'type'        => 'array',
505
					'context'     => array( 'view', 'edit' ),
506
					'readonly'    => true,
507
				),
508
				'delivery_url' => array(
509
					'description' => __( 'The URL where the webhook payload is delivered.', 'woocommerce' ),
510
					'type'        => 'string',
511
					'format'      => 'uri',
512
					'context'     => array( 'view', 'edit' ),
513
					'readonly'    => true,
514
				),
515
				'secret' => array(
516
					'description' => __( "Secret key used to generate a hash of the delivered webhook and provided in the request headers. This will default is a MD5 hash from the current user's ID|username if not provided.", 'woocommerce' ),
517
					'type'        => 'string',
518
					'format'      => 'uri',
519
					'context'     => array( 'edit' ),
520
				),
521
				'date_created' => array(
522
					'description' => __( "The date the webhook was created, in the site's timezone.", 'woocommerce' ),
523
					'type'        => 'date-time',
524
					'context'     => array( 'view', 'edit' ),
525
					'readonly'    => true,
526
				),
527
				'date_modified' => array(
528
					'description' => __( "The date the webhook was last modified, in the site's timezone.", 'woocommerce' ),
529
					'type'        => 'date-time',
530
					'context'     => array( 'view', 'edit' ),
531
					'readonly'    => true,
532
				),
533
			),
534
		);
535
536
		return $this->add_additional_fields_schema( $schema );
537
	}
538
539
	/**
540
	 * Get the query params for collections of attachments.
541
	 *
542
	 * @return array
543
	 */
544
	public function get_collection_params() {
545
		$params = parent::get_collection_params();
546
547
		$params['status'] = array(
548
			'default'           => 'all',
549
			'description'       => __( 'Limit result set to webhooks assigned a specific status.', 'woocommerce' ),
550
			'type'              => 'string',
551
			'enum'              => array( 'all', 'active', 'paused', 'disabled' ),
552
			'sanitize_callback' => 'sanitize_key',
553
			'validate_callback' => 'rest_validate_request_arg',
554
		);
555
556
		return $params;
557
	}
558
}
559