GetPaid_REST_Posts_Controller   D
last analyzed

Complexity

Total Complexity 58

Size/Duplication

Total Lines 623
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 249
c 0
b 0
f 0
dl 0
loc 623
rs 4.5599
wmc 58

22 Methods

Rating   Name   Duplication   Size   Complexity  
A delete_item_permissions_check() 0 8 3
A batch_items_permissions_check() 0 2 2
A get_item() 0 11 3
A prepare_links() 0 26 5
A get_item_permissions_check() 0 8 3
A get_items_permissions_check() 0 2 2
A get_allowed_query_vars() 0 43 2
A create_item() 0 20 2
A delete_item() 0 23 5
A create_item_permissions_check() 0 2 2
A prepare_items_query() 0 21 6
B get_items() 0 84 9
A check_post_permissions() 0 15 1
A get_post() 0 2 1
A update_item_permissions_check() 0 8 3
A update_item() 0 20 2
A register_namespace_routes() 0 15 1
A sanitize_post_statuses() 0 2 1
A get_item_schema() 0 22 2
A get_post_statuses() 0 2 1
A object_supports_field() 0 3 1
B get_collection_params() 0 76 1

How to fix   Complexity   

Complex Class

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

1
<?php
2
/**
3
 * GetPaid REST Posts controller class.
4
 *
5
 * Extends the GetPaid_REST_CRUD_Controller class to provide functionalities for endpoints
6
 * that store CRUD data using CPTs
7
 *
8
 * @version 1.0.19
9
 */
10
11
defined( 'ABSPATH' ) || exit;
12
13
/**
14
 * GetPaid REST Posts controller class.
15
 *
16
 * @package Invoicing
17
 */
