|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* REST API Items controller |
|
4
|
|
|
* |
|
5
|
|
|
* Handles requests to the invoices endpoint. |
|
6
|
|
|
* |
|
7
|
|
|
* @package Invoicing |
|
8
|
|
|
* @since 1.0.13 |
|
9
|
|
|
*/ |
|
10
|
|
|
|
|
11
|
|
|
if ( !defined( 'WPINC' ) ) { |
|
12
|
|
|
exit; |
|
13
|
|
|
} |
|
14
|
|
|
|
|
15
|
|
|
/** |
|
16
|
|
|
* REST API items controller class. |
|
17
|
|
|
* |
|
18
|
|
|
* @package Invoicing |
|
19
|
|
|
*/ |
|
20
|
|
|
class WPInv_REST_Items_Controller extends WP_REST_Posts_Controller { |
|
21
|
|
|
|
|
22
|
|
|
/** |
|
23
|
|
|
* Post type. |
|
24
|
|
|
* |
|
25
|
|
|
* @var string |
|
26
|
|
|
*/ |
|
27
|
|
|
protected $post_type = 'wpi_item'; |
|
28
|
|
|
|
|
29
|
|
|
/** |
|
30
|
|
|
* Cached results of get_item_schema. |
|
31
|
|
|
* |
|
32
|
|
|
* @since 1.0.13 |
|
33
|
|
|
* @var array |
|
34
|
|
|
*/ |
|
35
|
|
|
protected $schema; |
|
36
|
|
|
|
|
37
|
|
|
/** |
|
38
|
|
|
* Constructor. |
|
39
|
|
|
* |
|
40
|
|
|
* @since 1.0.13 |
|
41
|
|
|
* |
|
42
|
|
|
* @param string $namespace Api Namespace |
|
43
|
|
|
*/ |
|
44
|
|
|
public function __construct( $namespace ) { |
|
45
|
|
|
|
|
46
|
|
|
// Set api namespace... |
|
47
|
|
|
$this->namespace = $namespace; |
|
48
|
|
|
|
|
49
|
|
|
// ... and the rest base |
|
50
|
|
|
$this->rest_base = 'items'; |
|
51
|
|
|
|
|
52
|
|
|
} |
|
53
|
|
|
|
|
54
|
|
|
/** |
|
55
|
|
|
* Registers the routes for the objects of the controller. |
|
56
|
|
|
* |
|
57
|
|
|
* @since 1.0.13 |
|
58
|
|
|
* |
|
59
|
|
|
* @see register_rest_route() |
|
60
|
|
|
*/ |
|
61
|
|
|
public function register_routes() { |
|
62
|
|
|
|
|
63
|
|
|
parent::register_routes(); |
|
64
|
|
|
|
|
65
|
|
|
register_rest_route( |
|
66
|
|
|
$this->namespace, |
|
67
|
|
|
'/' . $this->rest_base . '/item-types', |
|
68
|
|
|
array( |
|
69
|
|
|
array( |
|
70
|
|
|
'methods' => WP_REST_Server::READABLE, |
|
71
|
|
|
'callback' => array( $this, 'get_item_types' ), |
|
72
|
|
|
), |
|
73
|
|
|
) |
|
74
|
|
|
); |
|
75
|
|
|
|
|
76
|
|
|
} |
|
77
|
|
|
|
|
78
|
|
|
/** |
|
79
|
|
|
* Checks if a given request has access to read items. |
|
80
|
|
|
* |
|
81
|
|
|
* |
|
82
|
|
|
* @since 1.0.13 |
|
83
|
|
|
* |
|
84
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
85
|
|
|
* @return true|WP_Error True if the request has read access, WP_Error object otherwise. |
|
86
|
|
|
*/ |
|
87
|
|
|
public function get_items_permissions_check( $request ) { |
|
88
|
|
|
|
|
89
|
|
|
if ( current_user_can( 'manage_options' ) || current_user_can( 'manage_invoicing' ) ) { |
|
90
|
|
|
return true; |
|
91
|
|
|
} |
|
92
|
|
|
|
|
93
|
|
|
return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to view invoice items.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) ); |
|
94
|
|
|
|
|
95
|
|
|
} |
|
96
|
|
|
|
|
97
|
|
|
/** |
|
98
|
|
|
* Retrieves a collection of invoice items. |
|
99
|
|
|
* |
|
100
|
|
|
* @since 1.0.13 |
|
101
|
|
|
* |
|
102
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
103
|
|
|
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
|
104
|
|
|
*/ |
|
105
|
|
View Code Duplication |
public function get_items( $request ) { |
|
|
|
|
|
|
106
|
|
|
|
|
107
|
|
|
// Retrieve the list of registered item query parameters. |
|
108
|
|
|
$registered = $this->get_collection_params(); |
|
109
|
|
|
|
|
110
|
|
|
$args = array(); |
|
111
|
|
|
|
|
112
|
|
|
foreach( array_keys( $registered ) as $key ) { |
|
113
|
|
|
|
|
114
|
|
|
if( isset( $request[ $key] ) ) { |
|
115
|
|
|
$args[ $key ] = $request[ $key]; |
|
116
|
|
|
} |
|
117
|
|
|
|
|
118
|
|
|
} |
|
119
|
|
|
|
|
120
|
|
|
/** |
|
121
|
|
|
* Filters the wpinv_get_items arguments for items rest requests. |
|
122
|
|
|
* |
|
123
|
|
|
* |
|
124
|
|
|
* @since 1.0.13 |
|
125
|
|
|
* |
|
126
|
|
|
* |
|
127
|
|
|
* @param array $args Key value array of query var to query value. |
|
128
|
|
|
* @param WP_REST_Request $request The request used. |
|
129
|
|
|
*/ |
|
130
|
|
|
$args = apply_filters( "wpinv_rest_get_items_arguments", $args, $request, $this ); |
|
131
|
|
|
|
|
132
|
|
|
// Special args |
|
133
|
|
|
$args[ 'return' ] = 'objects'; |
|
134
|
|
|
$args[ 'paginate' ] = true; |
|
135
|
|
|
|
|
136
|
|
|
// Run the query. |
|
137
|
|
|
$query = wpinv_get_all_items( $args ); |
|
138
|
|
|
|
|
139
|
|
|
// Prepare the retrieved items |
|
140
|
|
|
$items = array(); |
|
141
|
|
|
foreach( $query->items as $item ) { |
|
142
|
|
|
|
|
143
|
|
|
if ( ! $this->check_read_permission( $item ) ) { |
|
144
|
|
|
continue; |
|
145
|
|
|
} |
|
146
|
|
|
|
|
147
|
|
|
$data = $this->prepare_item_for_response( $item, $request ); |
|
148
|
|
|
$items[] = $this->prepare_response_for_collection( $data ); |
|
149
|
|
|
|
|
150
|
|
|
} |
|
151
|
|
|
|
|
152
|
|
|
// Prepare the response. |
|
153
|
|
|
$response = rest_ensure_response( $items ); |
|
154
|
|
|
$response->header( 'X-WP-Total', (int) $query->total ); |
|
155
|
|
|
$response->header( 'X-WP-TotalPages', (int) $query->max_num_pages ); |
|
156
|
|
|
|
|
157
|
|
|
/** |
|
158
|
|
|
* Filters the responses for item requests. |
|
159
|
|
|
* |
|
160
|
|
|
* |
|
161
|
|
|
* @since 1.0.13 |
|
162
|
|
|
* |
|
163
|
|
|
* |
|
164
|
|
|
* @param arrWP_REST_Response $response Response object. |
|
165
|
|
|
* @param WP_REST_Request $request The request used. |
|
166
|
|
|
* @param array $args Array of args used to retrieve the items |
|
167
|
|
|
*/ |
|
168
|
|
|
$response = apply_filters( "wpinv_rest_items_response", $response, $request, $args ); |
|
169
|
|
|
|
|
170
|
|
|
return rest_ensure_response( $response ); |
|
171
|
|
|
|
|
172
|
|
|
} |
|
173
|
|
|
|
|
174
|
|
|
/** |
|
175
|
|
|
* Get the post, if the ID is valid. |
|
176
|
|
|
* |
|
177
|
|
|
* @since 1.0.13 |
|
178
|
|
|
* |
|
179
|
|
|
* @param int $item_id Supplied ID. |
|
180
|
|
|
* @return WPInv_Item|WP_Error Item object if ID is valid, WP_Error otherwise. |
|
181
|
|
|
*/ |
|
182
|
|
View Code Duplication |
protected function get_post( $item_id ) { |
|
|
|
|
|
|
183
|
|
|
|
|
184
|
|
|
$error = new WP_Error( 'rest_item_invalid_id', __( 'Invalid item ID.', 'invoicing' ), array( 'status' => 404 ) ); |
|
185
|
|
|
|
|
186
|
|
|
// Ids start from 1 |
|
187
|
|
|
if ( (int) $item_id <= 0 ) { |
|
188
|
|
|
return $error; |
|
189
|
|
|
} |
|
190
|
|
|
|
|
191
|
|
|
$item = wpinv_get_item_by( 'id', (int) $item_id ); |
|
192
|
|
|
if ( empty( $item ) ) { |
|
193
|
|
|
return $error; |
|
194
|
|
|
} |
|
195
|
|
|
|
|
196
|
|
|
return $item; |
|
197
|
|
|
|
|
198
|
|
|
} |
|
199
|
|
|
|
|
200
|
|
|
/** |
|
201
|
|
|
* Checks if a given request has access to read an invoice item. |
|
202
|
|
|
* |
|
203
|
|
|
* @since 1.0.13 |
|
204
|
|
|
* |
|
205
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
206
|
|
|
* @return bool|WP_Error True if the request has read access for the invoice item, WP_Error object otherwise. |
|
207
|
|
|
*/ |
|
208
|
|
View Code Duplication |
public function get_item_permissions_check( $request ) { |
|
|
|
|
|
|
209
|
|
|
|
|
210
|
|
|
// Retrieve the item object. |
|
211
|
|
|
$item = $this->get_post( $request['id'] ); |
|
212
|
|
|
|
|
213
|
|
|
// Ensure it is valid. |
|
214
|
|
|
if ( is_wp_error( $item ) ) { |
|
215
|
|
|
return $item; |
|
216
|
|
|
} |
|
217
|
|
|
|
|
218
|
|
|
$post_type = get_post_type_object( $this->post_type ); |
|
219
|
|
|
|
|
220
|
|
|
if ( ! current_user_can( $post_type->cap->read_post, $item->ID ) ) { |
|
221
|
|
|
return new WP_Error( |
|
222
|
|
|
'rest_cannot_edit', |
|
223
|
|
|
__( 'Sorry, you are not allowed to view this item.', 'invoicing' ), |
|
224
|
|
|
array( |
|
225
|
|
|
'status' => rest_authorization_required_code(), |
|
226
|
|
|
) |
|
227
|
|
|
); |
|
228
|
|
|
} |
|
229
|
|
|
|
|
230
|
|
|
return $this->check_read_permission( $item ); |
|
231
|
|
|
} |
|
232
|
|
|
|
|
233
|
|
|
/** |
|
234
|
|
|
* Checks if an item can be read. |
|
235
|
|
|
* |
|
236
|
|
|
* An item can be read by site admins. |
|
237
|
|
|
* |
|
238
|
|
|
* |
|
239
|
|
|
* @since 1.0.13 |
|
240
|
|
|
* |
|
241
|
|
|
* @param WPInv_Item $item WPInv_Item object. |
|
242
|
|
|
* @return bool Whether the post can be read. |
|
243
|
|
|
*/ |
|
244
|
|
|
public function check_read_permission( $item ) { |
|
245
|
|
|
|
|
246
|
|
|
// An item can be read by an admin... |
|
247
|
|
|
if ( current_user_can( 'manage_options' ) || current_user_can( 'manage_invoicing' ) ) { |
|
248
|
|
|
return true; |
|
249
|
|
|
} |
|
250
|
|
|
|
|
251
|
|
|
return false; |
|
252
|
|
|
} |
|
253
|
|
|
|
|
254
|
|
|
/** |
|
255
|
|
|
* Retrieves a single invoice item. |
|
256
|
|
|
* |
|
257
|
|
|
* @since 1.0.13 |
|
258
|
|
|
* |
|
259
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
260
|
|
|
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
|
261
|
|
|
*/ |
|
262
|
|
|
public function get_item( $request ) { |
|
263
|
|
|
|
|
264
|
|
|
// Fetch the item. |
|
265
|
|
|
$item = $this->get_post( $request['id'] ); |
|
|
|
|
|
|
266
|
|
|
|
|
267
|
|
|
// Abort early if it does not exist |
|
268
|
|
|
if ( is_wp_error( $item ) ) { |
|
269
|
|
|
return $item; |
|
270
|
|
|
} |
|
271
|
|
|
|
|
272
|
|
|
// Prepare the response |
|
273
|
|
|
$response = $this->prepare_item_for_response( $item, $request ); |
|
274
|
|
|
|
|
275
|
|
|
/** |
|
276
|
|
|
* Filters the responses for single invoice item requests. |
|
277
|
|
|
* |
|
278
|
|
|
* |
|
279
|
|
|
* @since 1.0.13 |
|
280
|
|
|
* @var WP_HTTP_Response |
|
281
|
|
|
* |
|
282
|
|
|
* @param WP_HTTP_Response $response Response. |
|
283
|
|
|
* @param WP_REST_Request $request The request used. |
|
284
|
|
|
*/ |
|
285
|
|
|
$response = apply_filters( "wpinv_rest_get_item_response", $response, $request ); |
|
286
|
|
|
|
|
287
|
|
|
return rest_ensure_response( $response ); |
|
288
|
|
|
|
|
289
|
|
|
} |
|
290
|
|
|
|
|
291
|
|
|
/** |
|
292
|
|
|
* Checks if a given request has access to create an invoice item. |
|
293
|
|
|
* |
|
294
|
|
|
* @since 1.0.13 |
|
295
|
|
|
* |
|
296
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
297
|
|
|
* @return true|WP_Error True if the request has access to create items, WP_Error object otherwise. |
|
298
|
|
|
*/ |
|
299
|
|
|
public function create_item_permissions_check( $request ) { |
|
300
|
|
|
|
|
301
|
|
|
if ( ! empty( $request['id'] ) ) { |
|
302
|
|
|
return new WP_Error( 'rest_item_exists', __( 'Cannot create existing item.', 'invoicing' ), array( 'status' => 400 ) ); |
|
303
|
|
|
} |
|
304
|
|
|
|
|
305
|
|
|
if ( current_user_can( 'manage_options' ) || current_user_can( 'manage_invoicing' ) ) { |
|
306
|
|
|
return true; |
|
307
|
|
|
} |
|
308
|
|
|
|
|
309
|
|
|
$post_type = get_post_type_object( $this->post_type ); |
|
310
|
|
|
if ( ! current_user_can( $post_type->cap->create_posts ) ) { |
|
311
|
|
|
return new WP_Error( |
|
312
|
|
|
'rest_cannot_create', |
|
313
|
|
|
__( 'Sorry, you are not allowed to create invoice items as this user.', 'invoicing' ), |
|
314
|
|
|
array( |
|
315
|
|
|
'status' => rest_authorization_required_code(), |
|
316
|
|
|
) |
|
317
|
|
|
); |
|
318
|
|
|
} |
|
319
|
|
|
|
|
320
|
|
|
return true; |
|
321
|
|
|
} |
|
322
|
|
|
|
|
323
|
|
|
/** |
|
324
|
|
|
* Creates a single invoice item. |
|
325
|
|
|
* |
|
326
|
|
|
* @since 1.0.13 |
|
327
|
|
|
* |
|
328
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
329
|
|
|
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
|
330
|
|
|
*/ |
|
331
|
|
View Code Duplication |
public function create_item( $request ) { |
|
|
|
|
|
|
332
|
|
|
|
|
333
|
|
|
if ( ! empty( $request['id'] ) ) { |
|
334
|
|
|
return new WP_Error( 'rest_item_exists', __( 'Cannot create existing invoice item.', 'invoicing' ), array( 'status' => 400 ) ); |
|
335
|
|
|
} |
|
336
|
|
|
|
|
337
|
|
|
$request->set_param( 'context', 'edit' ); |
|
338
|
|
|
|
|
339
|
|
|
// Prepare the updated data. |
|
340
|
|
|
$item_data = $this->prepare_item_for_database( $request ); |
|
|
|
|
|
|
341
|
|
|
|
|
342
|
|
|
if ( is_wp_error( $item_data ) ) { |
|
343
|
|
|
return $item_data; |
|
344
|
|
|
} |
|
345
|
|
|
|
|
346
|
|
|
// Try creating the item. |
|
347
|
|
|
$item = wpinv_create_item( $item_data, true ); |
|
348
|
|
|
|
|
349
|
|
|
if ( is_wp_error( $item ) ) { |
|
350
|
|
|
return $item; |
|
351
|
|
|
} |
|
352
|
|
|
|
|
353
|
|
|
// Prepare the response |
|
354
|
|
|
$response = $this->prepare_item_for_response( $item, $request ); |
|
355
|
|
|
|
|
356
|
|
|
/** |
|
357
|
|
|
* Fires after a single invoice item is created or updated via the REST API. |
|
358
|
|
|
* |
|
359
|
|
|
* @since 1.0.13 |
|
360
|
|
|
* |
|
361
|
|
|
* @param WPinv_Item $item Inserted or updated item object. |
|
362
|
|
|
* @param WP_REST_Request $request Request object. |
|
363
|
|
|
* @param bool $creating True when creating a post, false when updating. |
|
364
|
|
|
*/ |
|
365
|
|
|
do_action( "wpinv_rest_insert_item", $item, $request, true ); |
|
366
|
|
|
|
|
367
|
|
|
/** |
|
368
|
|
|
* Filters the responses for creating single item requests. |
|
369
|
|
|
* |
|
370
|
|
|
* |
|
371
|
|
|
* @since 1.0.13 |
|
372
|
|
|
* |
|
373
|
|
|
* |
|
374
|
|
|
* @param array $item_data Invoice properties. |
|
375
|
|
|
* @param WP_REST_Request $request The request used. |
|
376
|
|
|
*/ |
|
377
|
|
|
$response = apply_filters( "wpinv_rest_create_item_response", $response, $request ); |
|
378
|
|
|
|
|
379
|
|
|
return rest_ensure_response( $response ); |
|
380
|
|
|
} |
|
381
|
|
|
|
|
382
|
|
|
/** |
|
383
|
|
|
* Checks if a given request has access to update an item. |
|
384
|
|
|
* |
|
385
|
|
|
* @since 1.0.13 |
|
386
|
|
|
* |
|
387
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
388
|
|
|
* @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise. |
|
389
|
|
|
*/ |
|
390
|
|
View Code Duplication |
public function update_item_permissions_check( $request ) { |
|
|
|
|
|
|
391
|
|
|
|
|
392
|
|
|
// Retrieve the item. |
|
393
|
|
|
$item = $this->get_post( $request['id'] ); |
|
394
|
|
|
if ( is_wp_error( $item ) ) { |
|
395
|
|
|
return $item; |
|
396
|
|
|
} |
|
397
|
|
|
|
|
398
|
|
|
if ( current_user_can( 'manage_options' ) || current_user_can( 'manage_invoicing' ) ) { |
|
399
|
|
|
return true; |
|
400
|
|
|
} |
|
401
|
|
|
|
|
402
|
|
|
return new WP_Error( |
|
403
|
|
|
'rest_cannot_edit', |
|
404
|
|
|
__( 'Sorry, you are not allowed to update this item.', 'invoicing' ), |
|
405
|
|
|
array( |
|
406
|
|
|
'status' => rest_authorization_required_code(), |
|
407
|
|
|
) |
|
408
|
|
|
); |
|
409
|
|
|
|
|
410
|
|
|
} |
|
411
|
|
|
|
|
412
|
|
|
/** |
|
413
|
|
|
* Updates a single item. |
|
414
|
|
|
* |
|
415
|
|
|
* @since 1.0.13 |
|
416
|
|
|
* |
|
417
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
418
|
|
|
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
|
419
|
|
|
*/ |
|
420
|
|
View Code Duplication |
public function update_item( $request ) { |
|
|
|
|
|
|
421
|
|
|
|
|
422
|
|
|
// Ensure the item exists. |
|
423
|
|
|
$valid_check = $this->get_post( $request['id'] ); |
|
|
|
|
|
|
424
|
|
|
|
|
425
|
|
|
// Abort early if it does not exist |
|
426
|
|
|
if ( is_wp_error( $valid_check ) ) { |
|
427
|
|
|
return $valid_check; |
|
428
|
|
|
} |
|
429
|
|
|
|
|
430
|
|
|
$request->set_param( 'context', 'edit' ); |
|
431
|
|
|
|
|
432
|
|
|
// Prepare the updated data. |
|
433
|
|
|
$data_to_update = $this->prepare_item_for_database( $request ); |
|
|
|
|
|
|
434
|
|
|
|
|
435
|
|
|
if ( is_wp_error( $data_to_update ) ) { |
|
436
|
|
|
return $data_to_update; |
|
437
|
|
|
} |
|
438
|
|
|
|
|
439
|
|
|
// Abort if no item data is provided |
|
440
|
|
|
if( empty( $data_to_update ) ) { |
|
441
|
|
|
return new WP_Error( 'missing_data', __( 'An update request cannot be empty.', 'invoicing' ) ); |
|
442
|
|
|
} |
|
443
|
|
|
|
|
444
|
|
|
// Include the item ID |
|
445
|
|
|
$data_to_update['ID'] = $request['id']; |
|
446
|
|
|
|
|
447
|
|
|
// Update the item |
|
448
|
|
|
$updated_item = wpinv_update_item( $data_to_update, true ); |
|
449
|
|
|
|
|
450
|
|
|
// Incase the update operation failed... |
|
451
|
|
|
if ( is_wp_error( $updated_item ) ) { |
|
452
|
|
|
return $updated_item; |
|
453
|
|
|
} |
|
454
|
|
|
|
|
455
|
|
|
// Prepare the response |
|
456
|
|
|
$response = $this->prepare_item_for_response( $updated_item, $request ); |
|
457
|
|
|
|
|
458
|
|
|
/** This action is documented in includes/class-wpinv-rest-item-controller.php */ |
|
459
|
|
|
do_action( "wpinv_rest_insert_item", $updated_item, $request, false ); |
|
460
|
|
|
|
|
461
|
|
|
/** |
|
462
|
|
|
* Filters the responses for updating single item requests. |
|
463
|
|
|
* |
|
464
|
|
|
* |
|
465
|
|
|
* @since 1.0.13 |
|
466
|
|
|
* |
|
467
|
|
|
* |
|
468
|
|
|
* @param array $item_data Item properties. |
|
469
|
|
|
* @param WP_REST_Request $request The request used. |
|
470
|
|
|
*/ |
|
471
|
|
|
$response = apply_filters( "wpinv_rest_update_item_response", $response, $data_to_update, $request ); |
|
472
|
|
|
|
|
473
|
|
|
return rest_ensure_response( $response ); |
|
474
|
|
|
} |
|
475
|
|
|
|
|
476
|
|
|
/** |
|
477
|
|
|
* Checks if a given request has access to delete an item. |
|
478
|
|
|
* |
|
479
|
|
|
* @since 1.0.13 |
|
480
|
|
|
* |
|
481
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
482
|
|
|
* @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. |
|
483
|
|
|
*/ |
|
484
|
|
View Code Duplication |
public function delete_item_permissions_check( $request ) { |
|
|
|
|
|
|
485
|
|
|
|
|
486
|
|
|
// Retrieve the item. |
|
487
|
|
|
$item = $this->get_post( $request['id'] ); |
|
488
|
|
|
if ( is_wp_error( $item ) ) { |
|
489
|
|
|
return $item; |
|
490
|
|
|
} |
|
491
|
|
|
|
|
492
|
|
|
// |
|
493
|
|
|
|
|
494
|
|
|
// Ensure the current user can delete the item |
|
495
|
|
|
if (! wpinv_can_delete_item( $request['id'] ) ) { |
|
496
|
|
|
return new WP_Error( |
|
497
|
|
|
'rest_cannot_delete', |
|
498
|
|
|
__( 'Sorry, you are not allowed to delete this item.', 'invoicing' ), |
|
499
|
|
|
array( |
|
500
|
|
|
'status' => rest_authorization_required_code(), |
|
501
|
|
|
) |
|
502
|
|
|
); |
|
503
|
|
|
} |
|
504
|
|
|
|
|
505
|
|
|
return true; |
|
506
|
|
|
} |
|
507
|
|
|
|
|
508
|
|
|
/** |
|
509
|
|
|
* Deletes a single item. |
|
510
|
|
|
* |
|
511
|
|
|
* @since 1.0.13 |
|
512
|
|
|
* |
|
513
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
514
|
|
|
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
|
515
|
|
|
*/ |
|
516
|
|
View Code Duplication |
public function delete_item( $request ) { |
|
|
|
|
|
|
517
|
|
|
|
|
518
|
|
|
// Retrieve the item. |
|
519
|
|
|
$item = $this->get_post( $request['id'] ); |
|
520
|
|
|
if ( is_wp_error( $item ) ) { |
|
521
|
|
|
return $item; |
|
522
|
|
|
} |
|
523
|
|
|
|
|
524
|
|
|
$request->set_param( 'context', 'edit' ); |
|
525
|
|
|
|
|
526
|
|
|
// Prepare the item id |
|
527
|
|
|
$id = $item->ID; |
|
528
|
|
|
|
|
529
|
|
|
// Prepare the response |
|
530
|
|
|
$response = $this->prepare_item_for_response( $item, $request ); |
|
531
|
|
|
|
|
532
|
|
|
// Check if the user wants to bypass the trash... |
|
533
|
|
|
$force_delete = (bool) $request['force']; |
|
534
|
|
|
|
|
535
|
|
|
// Try deleting the item. |
|
536
|
|
|
$deleted = wp_delete_post( $id, $force_delete ); |
|
537
|
|
|
|
|
538
|
|
|
// Abort early if we can't delete the item. |
|
539
|
|
|
if ( ! $deleted ) { |
|
540
|
|
|
return new WP_Error( 'rest_cannot_delete', __( 'The item cannot be deleted.', 'invoicing' ), array( 'status' => 500 ) ); |
|
541
|
|
|
} |
|
542
|
|
|
|
|
543
|
|
|
/** |
|
544
|
|
|
* Fires immediately after a single item is deleted or trashed via the REST API. |
|
545
|
|
|
* |
|
546
|
|
|
* |
|
547
|
|
|
* @since 1.0.13 |
|
548
|
|
|
* |
|
549
|
|
|
* @param WPInv_Item $item The deleted or trashed item. |
|
550
|
|
|
* @param WP_REST_Request $request The request sent to the API. |
|
551
|
|
|
*/ |
|
552
|
|
|
do_action( "wpinv_rest_delete_item", $item, $request ); |
|
553
|
|
|
|
|
554
|
|
|
return $response; |
|
555
|
|
|
|
|
556
|
|
|
} |
|
557
|
|
|
|
|
558
|
|
|
|
|
559
|
|
|
/** |
|
560
|
|
|
* Retrieves the query params for the items collection. |
|
561
|
|
|
* |
|
562
|
|
|
* @since 1.0.13 |
|
563
|
|
|
* |
|
564
|
|
|
* @return array Collection parameters. |
|
565
|
|
|
*/ |
|
566
|
|
|
public function get_collection_params() { |
|
567
|
|
|
|
|
568
|
|
|
$query_params = array( |
|
569
|
|
|
|
|
570
|
|
|
// Invoice status. |
|
571
|
|
|
'status' => array( |
|
572
|
|
|
'default' => 'publish', |
|
573
|
|
|
'description' => __( 'Limit result set to items assigned one or more statuses.', 'invoicing' ), |
|
574
|
|
|
'type' => 'array', |
|
575
|
|
|
'sanitize_callback' => array( $this, 'sanitize_post_statuses' ), |
|
576
|
|
|
), |
|
577
|
|
|
|
|
578
|
|
|
// Item types |
|
579
|
|
|
'type' => array( |
|
580
|
|
|
'description' => __( 'Type of items to fetch.', 'invoicing' ), |
|
581
|
|
|
'type' => 'array', |
|
582
|
|
|
'default' => wpinv_item_types(), |
|
583
|
|
|
'items' => array( |
|
584
|
|
|
'enum' => wpinv_item_types(), |
|
585
|
|
|
'type' => 'string', |
|
586
|
|
|
), |
|
587
|
|
|
), |
|
588
|
|
|
|
|
589
|
|
|
// Number of results per page |
|
590
|
|
|
'limit' => array( |
|
591
|
|
|
'description' => __( 'Number of items to fetch.', 'invoicing' ), |
|
592
|
|
|
'type' => 'integer', |
|
593
|
|
|
'default' => (int) get_option( 'posts_per_page' ), |
|
594
|
|
|
), |
|
595
|
|
|
|
|
596
|
|
|
// Pagination |
|
597
|
|
|
'page' => array( |
|
598
|
|
|
'description' => __( 'Current page to fetch.', 'invoicing' ), |
|
599
|
|
|
'type' => 'integer', |
|
600
|
|
|
'default' => 1, |
|
601
|
|
|
), |
|
602
|
|
|
|
|
603
|
|
|
// Exclude certain items |
|
604
|
|
|
'exclude' => array( |
|
605
|
|
|
'description' => __( 'Ensure result set excludes specific IDs.', 'invoicing' ), |
|
606
|
|
|
'type' => 'array', |
|
607
|
|
|
'items' => array( |
|
608
|
|
|
'type' => 'integer', |
|
609
|
|
|
), |
|
610
|
|
|
'default' => array(), |
|
611
|
|
|
), |
|
612
|
|
|
|
|
613
|
|
|
// Order items by |
|
614
|
|
|
'orderby' => array( |
|
615
|
|
|
'description' => __( 'Sort items by object attribute.', 'invoicing' ), |
|
616
|
|
|
'type' => 'string', |
|
617
|
|
|
'default' => 'date', |
|
618
|
|
|
'enum' => array( |
|
619
|
|
|
'author', |
|
620
|
|
|
'date', |
|
621
|
|
|
'ID', |
|
622
|
|
|
'modified', |
|
623
|
|
|
'title', |
|
624
|
|
|
'relevance', |
|
625
|
|
|
'rand' |
|
626
|
|
|
), |
|
627
|
|
|
), |
|
628
|
|
|
|
|
629
|
|
|
// How to order |
|
630
|
|
|
'order' => array( |
|
631
|
|
|
'description' => __( 'Order sort attribute ascending or descending.', 'invoicing' ), |
|
632
|
|
|
'type' => 'string', |
|
633
|
|
|
'default' => 'DESC', |
|
634
|
|
|
'enum' => array( 'ASC', 'DESC' ), |
|
635
|
|
|
), |
|
636
|
|
|
|
|
637
|
|
|
// Search term |
|
638
|
|
|
'search' => array( |
|
639
|
|
|
'description' => __( 'Return items that match the search term.', 'invoicing' ), |
|
640
|
|
|
'type' => 'string', |
|
641
|
|
|
), |
|
642
|
|
|
); |
|
643
|
|
|
|
|
644
|
|
|
/** |
|
645
|
|
|
* Filter collection parameters for the items controller. |
|
646
|
|
|
* |
|
647
|
|
|
* |
|
648
|
|
|
* @since 1.0.13 |
|
649
|
|
|
* |
|
650
|
|
|
* @param array $query_params JSON Schema-formatted collection parameters. |
|
651
|
|
|
*/ |
|
652
|
|
|
return apply_filters( "wpinv_rest_items_collection_params", $query_params ); |
|
653
|
|
|
} |
|
654
|
|
|
|
|
655
|
|
|
/** |
|
656
|
|
|
* Checks if a given post type can be viewed or managed. |
|
657
|
|
|
* |
|
658
|
|
|
* @since 1.0.13 |
|
659
|
|
|
* |
|
660
|
|
|
* @param object|string $post_type Post type name or object. |
|
661
|
|
|
* @return bool Whether the post type is allowed in REST. |
|
662
|
|
|
*/ |
|
663
|
|
|
protected function check_is_post_type_allowed( $post_type ) { |
|
664
|
|
|
return true; |
|
665
|
|
|
} |
|
666
|
|
|
|
|
667
|
|
|
/** |
|
668
|
|
|
* Prepares a single item for create or update. |
|
669
|
|
|
* |
|
670
|
|
|
* @since 1.0.13 |
|
671
|
|
|
* |
|
672
|
|
|
* @param WP_REST_Request $request Request object. |
|
673
|
|
|
* @return array|WP_Error Invoice Properties or WP_Error. |
|
674
|
|
|
*/ |
|
675
|
|
|
protected function prepare_item_for_database( $request ) { |
|
676
|
|
|
$prepared_item = new stdClass(); |
|
677
|
|
|
|
|
678
|
|
|
// Post ID. |
|
679
|
|
View Code Duplication |
if ( isset( $request['id'] ) ) { |
|
680
|
|
|
$existing_item = $this->get_post( $request['id'] ); |
|
|
|
|
|
|
681
|
|
|
if ( is_wp_error( $existing_item ) ) { |
|
682
|
|
|
return $existing_item; |
|
683
|
|
|
} |
|
684
|
|
|
|
|
685
|
|
|
$prepared_item->ID = $existing_item->ID; |
|
686
|
|
|
} |
|
687
|
|
|
|
|
688
|
|
|
$schema = $this->get_item_schema(); |
|
689
|
|
|
|
|
690
|
|
|
// item title. |
|
691
|
|
View Code Duplication |
if ( ! empty( $schema['properties']['name'] ) && isset( $request['name'] ) ) { |
|
692
|
|
|
$prepared_item->title = sanitize_text_field( $request['name'] ); |
|
693
|
|
|
} |
|
694
|
|
|
|
|
695
|
|
|
// item summary. |
|
696
|
|
|
if ( ! empty( $schema['properties']['summary'] ) && isset( $request['summary'] ) ) { |
|
697
|
|
|
$prepared_item->excerpt = wp_kses_post( $request['summary'] ); |
|
698
|
|
|
} |
|
699
|
|
|
|
|
700
|
|
|
// item price. |
|
701
|
|
View Code Duplication |
if ( ! empty( $schema['properties']['price'] ) && isset( $request['price'] ) ) { |
|
702
|
|
|
$prepared_item->price = floatval( $request['price'] ); |
|
703
|
|
|
} |
|
704
|
|
|
|
|
705
|
|
|
// minimum price (for dynamc items). |
|
706
|
|
View Code Duplication |
if ( ! empty( $schema['properties']['minimum_price'] ) && isset( $request['minimum_price'] ) ) { |
|
707
|
|
|
$prepared_item->minimum_price = floatval( $request['minimum_price'] ); |
|
708
|
|
|
} |
|
709
|
|
|
|
|
710
|
|
|
// item status. |
|
711
|
|
|
if ( ! empty( $schema['properties']['status'] ) && isset( $request['status'] ) ) { |
|
712
|
|
|
$prepared_item->status = 'publish' === $request['status'] ? 'publish' : 'pending'; |
|
713
|
|
|
} |
|
714
|
|
|
|
|
715
|
|
|
// item type. |
|
716
|
|
|
if ( ! empty( $schema['properties']['type'] ) && isset( $request['type'] ) ) { |
|
717
|
|
|
$prepared_item->type = in_array( $request['type'], wpinv_item_types() ) ? trim( strtolower( $request['type'] ) ) : 'custom'; |
|
718
|
|
|
} |
|
719
|
|
|
|
|
720
|
|
|
// VAT rule. |
|
721
|
|
|
if ( ! empty( $schema['properties']['vat_rule'] ) && isset( $request['vat_rule'] ) ) { |
|
722
|
|
|
$prepared_item->vat_rule = 'digital' === $request['vat_rule'] ? 'digital' : 'physical'; |
|
723
|
|
|
} |
|
724
|
|
|
|
|
725
|
|
|
// Simple strings. |
|
726
|
|
|
foreach( array( 'custom_id', 'custom_name', 'custom_singular_name' ) as $property ) { |
|
727
|
|
|
|
|
728
|
|
View Code Duplication |
if ( ! empty( $schema['properties'][$property] ) && isset( $request[$property] ) ) { |
|
729
|
|
|
$prepared_item->$property = sanitize_text_field( $request[$property] ); |
|
730
|
|
|
} |
|
731
|
|
|
|
|
732
|
|
|
} |
|
733
|
|
|
|
|
734
|
|
|
// Simple integers. |
|
735
|
|
|
foreach( array( 'is_recurring', 'recurring_interval', 'recurring_limit', 'free_trial', 'trial_interval', 'dynamic_pricing', 'editable' ) as $property ) { |
|
736
|
|
|
|
|
737
|
|
View Code Duplication |
if ( ! empty( $schema['properties'][$property] ) && isset( $request[$property] ) ) { |
|
738
|
|
|
$prepared_item->$property = intval( $request[$property] ); |
|
739
|
|
|
} |
|
740
|
|
|
|
|
741
|
|
|
} |
|
742
|
|
|
|
|
743
|
|
|
// Time periods. |
|
744
|
|
|
foreach( array( 'recurring_period', 'trial_period' ) as $property ) { |
|
745
|
|
|
|
|
746
|
|
|
if ( ! empty( $schema['properties'][$property] ) && isset( $request[$property] ) ) { |
|
747
|
|
|
$prepared_item->$property = in_array( $request[$property], array( 'D', 'W', 'M', 'Y' ) ) ? trim( strtoupper( $request[$property] ) ) : 'D'; |
|
748
|
|
|
} |
|
749
|
|
|
|
|
750
|
|
|
} |
|
751
|
|
|
|
|
752
|
|
|
$item_data = (array) wp_unslash( $prepared_item ); |
|
753
|
|
|
|
|
754
|
|
|
/** |
|
755
|
|
|
* Filters an item before it is inserted via the REST API. |
|
756
|
|
|
* |
|
757
|
|
|
* @since 1.0.13 |
|
758
|
|
|
* |
|
759
|
|
|
* @param array $item_data An array of item data |
|
760
|
|
|
* @param WP_REST_Request $request Request object. |
|
761
|
|
|
*/ |
|
762
|
|
|
return apply_filters( "wpinv_rest_pre_insert_item", $item_data, $request ); |
|
763
|
|
|
|
|
764
|
|
|
} |
|
765
|
|
|
|
|
766
|
|
|
/** |
|
767
|
|
|
* Prepares a single item output for response. |
|
768
|
|
|
* |
|
769
|
|
|
* @since 1.0.13 |
|
770
|
|
|
* |
|
771
|
|
|
* @param WPInv_Item $item item object. |
|
772
|
|
|
* @param WP_REST_Request $request Request object. |
|
773
|
|
|
* @return WP_REST_Response Response object. |
|
774
|
|
|
*/ |
|
775
|
|
|
public function prepare_item_for_response( $item, $request ) { |
|
776
|
|
|
|
|
777
|
|
|
$GLOBALS['post'] = get_post( $item->get_ID() ); |
|
778
|
|
|
|
|
779
|
|
|
setup_postdata( $item->get_ID() ); |
|
780
|
|
|
|
|
781
|
|
|
// Fetch the fields to include in this response. |
|
782
|
|
|
$fields = $this->get_fields_for_response( $request ); |
|
783
|
|
|
|
|
784
|
|
|
// Base fields for every item. |
|
785
|
|
|
$data = array(); |
|
786
|
|
|
|
|
787
|
|
|
// Set up ID |
|
788
|
|
|
if ( rest_is_field_included( 'id', $fields ) ) { |
|
789
|
|
|
$data['id'] = $item->get_ID(); |
|
790
|
|
|
} |
|
791
|
|
|
|
|
792
|
|
|
|
|
793
|
|
|
// Item properties |
|
794
|
|
|
$item_properties = array( |
|
795
|
|
|
'name', 'summary', 'price', 'status', 'type', |
|
796
|
|
|
'vat_rule', 'vat_class', |
|
797
|
|
|
'custom_id', 'custom_name', 'custom_singular_name', |
|
798
|
|
|
'editable' |
|
799
|
|
|
); |
|
800
|
|
|
|
|
801
|
|
View Code Duplication |
foreach( $item_properties as $property ) { |
|
802
|
|
|
|
|
803
|
|
|
if ( rest_is_field_included( $property, $fields ) && method_exists( $item, 'get_' . $property ) ) { |
|
804
|
|
|
$data[$property] = call_user_func( array( $item, 'get_' . $property ) ); |
|
805
|
|
|
} |
|
806
|
|
|
|
|
807
|
|
|
} |
|
808
|
|
|
|
|
809
|
|
|
// Dynamic pricing. |
|
810
|
|
|
if( $item->supports_dynamic_pricing() ) { |
|
811
|
|
|
|
|
812
|
|
|
if( rest_is_field_included( 'dynamic_pricing', $fields ) ) { |
|
813
|
|
|
$data['dynamic_pricing'] = $item->get_is_dynamic_pricing(); |
|
814
|
|
|
} |
|
815
|
|
|
|
|
816
|
|
|
if( rest_is_field_included( 'minimum_price', $fields ) ) { |
|
817
|
|
|
$data['minimum_price'] = $item->get_minimum_price(); |
|
818
|
|
|
} |
|
819
|
|
|
} |
|
820
|
|
|
|
|
821
|
|
|
// Subscriptions. |
|
822
|
|
|
if( rest_is_field_included( 'is_recurring', $fields ) ) { |
|
823
|
|
|
$data['is_recurring'] = $item->get_is_recurring(); |
|
824
|
|
|
} |
|
825
|
|
|
|
|
826
|
|
|
if( $item->is_recurring() ) { |
|
827
|
|
|
|
|
828
|
|
|
$recurring_fields = array( 'is_recurring', 'recurring_period', 'recurring_interval', 'recurring_limit', 'free_trial' ); |
|
829
|
|
View Code Duplication |
foreach( $recurring_fields as $field ) { |
|
830
|
|
|
|
|
831
|
|
|
if ( rest_is_field_included( $field, $fields ) && method_exists( $item, 'get_' . $field ) ) { |
|
832
|
|
|
$data[$field] = call_user_func( array( $item, 'get_' . $field ) ); |
|
833
|
|
|
} |
|
834
|
|
|
|
|
835
|
|
|
} |
|
836
|
|
|
|
|
837
|
|
|
if( $item->has_free_trial() ) { |
|
838
|
|
|
|
|
839
|
|
|
$trial_fields = array( 'trial_period', 'trial_interval' ); |
|
840
|
|
View Code Duplication |
foreach( $trial_fields as $field ) { |
|
841
|
|
|
|
|
842
|
|
|
if ( rest_is_field_included( $field, $fields ) && method_exists( $item, 'get_' . $field ) ) { |
|
843
|
|
|
$data[$field] = call_user_func( array( $item, 'get_' . $field ) ); |
|
844
|
|
|
} |
|
845
|
|
|
|
|
846
|
|
|
} |
|
847
|
|
|
|
|
848
|
|
|
} |
|
849
|
|
|
|
|
850
|
|
|
} |
|
851
|
|
|
|
|
852
|
|
|
$context = ! empty( $request['context'] ) ? $request['context'] : 'view'; |
|
853
|
|
|
$data = $this->add_additional_fields_to_object( $data, $request ); |
|
854
|
|
|
$data = $this->filter_response_by_context( $data, $context ); |
|
855
|
|
|
|
|
856
|
|
|
// Wrap the data in a response object. |
|
857
|
|
|
$response = rest_ensure_response( $data ); |
|
858
|
|
|
|
|
859
|
|
|
$links = $this->prepare_links( $item ); |
|
860
|
|
|
$response->add_links( $links ); |
|
861
|
|
|
|
|
862
|
|
View Code Duplication |
if ( ! empty( $links['self']['href'] ) ) { |
|
863
|
|
|
$actions = $this->get_available_actions( $item, $request ); |
|
864
|
|
|
|
|
865
|
|
|
$self = $links['self']['href']; |
|
866
|
|
|
|
|
867
|
|
|
foreach ( $actions as $rel ) { |
|
868
|
|
|
$response->add_link( $rel, $self ); |
|
869
|
|
|
} |
|
870
|
|
|
} |
|
871
|
|
|
|
|
872
|
|
|
/** |
|
873
|
|
|
* Filters the item data for a response. |
|
874
|
|
|
* |
|
875
|
|
|
* @since 1.0.13 |
|
876
|
|
|
* |
|
877
|
|
|
* @param WP_REST_Response $response The response object. |
|
878
|
|
|
* @param WPInv_Item $item The item object. |
|
879
|
|
|
* @param WP_REST_Request $request Request object. |
|
880
|
|
|
*/ |
|
881
|
|
|
return apply_filters( "wpinv_rest_prepare_item", $response, $item, $request ); |
|
882
|
|
|
} |
|
883
|
|
|
|
|
884
|
|
|
/** |
|
885
|
|
|
* Gets an array of fields to be included on the response. |
|
886
|
|
|
* |
|
887
|
|
|
* Included fields are based on item schema and `_fields=` request argument. |
|
888
|
|
|
* |
|
889
|
|
|
* @since 1.0.13 |
|
890
|
|
|
* |
|
891
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
892
|
|
|
* @return array Fields to be included in the response. |
|
893
|
|
|
*/ |
|
894
|
|
View Code Duplication |
public function get_fields_for_response( $request ) { |
|
|
|
|
|
|
895
|
|
|
$schema = $this->get_item_schema(); |
|
896
|
|
|
$properties = isset( $schema['properties'] ) ? $schema['properties'] : array(); |
|
897
|
|
|
|
|
898
|
|
|
$additional_fields = $this->get_additional_fields(); |
|
899
|
|
|
foreach ( $additional_fields as $field_name => $field_options ) { |
|
900
|
|
|
// For back-compat, include any field with an empty schema |
|
901
|
|
|
// because it won't be present in $this->get_item_schema(). |
|
902
|
|
|
if ( is_null( $field_options['schema'] ) ) { |
|
903
|
|
|
$properties[ $field_name ] = $field_options; |
|
904
|
|
|
} |
|
905
|
|
|
} |
|
906
|
|
|
|
|
907
|
|
|
// Exclude fields that specify a different context than the request context. |
|
908
|
|
|
$context = $request['context']; |
|
909
|
|
|
if ( $context ) { |
|
910
|
|
|
foreach ( $properties as $name => $options ) { |
|
911
|
|
|
if ( ! empty( $options['context'] ) && ! in_array( $context, $options['context'], true ) ) { |
|
912
|
|
|
unset( $properties[ $name ] ); |
|
913
|
|
|
} |
|
914
|
|
|
} |
|
915
|
|
|
} |
|
916
|
|
|
|
|
917
|
|
|
$fields = array_keys( $properties ); |
|
918
|
|
|
|
|
919
|
|
|
if ( ! isset( $request['_fields'] ) ) { |
|
920
|
|
|
return $fields; |
|
921
|
|
|
} |
|
922
|
|
|
$requested_fields = wpinv_parse_list( $request['_fields'] ); |
|
923
|
|
|
if ( 0 === count( $requested_fields ) ) { |
|
924
|
|
|
return $fields; |
|
925
|
|
|
} |
|
926
|
|
|
// Trim off outside whitespace from the comma delimited list. |
|
927
|
|
|
$requested_fields = array_map( 'trim', $requested_fields ); |
|
928
|
|
|
// Always persist 'id', because it can be needed for add_additional_fields_to_object(). |
|
929
|
|
|
if ( in_array( 'id', $fields, true ) ) { |
|
930
|
|
|
$requested_fields[] = 'id'; |
|
931
|
|
|
} |
|
932
|
|
|
// Return the list of all requested fields which appear in the schema. |
|
933
|
|
|
return array_reduce( |
|
934
|
|
|
$requested_fields, |
|
935
|
|
|
function( $response_fields, $field ) use ( $fields ) { |
|
936
|
|
|
if ( in_array( $field, $fields, true ) ) { |
|
937
|
|
|
$response_fields[] = $field; |
|
938
|
|
|
return $response_fields; |
|
939
|
|
|
} |
|
940
|
|
|
// Check for nested fields if $field is not a direct match. |
|
941
|
|
|
$nested_fields = explode( '.', $field ); |
|
942
|
|
|
// A nested field is included so long as its top-level property is |
|
943
|
|
|
// present in the schema. |
|
944
|
|
|
if ( in_array( $nested_fields[0], $fields, true ) ) { |
|
945
|
|
|
$response_fields[] = $field; |
|
946
|
|
|
} |
|
947
|
|
|
return $response_fields; |
|
948
|
|
|
}, |
|
949
|
|
|
array() |
|
950
|
|
|
); |
|
951
|
|
|
} |
|
952
|
|
|
|
|
953
|
|
|
/** |
|
954
|
|
|
* Retrieves the item's schema, conforming to JSON Schema. |
|
955
|
|
|
* |
|
956
|
|
|
* @since 1.0.13 |
|
957
|
|
|
* |
|
958
|
|
|
* @return array Item schema data. |
|
959
|
|
|
*/ |
|
960
|
|
|
public function get_item_schema() { |
|
961
|
|
|
|
|
962
|
|
|
// Maybe retrieve the schema from cache. |
|
963
|
|
|
if ( $this->schema ) { |
|
|
|
|
|
|
964
|
|
|
return $this->add_additional_fields_schema( $this->schema ); |
|
965
|
|
|
} |
|
966
|
|
|
|
|
967
|
|
|
$schema = array( |
|
968
|
|
|
'$schema' => 'http://json-schema.org/draft-04/schema#', |
|
969
|
|
|
'title' => $this->post_type, |
|
970
|
|
|
'type' => 'object', |
|
971
|
|
|
|
|
972
|
|
|
// Base properties for every Item. |
|
973
|
|
|
'properties' => array( |
|
974
|
|
|
|
|
975
|
|
|
'id' => array( |
|
976
|
|
|
'description' => __( 'Unique identifier for the item.', 'invoicing' ), |
|
977
|
|
|
'type' => 'integer', |
|
978
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
979
|
|
|
'readonly' => true, |
|
980
|
|
|
), |
|
981
|
|
|
|
|
982
|
|
|
'name' => array( |
|
983
|
|
|
'description' => __( 'The name for the item.', 'invoicing' ), |
|
984
|
|
|
'type' => 'string', |
|
985
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
986
|
|
|
), |
|
987
|
|
|
|
|
988
|
|
|
'summary' => array( |
|
989
|
|
|
'description' => __( 'A summary for the item.', 'invoicing' ), |
|
990
|
|
|
'type' => 'string', |
|
991
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
992
|
|
|
), |
|
993
|
|
|
|
|
994
|
|
|
'price' => array( |
|
995
|
|
|
'description' => __( 'The price for the item.', 'invoicing' ), |
|
996
|
|
|
'type' => 'number', |
|
997
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
998
|
|
|
), |
|
999
|
|
|
|
|
1000
|
|
|
'status' => array( |
|
1001
|
|
|
'description' => __( 'A named status for the item.', 'invoicing' ), |
|
1002
|
|
|
'type' => 'string', |
|
1003
|
|
|
'enum' => array_keys( get_post_stati( array( 'internal' => false ) ) ), |
|
1004
|
|
|
'context' => array( 'view', 'edit' ), |
|
1005
|
|
|
), |
|
1006
|
|
|
|
|
1007
|
|
|
'type' => array( |
|
1008
|
|
|
'description' => __( 'The item type.', 'invoicing' ), |
|
1009
|
|
|
'type' => 'string', |
|
1010
|
|
|
'enum' => wpinv_item_types(), |
|
1011
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
1012
|
|
|
), |
|
1013
|
|
|
|
|
1014
|
|
|
'vat_rule' => array( |
|
1015
|
|
|
'description' => __( 'VAT rule applied to the item.', 'invoicing' ), |
|
1016
|
|
|
'type' => 'string', |
|
1017
|
|
|
'enum' => array( 'digital', 'physical' ), |
|
1018
|
|
|
'context' => array( 'view', 'edit' ), |
|
1019
|
|
|
), |
|
1020
|
|
|
|
|
1021
|
|
|
'vat_class' => array( |
|
1022
|
|
|
'description' => __( 'VAT class for the item.', 'invoicing' ), |
|
1023
|
|
|
'type' => 'string', |
|
1024
|
|
|
'context' => array( 'view', 'edit' ), |
|
1025
|
|
|
'readonly' => true, |
|
1026
|
|
|
), |
|
1027
|
|
|
|
|
1028
|
|
|
'custom_id' => array( |
|
1029
|
|
|
'description' => __( 'Custom id for the item.', 'invoicing' ), |
|
1030
|
|
|
'type' => 'string', |
|
1031
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
1032
|
|
|
), |
|
1033
|
|
|
|
|
1034
|
|
|
'custom_name' => array( |
|
1035
|
|
|
'description' => __( 'Custom name for the item.', 'invoicing' ), |
|
1036
|
|
|
'type' => 'string', |
|
1037
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
1038
|
|
|
), |
|
1039
|
|
|
|
|
1040
|
|
|
'custom_singular_name' => array( |
|
1041
|
|
|
'description' => __( 'Custom singular name for the item.', 'invoicing' ), |
|
1042
|
|
|
'type' => 'string', |
|
1043
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
1044
|
|
|
), |
|
1045
|
|
|
|
|
1046
|
|
|
'dynamic_pricing' => array( |
|
1047
|
|
|
'description' => __( 'Whether the item allows a user to set their own price.', 'invoicing' ), |
|
1048
|
|
|
'type' => 'integer', |
|
1049
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
1050
|
|
|
), |
|
1051
|
|
|
|
|
1052
|
|
|
'minimum_price' => array( |
|
1053
|
|
|
'description' => __( 'For dynamic prices, this is the minimum price that a user can set.', 'invoicing' ), |
|
1054
|
|
|
'type' => 'number', |
|
1055
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
1056
|
|
|
), |
|
1057
|
|
|
|
|
1058
|
|
|
'is_recurring' => array( |
|
1059
|
|
|
'description' => __( 'Whether the item is a subscription item.', 'invoicing' ), |
|
1060
|
|
|
'type' => 'integer', |
|
1061
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
1062
|
|
|
), |
|
1063
|
|
|
|
|
1064
|
|
|
'recurring_period' => array( |
|
1065
|
|
|
'description' => __( 'The recurring period for a recurring item.', 'invoicing' ), |
|
1066
|
|
|
'type' => 'string', |
|
1067
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
1068
|
|
|
'enum' => array( 'D', 'W', 'M', 'Y' ), |
|
1069
|
|
|
), |
|
1070
|
|
|
|
|
1071
|
|
|
'recurring_interval' => array( |
|
1072
|
|
|
'description' => __( 'The recurring interval for a subscription item.', 'invoicing' ), |
|
1073
|
|
|
'type' => 'integer', |
|
1074
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
1075
|
|
|
), |
|
1076
|
|
|
|
|
1077
|
|
|
'recurring_limit' => array( |
|
1078
|
|
|
'description' => __( 'The maximum number of renewals for a subscription item.', 'invoicing' ), |
|
1079
|
|
|
'type' => 'integer', |
|
1080
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
1081
|
|
|
), |
|
1082
|
|
|
|
|
1083
|
|
|
'free_trial' => array( |
|
1084
|
|
|
'description' => __( 'Whether the item has a free trial period.', 'invoicing' ), |
|
1085
|
|
|
'type' => 'integer', |
|
1086
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
1087
|
|
|
), |
|
1088
|
|
|
|
|
1089
|
|
|
'trial_period' => array( |
|
1090
|
|
|
'description' => __( 'The trial period of a recurring item.', 'invoicing' ), |
|
1091
|
|
|
'type' => 'string', |
|
1092
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
1093
|
|
|
'enum' => array( 'D', 'W', 'M', 'Y' ), |
|
1094
|
|
|
), |
|
1095
|
|
|
|
|
1096
|
|
|
'trial_interval' => array( |
|
1097
|
|
|
'description' => __( 'The trial interval for a subscription item.', 'invoicing' ), |
|
1098
|
|
|
'type' => 'integer', |
|
1099
|
|
|
'context' => array( 'view', 'edit', 'embed' ), |
|
1100
|
|
|
), |
|
1101
|
|
|
|
|
1102
|
|
|
'editable' => array( |
|
1103
|
|
|
'description' => __( 'Whether or not the item is editable.', 'invoicing' ), |
|
1104
|
|
|
'type' => 'integer', |
|
1105
|
|
|
'context' => array( 'view', 'edit' ), |
|
1106
|
|
|
), |
|
1107
|
|
|
|
|
1108
|
|
|
), |
|
1109
|
|
|
); |
|
1110
|
|
|
|
|
1111
|
|
|
// Add helpful links to the item schem. |
|
1112
|
|
|
$schema['links'] = $this->get_schema_links(); |
|
1113
|
|
|
|
|
1114
|
|
|
/** |
|
1115
|
|
|
* Filters the item schema for the REST API. |
|
1116
|
|
|
* |
|
1117
|
|
|
* Enables adding extra properties to items. |
|
1118
|
|
|
* |
|
1119
|
|
|
* @since 1.0.13 |
|
1120
|
|
|
* |
|
1121
|
|
|
* @param array $schema The item schema. |
|
1122
|
|
|
*/ |
|
1123
|
|
|
$schema = apply_filters( "wpinv_rest_item_schema", $schema ); |
|
1124
|
|
|
|
|
1125
|
|
|
// Cache the item schema. |
|
1126
|
|
|
$this->schema = $schema; |
|
1127
|
|
|
|
|
1128
|
|
|
return $this->add_additional_fields_schema( $this->schema ); |
|
1129
|
|
|
} |
|
1130
|
|
|
|
|
1131
|
|
|
/** |
|
1132
|
|
|
* Retrieve Link Description Objects that should be added to the Schema for the invoices collection. |
|
1133
|
|
|
* |
|
1134
|
|
|
* @since 1.0.13 |
|
1135
|
|
|
* |
|
1136
|
|
|
* @return array |
|
1137
|
|
|
*/ |
|
1138
|
|
|
protected function get_schema_links() { |
|
1139
|
|
|
|
|
1140
|
|
|
$href = rest_url( "{$this->namespace}/{$this->rest_base}/{id}" ); |
|
1141
|
|
|
|
|
1142
|
|
|
$links = array(); |
|
1143
|
|
|
|
|
1144
|
|
|
$links[] = array( |
|
1145
|
|
|
'rel' => 'https://api.w.org/action-publish', |
|
1146
|
|
|
'title' => __( 'The current user can publish this item.' ), |
|
1147
|
|
|
'href' => $href, |
|
1148
|
|
|
'targetSchema' => array( |
|
1149
|
|
|
'type' => 'object', |
|
1150
|
|
|
'properties' => array( |
|
1151
|
|
|
'status' => array( |
|
1152
|
|
|
'type' => 'string', |
|
1153
|
|
|
'enum' => array( 'publish', 'future' ), |
|
1154
|
|
|
), |
|
1155
|
|
|
), |
|
1156
|
|
|
), |
|
1157
|
|
|
); |
|
1158
|
|
|
|
|
1159
|
|
|
return $links; |
|
1160
|
|
|
} |
|
1161
|
|
|
|
|
1162
|
|
|
/** |
|
1163
|
|
|
* Prepares links for the request. |
|
1164
|
|
|
* |
|
1165
|
|
|
* @since 1.0.13 |
|
1166
|
|
|
* |
|
1167
|
|
|
* @param WPInv_Item $item Item Object. |
|
1168
|
|
|
* @return array Links for the given item. |
|
1169
|
|
|
*/ |
|
1170
|
|
|
protected function prepare_links( $item ) { |
|
1171
|
|
|
|
|
1172
|
|
|
// Prepare the base REST API endpoint for items. |
|
1173
|
|
|
$base = sprintf( '%s/%s', $this->namespace, $this->rest_base ); |
|
1174
|
|
|
|
|
1175
|
|
|
// Entity meta. |
|
1176
|
|
|
$links = array( |
|
1177
|
|
|
'self' => array( |
|
1178
|
|
|
'href' => rest_url( trailingslashit( $base ) . $item->ID ), |
|
1179
|
|
|
), |
|
1180
|
|
|
'collection' => array( |
|
1181
|
|
|
'href' => rest_url( $base ), |
|
1182
|
|
|
), |
|
1183
|
|
|
); |
|
1184
|
|
|
|
|
1185
|
|
|
/** |
|
1186
|
|
|
* Filters the returned item links for the REST API. |
|
1187
|
|
|
* |
|
1188
|
|
|
* Enables adding extra links to item API responses. |
|
1189
|
|
|
* |
|
1190
|
|
|
* @since 1.0.13 |
|
1191
|
|
|
* |
|
1192
|
|
|
* @param array $links Rest links. |
|
1193
|
|
|
*/ |
|
1194
|
|
|
return apply_filters( "wpinv_rest_item_links", $links ); |
|
1195
|
|
|
|
|
1196
|
|
|
} |
|
1197
|
|
|
|
|
1198
|
|
|
/** |
|
1199
|
|
|
* Get the link relations available for the post and current user. |
|
1200
|
|
|
* |
|
1201
|
|
|
* @since 1.0.13 |
|
1202
|
|
|
* |
|
1203
|
|
|
* @param WPInv_Item $item Item object. |
|
1204
|
|
|
* @param WP_REST_Request $request Request object. |
|
1205
|
|
|
* @return array List of link relations. |
|
1206
|
|
|
*/ |
|
1207
|
|
|
protected function get_available_actions( $item, $request ) { |
|
1208
|
|
|
|
|
1209
|
|
|
if ( 'edit' !== $request['context'] ) { |
|
1210
|
|
|
return array(); |
|
1211
|
|
|
} |
|
1212
|
|
|
|
|
1213
|
|
|
$rels = array(); |
|
1214
|
|
|
|
|
1215
|
|
|
// Retrieve the post type object. |
|
1216
|
|
|
$post_type = get_post_type_object( $item->post_type ); |
|
|
|
|
|
|
1217
|
|
|
|
|
1218
|
|
|
// Mark item as published. |
|
1219
|
|
|
if ( current_user_can( $post_type->cap->publish_posts ) ) { |
|
1220
|
|
|
$rels[] = 'https://api.w.org/action-publish'; |
|
1221
|
|
|
} |
|
1222
|
|
|
|
|
1223
|
|
|
/** |
|
1224
|
|
|
* Filters the available item link relations for the REST API. |
|
1225
|
|
|
* |
|
1226
|
|
|
* Enables adding extra link relation for the current user and request to item responses. |
|
1227
|
|
|
* |
|
1228
|
|
|
* @since 1.0.13 |
|
1229
|
|
|
* |
|
1230
|
|
|
* @param array $rels Available link relations. |
|
1231
|
|
|
*/ |
|
1232
|
|
|
return apply_filters( "wpinv_rest_item_link_relations", $rels ); |
|
1233
|
|
|
} |
|
1234
|
|
|
|
|
1235
|
|
|
/** |
|
1236
|
|
|
* Handles rest requests for item types. |
|
1237
|
|
|
* |
|
1238
|
|
|
* @since 1.0.13 |
|
1239
|
|
|
* |
|
1240
|
|
|
* |
|
1241
|
|
|
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
|
1242
|
|
|
*/ |
|
1243
|
|
|
public function get_item_types() { |
|
1244
|
|
|
return rest_ensure_response( wpinv_get_item_types() ); |
|
1245
|
|
|
} |
|
1246
|
|
|
|
|
1247
|
|
|
|
|
1248
|
|
|
} |
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.