1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
if ( ! defined( 'ABSPATH' ) ) { |
4
|
|
|
exit; |
5
|
|
|
} |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* Abstract Rest Controler Class |
9
|
|
|
* |
10
|
|
|
* @author WooThemes |
11
|
|
|
* @category API |
12
|
|
|
* @package WooCommerce/Abstracts |
13
|
|
|
* @extends WP_REST_Controller |
14
|
|
|
* @version 2.6.0 |
15
|
|
|
*/ |
16
|
|
|
abstract class WC_REST_Controller extends WP_REST_Controller { |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Endpoint namespace. |
20
|
|
|
* |
21
|
|
|
* @var string |
22
|
|
|
*/ |
23
|
|
|
protected $namespace = 'wc/v1'; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Route base. |
27
|
|
|
* |
28
|
|
|
* @var string |
29
|
|
|
*/ |
30
|
|
|
protected $rest_base = ''; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* Add the schema from additional fields to an schema array. |
34
|
|
|
* |
35
|
|
|
* The type of object is inferred from the passed schema. |
36
|
|
|
* |
37
|
|
|
* @param array $schema Schema array. |
38
|
|
|
*/ |
39
|
|
|
protected function add_additional_fields_schema( $schema ) { |
40
|
|
|
if ( empty( $schema['title'] ) ) { |
41
|
|
|
return $schema; |
42
|
|
|
} |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* Can't use $this->get_object_type otherwise we cause an inf loop. |
46
|
|
|
*/ |
47
|
|
|
$object_type = $schema['title']; |
48
|
|
|
|
49
|
|
|
$additional_fields = $this->get_additional_fields( $object_type ); |
50
|
|
|
|
51
|
|
View Code Duplication |
foreach ( $additional_fields as $field_name => $field_options ) { |
|
|
|
|
52
|
|
|
if ( ! $field_options['schema'] ) { |
53
|
|
|
continue; |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
$schema['properties'][ $field_name ] = $field_options['schema']; |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
$schema['properties'] = apply_filters( 'woocommerce_rest_' . $object_type . '_schema', $schema['properties'] ); |
60
|
|
|
|
61
|
|
|
return $schema; |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Get normalized rest base. |
66
|
|
|
* |
67
|
|
|
* @return string |
68
|
|
|
*/ |
69
|
|
|
protected function get_normalized_rest_base() { |
70
|
|
|
return preg_replace( '/\(.*\)\//i', '', $this->rest_base ); |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* Check batch limit. |
75
|
|
|
* |
76
|
|
|
* @param array $items Request items. |
77
|
|
|
* @return bool|WP_Error |
78
|
|
|
*/ |
79
|
|
|
protected function check_batch_limit( $items ) { |
80
|
|
|
$limit = apply_filters( 'woocommerce_rest_batch_items_limit', 100, $this->get_normalized_rest_base() ); |
81
|
|
|
$total = 0; |
82
|
|
|
|
83
|
|
|
if ( ! empty( $items['create'] ) ) { |
84
|
|
|
$total += count( $items['create'] ); |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
if ( ! empty( $items['update'] ) ) { |
88
|
|
|
$total += count( $items['update'] ); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
if ( ! empty( $items['delete'] ) ) { |
92
|
|
|
$total += count( $items['delete'] ); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
View Code Duplication |
if ( $total > $limit ) { |
|
|
|
|
96
|
|
|
return new WP_Error( 'woocommerce_rest_request_entity_too_large', sprintf( __( 'Unable to accept more than %s items for this request.', 'woocommerce' ), $limit ), array( 'status' => 413 ) ); |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
return true; |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Bulk create, update and delete items. |
104
|
|
|
* |
105
|
|
|
* @param WP_REST_Request $request Full details about the request. |
106
|
|
|
* @return array Of WP_Error or WP_REST_Response. |
107
|
|
|
*/ |
108
|
|
|
public function batch_items( $request ) { |
109
|
|
|
/** @var WP_REST_Server $wp_rest_server */ |
110
|
|
|
global $wp_rest_server; |
111
|
|
|
|
112
|
|
|
// Get the request params. |
113
|
|
|
$items = array_filter( $request->get_params() ); |
114
|
|
|
$response = array(); |
115
|
|
|
|
116
|
|
|
// Check batch limit. |
117
|
|
|
$limit = $this->check_batch_limit( $items ); |
118
|
|
|
if ( is_wp_error( $limit ) ) { |
119
|
|
|
return $limit; |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
if ( ! empty( $items['create'] ) ) { |
123
|
|
|
foreach ( $items['create'] as $item ) { |
124
|
|
|
$_item = new WP_REST_Request( 'POST' ); |
125
|
|
|
|
126
|
|
|
// Default parameters. |
127
|
|
|
$defaults = array(); |
128
|
|
|
$schema = $this->get_public_item_schema(); |
129
|
|
|
foreach ( $schema['properties'] as $arg => $options ) { |
130
|
|
|
if ( isset( $options['default'] ) ) { |
131
|
|
|
$defaults[ $arg ] = $options['default']; |
132
|
|
|
} |
133
|
|
|
} |
134
|
|
|
$_item->set_default_params( $defaults ); |
135
|
|
|
|
136
|
|
|
// Set request parameters. |
137
|
|
|
$_item->set_body_params( $item ); |
138
|
|
|
$_response = $this->create_item( $_item ); |
139
|
|
|
|
140
|
|
|
if ( is_wp_error( $_response ) ) { |
141
|
|
|
$response['create'][] = array( |
142
|
|
|
'id' => 0, |
143
|
|
|
'error' => array( 'code' => $_response->get_error_code(), 'message' => $_response->get_error_message(), 'data' => $_response->get_error_data() ), |
144
|
|
|
); |
145
|
|
|
} else { |
146
|
|
|
$response['create'][] = $wp_rest_server->response_to_data( $_response, '' ); |
147
|
|
|
} |
148
|
|
|
} |
149
|
|
|
} |
150
|
|
|
|
151
|
|
View Code Duplication |
if ( ! empty( $items['update'] ) ) { |
|
|
|
|
152
|
|
|
foreach ( $items['update'] as $item ) { |
153
|
|
|
$_item = new WP_REST_Request( 'PUT' ); |
154
|
|
|
$_item->set_body_params( $item ); |
155
|
|
|
$_response = $this->update_item( $_item ); |
156
|
|
|
|
157
|
|
|
if ( is_wp_error( $_response ) ) { |
158
|
|
|
$response['update'][] = array( |
159
|
|
|
'id' => $item['id'], |
160
|
|
|
'error' => array( 'code' => $_response->get_error_code(), 'message' => $_response->get_error_message(), 'data' => $_response->get_error_data() ), |
161
|
|
|
); |
162
|
|
|
} else { |
163
|
|
|
$response['update'][] = $wp_rest_server->response_to_data( $_response, '' ); |
164
|
|
|
} |
165
|
|
|
} |
166
|
|
|
} |
167
|
|
|
|
168
|
|
View Code Duplication |
if ( ! empty( $items['delete'] ) ) { |
|
|
|
|
169
|
|
|
foreach ( $items['delete'] as $id ) { |
170
|
|
|
$_item = new WP_REST_Request( 'DELETE' ); |
171
|
|
|
$_item->set_query_params( array( 'id' => $id, 'force' => true ) ); |
172
|
|
|
$_response = $this->delete_item( $_item ); |
173
|
|
|
|
174
|
|
|
if ( is_wp_error( $_response ) ) { |
175
|
|
|
$response['delete'][] = array( |
176
|
|
|
'id' => $id, |
177
|
|
|
'error' => array( 'code' => $_response->get_error_code(), 'message' => $_response->get_error_message(), 'data' => $_response->get_error_data() ), |
178
|
|
|
); |
179
|
|
|
} else { |
180
|
|
|
$response['delete'][] = $wp_rest_server->response_to_data( $_response, '' ); |
181
|
|
|
} |
182
|
|
|
} |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
return $response; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Validate a text value for a text based setting. |
190
|
|
|
* |
191
|
|
|
* @since 2.7.0 |
192
|
|
|
* @param string $value |
193
|
|
|
* @param array $setting |
194
|
|
|
* @return string |
195
|
|
|
*/ |
196
|
|
|
public function validate_setting_text_field( $value, $setting ) { |
|
|
|
|
197
|
|
|
$value = is_null( $value ) ? '' : $value; |
198
|
|
|
return wp_kses_post( trim( stripslashes( $value ) ) ); |
199
|
|
|
return $value; |
|
|
|
|
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Validate select based settings. |
204
|
|
|
* |
205
|
|
|
* @since 2.7.0 |
206
|
|
|
* @param string $value |
207
|
|
|
* @param array $setting |
208
|
|
|
* @return string|WP_Error |
209
|
|
|
*/ |
210
|
|
|
public function validate_setting_select_field( $value, $setting ) { |
211
|
|
View Code Duplication |
if ( array_key_exists( $value, $setting['options'] ) ) { |
|
|
|
|
212
|
|
|
return $value; |
213
|
|
|
} else { |
214
|
|
|
return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce' ), array( 'status' => 400 ) ); |
215
|
|
|
} |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
/** |
219
|
|
|
* Validate multiselect based settings. |
220
|
|
|
* |
221
|
|
|
* @since 2.7.0 |
222
|
|
|
* @param array $values |
223
|
|
|
* @param array $setting |
224
|
|
|
* @return string|WP_Error |
225
|
|
|
*/ |
226
|
|
|
public function validate_setting_multiselect_field( $values, $setting ) { |
227
|
|
|
if ( empty( $values ) ) { |
228
|
|
|
return array(); |
229
|
|
|
} |
230
|
|
|
|
231
|
|
View Code Duplication |
if ( ! is_array( $values ) ) { |
|
|
|
|
232
|
|
|
return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce' ), array( 'status' => 400 ) ); |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
$final_values = array(); |
236
|
|
|
foreach ( $values as $value ) { |
237
|
|
|
if ( array_key_exists( $value, $setting['options'] ) ) { |
238
|
|
|
$final_values[] = $value; |
239
|
|
|
} |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
return $final_values; |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* Validate image_width based settings. |
247
|
|
|
* |
248
|
|
|
* @since 2.7.0 |
249
|
|
|
* @param array $value |
|
|
|
|
250
|
|
|
* @param array $setting |
251
|
|
|
* @return string|WP_Error |
252
|
|
|
*/ |
253
|
|
|
public function validate_setting_image_width_field( $values, $setting ) { |
254
|
|
View Code Duplication |
if ( ! is_array( $values ) ) { |
|
|
|
|
255
|
|
|
return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce' ), array( 'status' => 400 ) ); |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
$current = $setting['value']; |
259
|
|
|
if ( isset( $values['width'] ) ) { |
260
|
|
|
$current['width'] = intval( $values['width'] ); |
261
|
|
|
} |
262
|
|
|
if ( isset( $values['height'] ) ) { |
263
|
|
|
$current['height'] = intval( $values['height'] ); |
264
|
|
|
} |
265
|
|
|
if ( isset( $values['crop'] ) ) { |
266
|
|
|
$current['crop'] = (bool) $values['crop']; |
267
|
|
|
} |
268
|
|
|
return $current; |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* Validate radio based settings. |
273
|
|
|
* |
274
|
|
|
* @since 2.7.0 |
275
|
|
|
* @param string $value |
276
|
|
|
* @param array $setting |
277
|
|
|
* @return string|WP_Error |
278
|
|
|
*/ |
279
|
|
|
public function validate_setting_radio_field( $value, $setting ) { |
280
|
|
|
return $this->validate_setting_select_field( $value, $setting ); |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
/** |
284
|
|
|
* Validate checkbox based settings. |
285
|
|
|
* |
286
|
|
|
* @since 2.7.0 |
287
|
|
|
* @param string $value |
288
|
|
|
* @param array $setting |
289
|
|
|
* @return string|WP_Error |
290
|
|
|
*/ |
291
|
|
|
public function validate_setting_checkbox_field( $value, $setting ) { |
292
|
|
|
if ( in_array( $value, array( 'yes', 'no' ) ) ) { |
293
|
|
|
return $value; |
294
|
|
|
} elseif ( empty( $value ) ) { |
295
|
|
|
$value = isset( $setting['default'] ) ? $setting['default'] : 'no'; |
296
|
|
|
return $value; |
297
|
|
|
} else { |
298
|
|
|
return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'woocommerce' ), array( 'status' => 400 ) ); |
299
|
|
|
} |
300
|
|
|
} |
301
|
|
|
|
302
|
|
|
/** |
303
|
|
|
* Validate textarea based settings. |
304
|
|
|
* |
305
|
|
|
* @since 2.7.0 |
306
|
|
|
* @param string $value |
307
|
|
|
* @param array $setting |
308
|
|
|
* @return string |
309
|
|
|
*/ |
310
|
|
View Code Duplication |
public function validate_setting_textarea_field( $value, $setting ) { |
|
|
|
|
311
|
|
|
$value = is_null( $value ) ? '' : $value; |
312
|
|
|
return wp_kses( trim( stripslashes( $value ) ), |
313
|
|
|
array_merge( |
314
|
|
|
array( |
315
|
|
|
'iframe' => array( 'src' => true, 'style' => true, 'id' => true, 'class' => true ), |
316
|
|
|
), |
317
|
|
|
wp_kses_allowed_html( 'post' ) |
318
|
|
|
) |
319
|
|
|
); |
320
|
|
|
} |
321
|
|
|
|
322
|
|
|
/** |
323
|
|
|
* Get the batch schema, conforming to JSON Schema. |
324
|
|
|
* |
325
|
|
|
* @return array |
326
|
|
|
*/ |
327
|
|
|
public function get_public_batch_schema() { |
328
|
|
|
$schema = array( |
329
|
|
|
'$schema' => 'http://json-schema.org/draft-04/schema#', |
330
|
|
|
'title' => 'batch', |
331
|
|
|
'type' => 'object', |
332
|
|
|
'properties' => array( |
333
|
|
|
'create' => array( |
334
|
|
|
'description' => __( 'List of created resources.', 'woocommerce' ), |
335
|
|
|
'type' => 'array', |
336
|
|
|
'context' => array( 'view', 'edit' ), |
337
|
|
|
), |
338
|
|
|
'update' => array( |
339
|
|
|
'description' => __( 'List of updated resources.', 'woocommerce' ), |
340
|
|
|
'type' => 'array', |
341
|
|
|
'context' => array( 'view', 'edit' ), |
342
|
|
|
), |
343
|
|
|
'delete' => array( |
344
|
|
|
'description' => __( 'List of delete resources.', 'woocommerce' ), |
345
|
|
|
'type' => 'array', |
346
|
|
|
'context' => array( 'view', 'edit' ), |
347
|
|
|
), |
348
|
|
|
), |
349
|
|
|
); |
350
|
|
|
|
351
|
|
|
return $schema; |
352
|
|
|
} |
353
|
|
|
} |
354
|
|
|
|
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.