18
class GetPaid_REST_Posts_Controller extends GetPaid_REST_CRUD_Controller {
19
20
    /**
21
	 * Post type.
22
	 *
23
	 * @var string
24
	 */
25
	protected $post_type;
26
27
	/**
28
	 * Controls visibility on frontend.
29
	 *
30
	 * @var string
31
	 */
32
	public $public = false;
33
34
	/**
35
	 * Registers the routes for the objects of the controller.
36
	 *
37
	 * @since 1.0.19
38
	 *
39
	 * @see register_rest_route()
40
	 */
41
	public function register_namespace_routes( $namespace ) {
42
43
		parent::register_namespace_routes( $namespace );
44
45
		register_rest_route(
46
			$namespace,
47
			'/' . $this->rest_base . '/batch',
48
			array(
49
				array(
50
					'methods'             => WP_REST_Server::EDITABLE,
51
					'callback'            => array( $this, 'batch_items' ),
52
					'permission_callback' => array( $this, 'batch_items_permissions_check' ),
53
					'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
54
				),
55
				'schema' => array( $this, 'get_public_batch_schema' ),
56
			)
57
		);
58
59
	}
60
61
	/**
62
	 * Check permissions of items on REST API.
63
	 *
64
	 * @since 1.0.19
65
	 * @param string $context   Request context.
66
	 * @param int    $object_id Post ID.
67
	 * @return bool
68
	 */
69
	public function check_post_permissions( $context = 'read', $object_id = 0 ) {
70
71
		$contexts = array(
72
			'read'   => 'read_private_posts',
73
			'create' => 'publish_posts',
74
			'edit'   => 'edit_post',
75
			'delete' => 'delete_post',
76
			'batch'  => 'edit_others_posts',
77
		);
78
79
		$cap              = $contexts[ $context ];
80
		$post_type_object = get_post_type_object( $this->post_type );
81
		$permission       = current_user_can( $post_type_object->cap->$cap, $object_id );
82
83
		return apply_filters( 'getpaid_rest_check_permissions', $permission, $context, $object_id, $this->post_type );
84
	}
85
86
	/**
87
	 * Check if a given request has access to read items.
88
	 *
89
	 * @param  WP_REST_Request $request Full details about the request.
90
	 * @return WP_Error|boolean
91
	 */
92
	public function get_items_permissions_check( $request ) {
93
		return $this->check_post_permissions() ? true : new WP_Error( 'rest_cannot_view', __( 'Sorry, you cannot list resources.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
94
	}
95
96
	/**
97
	 * Check if a given request has access to create an item.
98
	 *
99
	 * @param  WP_REST_Request $request Full details about the request.
100
	 * @return WP_Error|boolean
101
	 */
102
	public function create_item_permissions_check( $request ) {
103
		return $this->check_post_permissions( 'create' ) ? true : new WP_Error( 'rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
104
	}
105
106
	/**
107
	 * Check if a given request has access to read an item.
108
	 *
109
	 * @param  WP_REST_Request $request Full details about the request.
110
	 * @return WP_Error|boolean
111
	 */
112
	public function get_item_permissions_check( $request ) {
113
		$post = get_post( (int) $request['id'] );
114
115
		if ( $post && ! $this->check_post_permissions( 'read', $post->ID ) ) {
116
			return new WP_Error( 'rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
117
		}
118
119
		return true;
120
	}
121
122
	/**
123
	 * Check if a given request has access to update an item.
124
	 *
125
	 * @param  WP_REST_Request $request Full details about the request.
126
	 * @return WP_Error|boolean
127
	 */
128
	public function update_item_permissions_check( $request ) {
129
		$post = get_post( (int) $request['id'] );
130
131
		if ( $post && ! $this->check_post_permissions( 'edit', $post->ID ) ) {
132
			return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
133
		}
134
135
		return true;
136
	}
137
138
	/**
139
	 * Check if a given request has access to delete an item.
140
	 *
141
	 * @param  WP_REST_Request $request Full details about the request.
142
	 * @return bool|WP_Error
143
	 */
144
	public function delete_item_permissions_check( $request ) {
145
		$post = get_post( (int) $request['id'] );
146
147
		if ( $post && ! $this->check_post_permissions( 'delete', $post->ID ) ) {
148
			return new WP_Error( 'rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
149
		}
150
151
		return true;
152
	}
153
154
	/**
155
	 * Check if a given request has access batch create, update and delete items.
156
	 *
157
	 * @param  WP_REST_Request $request Full details about the request.
158
	 *
159
	 * @return boolean|WP_Error
160
	 */
161
	public function batch_items_permissions_check( $request ) {
162
		return $this->check_post_permissions( 'batch' ) ? true : new WP_Error( 'rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
163
	}
164
165
	/**
166
	 * @deprecated
167
	 */
168
	public function get_post( $object_id ) {
169
		return $this->get_object( $object_id );
170
    }
171
172
	/**
173
	 * Get a single object.
174
	 *
175
	 * @param WP_REST_Request $request Full details about the request.
176
	 * @return WP_Error|WP_REST_Response
177
	 */
178
	public function get_item( $request ) {
179
180
		// Fetch item.
181
		$response = parent::get_item( $request );
182
183
		// (Maybe) add a link to the html pagee.
184
		if ( $this->public && ! is_wp_error( $response ) ) {
185
			$response->link_header( 'alternate', get_permalink( $this->data_object->get_id() ), array( 'type' => 'text/html' ) );
0 ignored issues
show
Bug introduced by
The method link_header() does not exist on WP_Error. ( Ignorable by Annotation )

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

185
			$response->/** @scrutinizer ignore-call */ 
186
              link_header( 'alternate', get_permalink( $this->data_object->get_id() ), array( 'type' => 'text/html' ) );

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...
Bug introduced by
It seems like get_permalink($this->data_object->get_id()) can also be of type false; however, parameter $link of WP_REST_Response::link_header() does only seem to accept string, 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

185
			$response->link_header( 'alternate', /** @scrutinizer ignore-type */ get_permalink( $this->data_object->get_id() ), array( 'type' => 'text/html' ) );
Loading history...
186
		}
187
188
		return $response;
189
	}
190
191
	/**
192
	 * Create a single object.
193
	 *
194
	 * @param WP_REST_Request $request Full details about the request.
195
	 * @return WP_Error|WP_REST_Response
196
	 */
197
	public function create_item( $request ) {
198
199
		// Create item.
200
		$response = parent::create_item( $request );
201
202
		// Fire a hook after an item is created.
203
		if ( ! is_wp_error( $response ) ) {
204
205
			/**
206
			 * Fires after a single item is created or updated via the REST API.
207
			 *
208
			 * @param WP_Post         $post      Post object.
209
			 * @param WP_REST_Request $request   Request object.
210
			 * @param boolean         $creating  True when creating item, false when updating.
211
			 */
212
			do_action( "getpaid_rest_insert_{$this->post_type}", $this->data_object, $request, true );
213
214
		}
215
216
		return $response;
217
218
	}
219
220
	/**
221
	 * Update a single object.
222
	 *
223
	 * @param WP_REST_Request $request Full details about the request.
224
	 * @return WP_Error|WP_REST_Response
225
	 */
226
	public function update_item( $request ) {
227
228
		// Create item.
229
		$response = parent::update_item( $request );
230
231
		// Fire a hook after an item is created.
232
		if ( ! is_wp_error( $response ) ) {
233
234
			/**
235
			 * Fires after a single item is created or updated via the REST API.
236
			 *
237
			 * @param WP_Post         $post      Post object.
238
			 * @param WP_REST_Request $request   Request object.
239
			 * @param boolean         $creating  True when creating item, false when updating.
240
			 */
241
			do_action( "getpaid_rest_insert_{$this->post_type}", $this->data_object, $request, false );
242
243
		}
244
245
		return $response;
246
247
	}
248
249
	/**
250
	 * Get a collection of objects.
251
	 *
252
	 * @param WP_REST_Request $request Full details about the request.
253
	 * @return WP_Error|WP_REST_Response
254
	 */
255
	public function get_items( $request ) {
256
257
		$args                         = array();
258
		$args['offset']               = $request['offset'];
259
		$args['order']                = $request['order'];
260
		$args['orderby']              = $request['orderby'];
261
		$args['paged']                = $request['page'];
262
		$args['post__in']             = $request['include'];
263
		$args['post__not_in']         = $request['exclude'];
264
		$args['posts_per_page']       = $request['per_page'];
265
		$args['name']                 = $request['slug'];
266
		$args['post_parent__in']      = $request['parent'];
267
		$args['post_parent__not_in']  = $request['parent_exclude'];
268
		$args['s']                    = $request['search'];
269
		$args['post_status']          = wpinv_parse_list( $request['status'] );
270
271
		$args['date_query'] = array();
272
273
		// Set before into date query. Date query must be specified as an array of an array.
274
		if ( isset( $request['before'] ) ) {
275
			$args['date_query'][0]['before'] = $request['before'];
276
		}
277
278
		// Set after into date query. Date query must be specified as an array of an array.
279
		if ( isset( $request['after'] ) ) {
280
			$args['date_query'][0]['after'] = $request['after'];
281
		}
282
283
		// Force the post_type & fields arguments, since they're not a user input variable.
284
		$args['post_type'] = $this->post_type;
285
		$args['fields']    = 'ids';
286
287
		// Filter the query arguments for a request.
288
		$args       = apply_filters( "getpaid_rest_{$this->post_type}_query", $args, $request );
289
		$query_args = $this->prepare_items_query( $args, $request );
290
291
		$posts_query = new WP_Query();
292
		$query_result = $posts_query->query( $query_args );
293
294
		$posts = array();
295
		foreach ( $query_result as $post_id ) {
296
			if ( ! $this->check_post_permissions( 'read', $post_id ) ) {
297
				continue;
298
			}
299
300
			$data    = $this->prepare_item_for_response( $this->get_object( $post_id ), $request );
0 ignored issues
show
Bug introduced by
$this->get_object($post_id) of type WP_Error is incompatible with the type GetPaid_Data expected by parameter $object of GetPaid_REST_CRUD_Contro...are_item_for_response(). ( Ignorable by Annotation )

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

300
			$data    = $this->prepare_item_for_response( /** @scrutinizer ignore-type */ $this->get_object( $post_id ), $request );
Loading history...
301
			$posts[] = $this->prepare_response_for_collection( $data );
302
		}
303
304
		$page        = (int) $query_args['paged'];
305
		$total_posts = $posts_query->found_posts;
306
307
		if ( $total_posts < 1 ) {
308
			// Out-of-bounds, run the query again without LIMIT for total count.
309
			unset( $query_args['paged'] );
310
			$count_query = new WP_Query();
311
			$count_query->query( $query_args );
312
			$total_posts = $count_query->found_posts;
313
		}
314
315
		$max_pages = ceil( $total_posts / (int) $query_args['posts_per_page'] );
316
317
		$response = rest_ensure_response( $posts );
318
		$response->header( 'X-WP-Total', (int) $total_posts );
319
		$response->header( 'X-WP-TotalPages', (int) $max_pages );
320
321
		$request_params = $request->get_query_params();
322
		$base = add_query_arg( $request_params, rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) );
323
324
		if ( $page > 1 ) {
325
			$prev_page = $page - 1;
326
			if ( $prev_page > $max_pages ) {
327
				$prev_page = $max_pages;
328
			}
329
			$prev_link = add_query_arg( 'page', $prev_page, $base );
330
			$response->link_header( 'prev', $prev_link );
331
		}
332
		if ( $max_pages > $page ) {
333
			$next_page = $page + 1;
334
			$next_link = add_query_arg( 'page', $next_page, $base );
335
			$response->link_header( 'next', $next_link );
336
		}
337
338
		return $response;
339
	}
340
341
	/**
342
	 * Delete a single item.
343
	 *
344
	 * @param WP_REST_Request $request Full details about the request.
345
	 * @return WP_REST_Response|WP_Error
346
	 */
347
	public function delete_item( $request ) {
348
349
		// Fetch the item.
350
		$item = $this->get_object( $request['id'] );
351
		if ( is_wp_error( $item ) ) {
352
			return $item;
353
		}
354
355
		$supports_trash = EMPTY_TRASH_DAYS > 0;
356
		$force          = $supports_trash && (bool) $request['force'];
357
358
		if ( ! $this->check_post_permissions( 'delete', $item->ID ) ) {
0 ignored issues
show
Bug introduced by
The property ID does not seem to exist on WP_Error.
Loading history...
359
			return new WP_Error( 'cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
360
		}
361
362
		$request->set_param( 'context', 'edit' );
363
		$response = $this->prepare_item_for_response( $item, $request );
0 ignored issues
show
Bug introduced by
$item of type WP_Error is incompatible with the type GetPaid_Data expected by parameter $object of GetPaid_REST_CRUD_Contro...are_item_for_response(). ( Ignorable by Annotation )

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

363
		$response = $this->prepare_item_for_response( /** @scrutinizer ignore-type */ $item, $request );
Loading history...
364
365
		if ( ! wp_delete_post( $item->ID, $force ) ) {
366
			return new WP_Error( 'rest_cannot_delete', sprintf( __( 'The resource cannot be deleted.', 'invoicing' ), $this->post_type ), array( 'status' => 500 ) );
367
		}
368
369
		return $response;
370
	}
371
372
	/**
373
	 * Prepare links for the request.
374
	 *
375
	 * @param GetPaid_Data    $object GetPaid_Data object.
376
	 * @return array Links for the given object.
377
	 */
378
	protected function prepare_links( $object ) {
379
380
		$links = parent::prepare_links( $object );
381
382
		if ( is_callable( array( $object, 'get_user_id' ) ) ) {
383
			$links['user'] = array(
384
				'href'       => rest_url( 'wp/v2/users/' . call_user_func( array( $object, 'get_user_id' ) ) ),
385
				'embeddable' => true,
386
			);
387
		}
388
389
		if ( is_callable( array( $object, 'get_owner' ) ) ) {
390
			$links['owner']  = array(
391
				'href'       => rest_url( 'wp/v2/users/' . call_user_func( array( $object, 'get_owner' ) ) ),
392
				'embeddable' => true,
393
			);
394
		}
395
396
		if ( is_callable( array( $object, 'get_parent_id' ) ) && call_user_func( array( $object, 'get_parent_id' ) ) ) {
397
			$links['parent']  = array(
398
				'href'       => rest_url( "$this->namespace/$this->rest_base/" . call_user_func( array( $object, 'get_parent_id' ) ) ),
399
				'embeddable' => true,
400
			);
401
		}
402
403
		return $links;
404
	}
405
406
	/**
407
	 * Determine the allowed query_vars for a get_items() response and
408
	 * prepare for WP_Query.
409
	 *
410
	 * @param array           $prepared_args Prepared arguments.
411
	 * @param WP_REST_Request $request Request object.
412
	 * @return array          $query_args
413
	 */
414
	protected function prepare_items_query( $prepared_args = array(), $request = null ) {
415
416
		$valid_vars = array_flip( $this->get_allowed_query_vars() );
417
		$query_args = array();
418
		foreach ( $valid_vars as $var => $index ) {
419
			if ( isset( $prepared_args[ $var ] ) ) {
420
				$query_args[ $var ] = apply_filters( "getpaid_rest_query_var-{$var}", $prepared_args[ $var ], $index );
421
			}
422
		}
423
424
		$query_args['ignore_sticky_posts'] = true;
425
426
		if ( 'include' === $query_args['orderby'] ) {
427
			$query_args['orderby'] = 'post__in';
428
		} elseif ( 'id' === $query_args['orderby'] ) {
429
			$query_args['orderby'] = 'ID'; // ID must be capitalized.
430
		} elseif ( 'slug' === $query_args['orderby'] ) {
431
			$query_args['orderby'] = 'name';
432
		}
433
434
		return apply_filters( 'getpaid_rest_prepare_items_query', $query_args, $request, $this );
435
436
	}
437
438
	/**
439
	 * Get all the WP Query vars that are allowed for the API request.
440
	 *
441
	 * @return array
442
	 */
443
	protected function get_allowed_query_vars() {
444
		global $wp;
445
446
		/**
447
		 * Filter the publicly allowed query vars.
448
		 *
449
		 * Allows adjusting of the default query vars that are made public.
450
		 *
451
		 * @param array  Array of allowed WP_Query query vars.
452
		 */
453
		$valid_vars = apply_filters( 'query_vars', $wp->public_query_vars );
454
455
		$post_type_obj = get_post_type_object( $this->post_type );
456
		if ( current_user_can( $post_type_obj->cap->edit_posts ) ) {
457
			$private = apply_filters( 'getpaid_rest_private_query_vars', $wp->private_query_vars );
458
			$valid_vars = array_merge( $valid_vars, $private );
459
		}
460
461
		// Define our own in addition to WP's normal vars.
462
		$rest_valid = array(
463
			'post_status',
464
			'date_query',
465
			'ignore_sticky_posts',
466
			'offset',
467
			'post__in',
468
			'post__not_in',
469
			'post_parent',
470
			'post_parent__in',
471
			'post_parent__not_in',
472
			'posts_per_page',
473
			'meta_query',
474
			'tax_query',
475
			'meta_key',
476
			'meta_value',
477
			'meta_compare',
478
			'meta_value_num',
479
		);
480
		$valid_vars = array_merge( $valid_vars, $rest_valid );
481
482
		// Filter allowed query vars for the REST API.
483
		$valid_vars = apply_filters( 'getpaid_rest_query_vars', $valid_vars, $this );
484
485
		return $valid_vars;
486
	}
487
488
	/**
489
	 * Get the query params for collections of attachments.
490
	 *
491
	 * @return array
492
	 */
493
	public function get_collection_params() {
494
495
		return array_merge(
496
			parent::get_collection_params(),
497
			array(
498
				'status'  => array(
499
					'default'           => $this->get_post_statuses(),
500
					'description'       => __( 'Limit result set to resources assigned one or more statuses.', 'invoicing' ),
501
					'type'              => array( 'array', 'string' ),
502
					'items'             => array(
503
						'enum' => $this->get_post_statuses(),
504
						'type' => 'string',
505
					),
506
					'validate_callback' => 'rest_validate_request_arg',
507
					'sanitize_callback' => array( $this, 'sanitize_post_statuses' ),
508
				),
509
				'after'   => array(
510
					'description'       => __( 'Limit response to resources created after a given ISO8601 compliant date.', 'invoicing' ),
511
					'type'              => 'string',
512
					'format'            => 'string',
513
					'validate_callback' => 'rest_validate_request_arg',
514
					'sanitize_callback' => 'sanitize_text_field',
515
				),
516
				'before'  => array(
517
					'description'       => __( 'Limit response to resources created before a given ISO8601 compliant date.', 'invoicing' ),
518
					'type'              => 'string',
519
					'format'            => 'string',
520
					'validate_callback' => 'rest_validate_request_arg',
521
					'sanitize_callback' => 'sanitize_text_field',
522
				),
523
				'exclude' => array(
524
					'description'       => __( 'Ensure result set excludes specific IDs.', 'invoicing' ),
525
					'type'              => 'array',
526
					'items'             => array(
527
						'type' => 'integer',
528
					),
529
					'default'           => array(),
530
					'sanitize_callback' => 'wp_parse_id_list',
531
					'validate_callback' => 'rest_validate_request_arg',
532
				),
533
				'include' => array(
534
					'description'       => __( 'Limit result set to specific ids.', 'invoicing' ),
535
					'type'              => 'array',
536
					'items'             => array(
537
						'type' => 'integer',
538
					),
539
					'default'           => array(),
540
					'sanitize_callback' => 'wp_parse_id_list',
541
					'validate_callback' => 'rest_validate_request_arg',
542
				),
543
				'offset'  => array(
544
					'description'       => __( 'Offset the result set by a specific number of items.', 'invoicing' ),
545
					'type'              => 'integer',
546
					'sanitize_callback' => 'absint',
547
					'validate_callback' => 'rest_validate_request_arg',
548
				),
549
				'order'   => array(
550
					'description'       => __( 'Order sort attribute ascending or descending.', 'invoicing' ),
551
					'type'              => 'string',
552
					'default'           => 'desc',
553
					'enum'              => array( 'asc', 'desc' ),
554
					'validate_callback' => 'rest_validate_request_arg',
555
				),
556
				'orderby' => array(
557
					'description'       => __( 'Sort collection by object attribute.', 'invoicing' ),
558
					'type'              => 'string',
559
					'default'           => 'date',
560
					'enum'              => array(
561
						'date',
562
						'id',
563
						'include',
564
						'title',
565
						'slug',
566
						'modified',
567
					),
568
					'validate_callback' => 'rest_validate_request_arg',
569
				),
570
			)
571
		);
572
	}
573
574
	/**
575
	 * Retrieves the items's schema, conforming to JSON Schema.
576
	 *
577
	 * @since 1.0.19
578
	 *
579
	 * @return array Item schema data.
580
	 */
581
	public function get_item_schema() {
582
583
		// Maybe retrieve the schema from cache.
584
		if ( ! empty( $this->schema ) ) {
585
			return $this->add_additional_fields_schema( $this->schema );
586
		}
587
588
		$type   = str_replace( 'wpi_', '', $this->post_type );
589
		$schema = array(
590
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
591
			'title'      => $this->post_type,
592
			'type'       => 'object',
593
			'properties' => wpinv_get_data( "$type-schema" ),
594
		);
595
596
		// Filters the invoice schema for the REST API.
597
        $schema = apply_filters( "wpinv_rest_{$type}_schema", $schema );
598
599
		// Cache the invoice schema.
600
		$this->schema = $schema;
601
602
		return $this->add_additional_fields_schema( $this->schema );
603
	}
604
605
	/**
606
	 * Sanitizes and validates the list of post statuses.
607
	 *
608
	 * @since 1.0.13
609
	 *
610
	 * @param string|array    $statuses  One or more post statuses.
611
	 * @param WP_REST_Request $request   Full details about the request.
612
	 * @param string          $parameter Additional parameter to pass to validation.
613
	 * @return array|WP_Error A list of valid statuses, otherwise WP_Error object.
614
	 */
615
	public function sanitize_post_statuses( $statuses, $request, $parameter ) {
616
		return array_intersect( wp_parse_slug_list( $statuses ), $this->get_post_statuses() );
617
	}
618
619
	/**
620
	 * Retrieves a valid list of post statuses.
621
	 *
622
	 * @since 1.0.19
623
	 *
624
	 * @return array A list of registered item statuses.
625
	 */
626
	public function get_post_statuses() {
627
		return get_post_stati();
628
	}
629
630
	/**
631
	 * Checks if a key should be included in a response.
632
	 *
633
	 * @since  1.0.19
634
	 * @param  GetPaid_Data $object  Data object.
635
	 * @param  string       $field_key The key to check for.
636
	 * @return bool
637
	 */
638
	public function object_supports_field( $object, $field_key ) {
639
		$supports = parent::object_supports_field( $object, $field_key );
640
		return apply_filters( "getpaid_rest_{$this->post_type}_object_supports_key", $supports, $object, $field_key );
641
	}
642
643
}
644