|
1
|
|
|
<?php |
|
|
|
|
|
|
2
|
|
|
/** |
|
3
|
|
|
* REST API Product Attributes controller |
|
4
|
|
|
* |
|
5
|
|
|
* Handles requests to the products/attributes 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 Product Attributes controller class. |
|
19
|
|
|
* |
|
20
|
|
|
* @package WooCommerce/API |
|
21
|
|
|
* @extends WC_REST_Controller |
|
22
|
|
|
*/ |
|
23
|
|
|
class WC_REST_Product_Attributes_Controller extends WC_REST_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 = 'products/attributes'; |
|
38
|
|
|
|
|
39
|
|
|
/** |
|
40
|
|
|
* Attribute name. |
|
41
|
|
|
* |
|
42
|
|
|
* @var string |
|
43
|
|
|
*/ |
|
44
|
|
|
protected $attribute = ''; |
|
45
|
|
|
|
|
46
|
|
|
/** |
|
47
|
|
|
* Register the routes for product attributes. |
|
48
|
|
|
*/ |
|
49
|
|
View Code Duplication |
public function register_routes() { |
|
|
|
|
|
|
50
|
|
|
register_rest_route( $this->namespace, '/' . $this->rest_base, array( |
|
51
|
|
|
array( |
|
52
|
|
|
'methods' => WP_REST_Server::READABLE, |
|
53
|
|
|
'callback' => array( $this, 'get_items' ), |
|
54
|
|
|
'permission_callback' => array( $this, 'get_items_permissions_check' ), |
|
55
|
|
|
'args' => $this->get_collection_params(), |
|
56
|
|
|
), |
|
57
|
|
|
array( |
|
58
|
|
|
'methods' => WP_REST_Server::CREATABLE, |
|
59
|
|
|
'callback' => array( $this, 'create_item' ), |
|
60
|
|
|
'permission_callback' => array( $this, 'create_item_permissions_check' ), |
|
61
|
|
|
'args' => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array( |
|
62
|
|
|
'name' => array( |
|
63
|
|
|
'required' => true, |
|
64
|
|
|
), |
|
65
|
|
|
) ), |
|
66
|
|
|
), |
|
67
|
|
|
'schema' => array( $this, 'get_public_item_schema' ), |
|
68
|
|
|
)); |
|
69
|
|
|
|
|
70
|
|
|
register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array( |
|
71
|
|
|
array( |
|
72
|
|
|
'methods' => WP_REST_Server::READABLE, |
|
73
|
|
|
'callback' => array( $this, 'get_item' ), |
|
74
|
|
|
'permission_callback' => array( $this, 'get_item_permissions_check' ), |
|
75
|
|
|
'args' => array( |
|
76
|
|
|
'context' => $this->get_context_param( array( 'default' => 'view' ) ), |
|
77
|
|
|
), |
|
78
|
|
|
), |
|
79
|
|
|
array( |
|
80
|
|
|
'methods' => WP_REST_Server::EDITABLE, |
|
81
|
|
|
'callback' => array( $this, 'update_item' ), |
|
82
|
|
|
'permission_callback' => array( $this, 'update_item_permissions_check' ), |
|
83
|
|
|
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), |
|
84
|
|
|
), |
|
85
|
|
|
array( |
|
86
|
|
|
'methods' => WP_REST_Server::DELETABLE, |
|
87
|
|
|
'callback' => array( $this, 'delete_item' ), |
|
88
|
|
|
'permission_callback' => array( $this, 'delete_item_permissions_check' ), |
|
89
|
|
|
'args' => array( |
|
90
|
|
|
'force' => array( |
|
91
|
|
|
'default' => false, |
|
92
|
|
|
'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce' ), |
|
93
|
|
|
), |
|
94
|
|
|
), |
|
95
|
|
|
), |
|
96
|
|
|
'schema' => array( $this, 'get_public_item_schema' ), |
|
97
|
|
|
) ); |
|
98
|
|
|
|
|
99
|
|
|
register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array( |
|
100
|
|
|
array( |
|
101
|
|
|
'methods' => WP_REST_Server::EDITABLE, |
|
102
|
|
|
'callback' => array( $this, 'batch_items' ), |
|
103
|
|
|
'permission_callback' => array( $this, 'batch_items_permissions_check' ), |
|
104
|
|
|
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), |
|
105
|
|
|
), |
|
106
|
|
|
'schema' => array( $this, 'get_public_batch_schema' ), |
|
107
|
|
|
) ); |
|
108
|
|
|
} |
|
109
|
|
|
|
|
110
|
|
|
/** |
|
111
|
|
|
* Check if a given request has access to read the attributes. |
|
112
|
|
|
* |
|
113
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
114
|
|
|
* @return WP_Error|boolean |
|
115
|
|
|
*/ |
|
116
|
|
View Code Duplication |
public function get_items_permissions_check( $request ) { |
|
|
|
|
|
|
117
|
|
|
if ( ! wc_rest_check_manager_permissions( 'attributes', 'read' ) ) { |
|
118
|
|
|
return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); |
|
119
|
|
|
} |
|
120
|
|
|
|
|
121
|
|
|
return true; |
|
122
|
|
|
} |
|
123
|
|
|
|
|
124
|
|
|
/** |
|
125
|
|
|
* Check if a given request has access to create a attribute. |
|
126
|
|
|
* |
|
127
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
128
|
|
|
* @return WP_Error|boolean |
|
129
|
|
|
*/ |
|
130
|
|
View Code Duplication |
public function create_item_permissions_check( $request ) { |
|
|
|
|
|
|
131
|
|
|
if ( ! wc_rest_check_manager_permissions( 'attributes', 'create' ) ) { |
|
132
|
|
|
return new WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you cannot create new resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); |
|
133
|
|
|
} |
|
134
|
|
|
|
|
135
|
|
|
return true; |
|
136
|
|
|
} |
|
137
|
|
|
|
|
138
|
|
|
/** |
|
139
|
|
|
* Check if a given request has access to read a attribute. |
|
140
|
|
|
* |
|
141
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
142
|
|
|
* @return WP_Error|boolean |
|
143
|
|
|
*/ |
|
144
|
|
View Code Duplication |
public function get_item_permissions_check( $request ) { |
|
|
|
|
|
|
145
|
|
|
if ( ! $this->get_taxonomy( $request ) ) { |
|
146
|
|
|
return new WP_Error( "woocommerce_rest_taxonomy_invalid", __( "Resource doesn't exist.", 'woocommerce' ), array( 'status' => 404 ) ); |
|
147
|
|
|
} |
|
148
|
|
|
|
|
149
|
|
|
if ( ! wc_rest_check_manager_permissions( 'attributes', 'read' ) ) { |
|
150
|
|
|
return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); |
|
151
|
|
|
} |
|
152
|
|
|
|
|
153
|
|
|
return true; |
|
154
|
|
|
} |
|
155
|
|
|
|
|
156
|
|
|
/** |
|
157
|
|
|
* Check if a given request has access to update a attribute. |
|
158
|
|
|
* |
|
159
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
160
|
|
|
* @return WP_Error|boolean |
|
161
|
|
|
*/ |
|
162
|
|
View Code Duplication |
public function update_item_permissions_check( $request ) { |
|
|
|
|
|
|
163
|
|
|
if ( ! $this->get_taxonomy( $request ) ) { |
|
164
|
|
|
return new WP_Error( "woocommerce_rest_taxonomy_invalid", __( "Resource doesn't exist.", 'woocommerce' ), array( 'status' => 404 ) ); |
|
165
|
|
|
} |
|
166
|
|
|
|
|
167
|
|
|
if ( ! wc_rest_check_manager_permissions( 'attributes', 'edit' ) ) { |
|
168
|
|
|
return new WP_Error( 'woocommerce_rest_cannot_update', __( 'Sorry, you cannot update resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); |
|
169
|
|
|
} |
|
170
|
|
|
|
|
171
|
|
|
return true; |
|
172
|
|
|
} |
|
173
|
|
|
|
|
174
|
|
|
/** |
|
175
|
|
|
* Check if a given request has access to delete a attribute. |
|
176
|
|
|
* |
|
177
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
178
|
|
|
* @return WP_Error|boolean |
|
179
|
|
|
*/ |
|
180
|
|
View Code Duplication |
public function delete_item_permissions_check( $request ) { |
|
|
|
|
|
|
181
|
|
|
if ( ! $this->get_taxonomy( $request ) ) { |
|
182
|
|
|
return new WP_Error( "woocommerce_rest_taxonomy_invalid", __( "Resource doesn't exist.", 'woocommerce' ), array( 'status' => 404 ) ); |
|
183
|
|
|
} |
|
184
|
|
|
|
|
185
|
|
|
if ( ! wc_rest_check_manager_permissions( 'attributes', 'delete' ) ) { |
|
186
|
|
|
return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you cannot delete resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); |
|
187
|
|
|
} |
|
188
|
|
|
|
|
189
|
|
|
return true; |
|
190
|
|
|
} |
|
191
|
|
|
|
|
192
|
|
|
/** |
|
193
|
|
|
* Get all attributes. |
|
194
|
|
|
* |
|
195
|
|
|
* @param WP_REST_Request $request |
|
196
|
|
|
* @return array |
|
197
|
|
|
*/ |
|
198
|
|
|
public function get_items( $request ) { |
|
199
|
|
|
$attributes = wc_get_attribute_taxonomies(); |
|
200
|
|
|
$data = array(); |
|
201
|
|
|
foreach ( $attributes as $attribute_obj ) { |
|
202
|
|
|
$attribute = $this->prepare_item_for_response( $attribute_obj, $request ); |
|
203
|
|
|
$attribute = $this->prepare_response_for_collection( $attribute ); |
|
204
|
|
|
$data[] = $attribute; |
|
205
|
|
|
} |
|
206
|
|
|
|
|
207
|
|
|
return rest_ensure_response( $data ); |
|
208
|
|
|
} |
|
209
|
|
|
|
|
210
|
|
|
/** |
|
211
|
|
|
* Create a single attribute. |
|
212
|
|
|
* |
|
213
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
214
|
|
|
* @return WP_REST_Request|WP_Error |
|
215
|
|
|
*/ |
|
216
|
|
|
public function create_item( $request ) { |
|
217
|
|
|
global $wpdb; |
|
218
|
|
|
|
|
219
|
|
|
$args = array( |
|
220
|
|
|
'attribute_label' => $request['name'], |
|
221
|
|
|
'attribute_name' => $request['slug'], |
|
222
|
|
|
'attribute_type' => $request['type'], |
|
223
|
|
|
'attribute_orderby' => $request['order_by'], |
|
224
|
|
|
'attribute_public' => $request['has_archives'], |
|
225
|
|
|
); |
|
226
|
|
|
|
|
227
|
|
|
// Set the attribute slug. |
|
228
|
|
|
if ( empty( $args['attribute_name'] ) ) { |
|
229
|
|
|
$args['attribute_name'] = wc_sanitize_taxonomy_name( stripslashes( $args['attribute_label'] ) ); |
|
230
|
|
|
} else { |
|
231
|
|
|
$args['attribute_name'] = preg_replace( '/^pa\_/', '', wc_sanitize_taxonomy_name( stripslashes( $args['attribute_name'] ) ) ); |
|
232
|
|
|
} |
|
233
|
|
|
|
|
234
|
|
|
$valid_slug = $this->validate_attribute_slug( $args['attribute_name'], true ); |
|
235
|
|
|
if ( is_wp_error( $valid_slug ) ) { |
|
236
|
|
|
return $valid_slug; |
|
237
|
|
|
} |
|
238
|
|
|
|
|
239
|
|
|
$insert = $wpdb->insert( |
|
240
|
|
|
$wpdb->prefix . 'woocommerce_attribute_taxonomies', |
|
241
|
|
|
$args, |
|
242
|
|
|
array( '%s', '%s', '%s', '%s', '%d' ) |
|
243
|
|
|
); |
|
244
|
|
|
|
|
245
|
|
|
// Checks for errors. |
|
246
|
|
|
if ( is_wp_error( $insert ) ) { |
|
247
|
|
|
return new WP_Error( 'woocommerce_rest_cannot_create', $insert->get_error_message(), array( 'status' => 400 ) ); |
|
248
|
|
|
} |
|
249
|
|
|
|
|
250
|
|
|
$attribute = $this->get_attribute( $wpdb->insert_id ); |
|
251
|
|
|
|
|
252
|
|
|
if ( is_wp_error( $attribute ) ) { |
|
253
|
|
|
return $attribute; |
|
254
|
|
|
} |
|
255
|
|
|
|
|
256
|
|
|
$this->update_additional_fields_for_object( $attribute, $request ); |
|
|
|
|
|
|
257
|
|
|
|
|
258
|
|
|
/** |
|
259
|
|
|
* Fires after a single product attribute is created or updated via the REST API. |
|
260
|
|
|
* |
|
261
|
|
|
* @param stdObject $attribute Inserted attribute object. |
|
262
|
|
|
* @param WP_REST_Request $request Request object. |
|
263
|
|
|
* @param boolean $creating True when creating attribute, false when updating. |
|
264
|
|
|
*/ |
|
265
|
|
|
do_action( 'woocommerce_rest_insert_product_attribute', $attribute, $request, true ); |
|
266
|
|
|
|
|
267
|
|
|
$request->set_param( 'context', 'edit' ); |
|
268
|
|
|
$response = $this->prepare_item_for_response( $attribute, $request ); |
|
|
|
|
|
|
269
|
|
|
$response = rest_ensure_response( $response ); |
|
270
|
|
|
$response->set_status( 201 ); |
|
271
|
|
|
$response->header( 'Location', rest_url( '/' . $this->namespace . '/' . $this->rest_base . '/' . $attribute->attribute_id ) ); |
|
272
|
|
|
|
|
273
|
|
|
// Clear transients. |
|
274
|
|
|
flush_rewrite_rules(); |
|
275
|
|
|
delete_transient( 'wc_attribute_taxonomies' ); |
|
276
|
|
|
|
|
277
|
|
|
return $response; |
|
278
|
|
|
} |
|
279
|
|
|
|
|
280
|
|
|
/** |
|
281
|
|
|
* Get a single attribute. |
|
282
|
|
|
* |
|
283
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
284
|
|
|
* @return WP_REST_Request|WP_Error |
|
285
|
|
|
*/ |
|
286
|
|
|
public function get_item( $request ) { |
|
287
|
|
|
global $wpdb; |
|
288
|
|
|
|
|
289
|
|
|
$attribute = $this->get_attribute( $request['id'] ); |
|
290
|
|
|
|
|
291
|
|
|
if ( is_wp_error( $attribute ) ) { |
|
292
|
|
|
return $attribute; |
|
293
|
|
|
} |
|
294
|
|
|
|
|
295
|
|
|
$response = $this->prepare_item_for_response( $attribute, $request ); |
|
|
|
|
|
|
296
|
|
|
|
|
297
|
|
|
return rest_ensure_response( $response ); |
|
298
|
|
|
} |
|
299
|
|
|
|
|
300
|
|
|
/** |
|
301
|
|
|
* Update a single term from a taxonomy. |
|
302
|
|
|
* |
|
303
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
304
|
|
|
* @return WP_REST_Request|WP_Error |
|
305
|
|
|
*/ |
|
306
|
|
|
public function update_item( $request ) { |
|
307
|
|
|
global $wpdb; |
|
308
|
|
|
|
|
309
|
|
|
$id = (int) $request['id']; |
|
310
|
|
|
$format = array( '%s', '%s', '%s', '%s', '%d' ); |
|
311
|
|
|
$args = array( |
|
312
|
|
|
'attribute_label' => $request['name'], |
|
313
|
|
|
'attribute_name' => $request['slug'], |
|
314
|
|
|
'attribute_type' => $request['type'], |
|
315
|
|
|
'attribute_orderby' => $request['order_by'], |
|
316
|
|
|
'attribute_public' => $request['has_archives'], |
|
317
|
|
|
); |
|
318
|
|
|
|
|
319
|
|
|
$i = 0; |
|
320
|
|
|
foreach ( $args as $key => $value ) { |
|
321
|
|
|
if ( empty( $value ) && ! is_bool( $value ) ) { |
|
322
|
|
|
unset( $args[ $key ] ); |
|
323
|
|
|
unset( $format[ $i ] ); |
|
324
|
|
|
} |
|
325
|
|
|
|
|
326
|
|
|
$i++; |
|
327
|
|
|
} |
|
328
|
|
|
|
|
329
|
|
|
// Set the attribute slug. |
|
330
|
|
|
if ( ! empty( $args['attribute_name'] ) ) { |
|
331
|
|
|
$args['attribute_name'] = preg_replace( '/^pa\_/', '', wc_sanitize_taxonomy_name( stripslashes( $args['attribute_name'] ) ) ); |
|
332
|
|
|
|
|
333
|
|
|
$valid_slug = $this->validate_attribute_slug( $args['attribute_name'], true ); |
|
334
|
|
|
if ( is_wp_error( $valid_slug ) ) { |
|
335
|
|
|
return $valid_slug; |
|
336
|
|
|
} |
|
337
|
|
|
} |
|
338
|
|
|
|
|
339
|
|
|
$update = $wpdb->update( |
|
340
|
|
|
$wpdb->prefix . 'woocommerce_attribute_taxonomies', |
|
341
|
|
|
$args, |
|
342
|
|
|
array( 'attribute_id' => $id ), |
|
343
|
|
|
$format, |
|
344
|
|
|
array( '%d' ) |
|
345
|
|
|
); |
|
346
|
|
|
|
|
347
|
|
|
// Checks for errors. |
|
348
|
|
View Code Duplication |
if ( false === $update ) { |
|
|
|
|
|
|
349
|
|
|
return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Could not edit the attribute', 'woocommerce' ), array( 'status' => 400 ) ); |
|
350
|
|
|
} |
|
351
|
|
|
|
|
352
|
|
|
$attribute = $this->get_attribute( $id ); |
|
353
|
|
|
|
|
354
|
|
|
if ( is_wp_error( $attribute ) ) { |
|
355
|
|
|
return $attribute; |
|
356
|
|
|
} |
|
357
|
|
|
|
|
358
|
|
|
$this->update_additional_fields_for_object( $attribute, $request ); |
|
|
|
|
|
|
359
|
|
|
|
|
360
|
|
|
/** |
|
361
|
|
|
* Fires after a single product attribute is created or updated via the REST API. |
|
362
|
|
|
* |
|
363
|
|
|
* @param stdObject $attribute Inserted attribute object. |
|
364
|
|
|
* @param WP_REST_Request $request Request object. |
|
365
|
|
|
* @param boolean $creating True when creating attribute, false when updating. |
|
366
|
|
|
*/ |
|
367
|
|
|
do_action( 'woocommerce_rest_insert_product_attribute', $attribute, $request, false ); |
|
368
|
|
|
|
|
369
|
|
|
$request->set_param( 'context', 'edit' ); |
|
370
|
|
|
$response = $this->prepare_item_for_response( $attribute, $request ); |
|
|
|
|
|
|
371
|
|
|
|
|
372
|
|
|
// Clear transients. |
|
373
|
|
|
flush_rewrite_rules(); |
|
374
|
|
|
delete_transient( 'wc_attribute_taxonomies' ); |
|
375
|
|
|
|
|
376
|
|
|
return rest_ensure_response( $response ); |
|
377
|
|
|
} |
|
378
|
|
|
|
|
379
|
|
|
/** |
|
380
|
|
|
* Delete a single attribute. |
|
381
|
|
|
* |
|
382
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
383
|
|
|
* @return WP_REST_Response|WP_Error |
|
384
|
|
|
*/ |
|
385
|
|
|
public function delete_item( $request ) { |
|
386
|
|
|
global $wpdb; |
|
387
|
|
|
|
|
388
|
|
|
$force = isset( $request['force'] ) ? (bool) $request['force'] : false; |
|
389
|
|
|
|
|
390
|
|
|
// We don't support trashing for this type, error out. |
|
391
|
|
|
if ( ! $force ) { |
|
392
|
|
|
return new WP_Error( 'woocommerce_rest_trash_not_supported', __( 'Resource does not support trashing.', 'woocommerce' ), array( 'status' => 501 ) ); |
|
393
|
|
|
} |
|
394
|
|
|
|
|
395
|
|
|
$attribute = $this->get_attribute( $request['id'] ); |
|
396
|
|
|
|
|
397
|
|
|
if ( is_wp_error( $attribute ) ) { |
|
398
|
|
|
return $attribute; |
|
399
|
|
|
} |
|
400
|
|
|
|
|
401
|
|
|
$request->set_param( 'context', 'edit' ); |
|
402
|
|
|
$response = $this->prepare_item_for_response( $attribute, $request ); |
|
|
|
|
|
|
403
|
|
|
|
|
404
|
|
|
$deleted = $wpdb->delete( |
|
405
|
|
|
$wpdb->prefix . 'woocommerce_attribute_taxonomies', |
|
406
|
|
|
array( 'attribute_id' => $attribute->attribute_id ), |
|
407
|
|
|
array( '%d' ) |
|
408
|
|
|
); |
|
409
|
|
|
|
|
410
|
|
View Code Duplication |
if ( false === $deleted ) { |
|
|
|
|
|
|
411
|
|
|
return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'The resource cannot be deleted.', 'woocommerce' ), array( 'status' => 500 ) ); |
|
412
|
|
|
} |
|
413
|
|
|
|
|
414
|
|
|
$taxonomy = wc_attribute_taxonomy_name( $attribute->attribute_name ); |
|
415
|
|
|
|
|
416
|
|
|
if ( taxonomy_exists( $taxonomy ) ) { |
|
417
|
|
|
$terms = get_terms( $taxonomy, 'orderby=name&hide_empty=0' ); |
|
418
|
|
|
foreach ( $terms as $term ) { |
|
419
|
|
|
wp_delete_term( $term->term_id, $taxonomy ); |
|
420
|
|
|
} |
|
421
|
|
|
} |
|
422
|
|
|
|
|
423
|
|
|
/** |
|
424
|
|
|
* Fires after a single attribute is deleted via the REST API. |
|
425
|
|
|
* |
|
426
|
|
|
* @param stdObject $attribute The deleted attribute. |
|
427
|
|
|
* @param WP_REST_Response $response The response data. |
|
428
|
|
|
* @param WP_REST_Request $request The request sent to the API. |
|
429
|
|
|
*/ |
|
430
|
|
|
do_action( 'woocommerce_rest_delete_product_attribute', $attribute, $response, $request ); |
|
431
|
|
|
|
|
432
|
|
|
// Fires woocommerce_attribute_deleted hook. |
|
433
|
|
|
do_action( 'woocommerce_attribute_deleted', $attribute->attribute_id, $attribute->attribute_name, $taxonomy ); |
|
434
|
|
|
|
|
435
|
|
|
// Clear transients. |
|
436
|
|
|
flush_rewrite_rules(); |
|
437
|
|
|
delete_transient( 'wc_attribute_taxonomies' ); |
|
438
|
|
|
|
|
439
|
|
|
return $response; |
|
440
|
|
|
} |
|
441
|
|
|
|
|
442
|
|
|
/** |
|
443
|
|
|
* Prepare a single product attribute output for response. |
|
444
|
|
|
* |
|
445
|
|
|
* @param obj $item Term object. |
|
446
|
|
|
* @param WP_REST_Request $request |
|
447
|
|
|
* @return WP_REST_Response $response |
|
448
|
|
|
*/ |
|
449
|
|
|
public function prepare_item_for_response( $item, $request ) { |
|
450
|
|
|
$data = array( |
|
451
|
|
|
'id' => (int) $item->attribute_id, |
|
452
|
|
|
'name' => $item->attribute_label, |
|
453
|
|
|
'slug' => wc_attribute_taxonomy_name( $item->attribute_name ), |
|
454
|
|
|
'type' => $item->attribute_type, |
|
455
|
|
|
'order_by' => $item->attribute_orderby, |
|
456
|
|
|
'has_archives' => (bool) $item->attribute_public, |
|
457
|
|
|
); |
|
458
|
|
|
|
|
459
|
|
|
$context = ! empty( $request['context'] ) ? $request['context'] : 'view'; |
|
460
|
|
|
$data = $this->add_additional_fields_to_object( $data, $request ); |
|
461
|
|
|
$data = $this->filter_response_by_context( $data, $context ); |
|
462
|
|
|
|
|
463
|
|
|
$response = rest_ensure_response( $data ); |
|
464
|
|
|
|
|
465
|
|
|
$response->add_links( $this->prepare_links( $item ) ); |
|
466
|
|
|
|
|
467
|
|
|
/** |
|
468
|
|
|
* Filter a attribute item returned from the API. |
|
469
|
|
|
* |
|
470
|
|
|
* Allows modification of the product attribute data right before it is returned. |
|
471
|
|
|
* |
|
472
|
|
|
* @param WP_REST_Response $response The response object. |
|
473
|
|
|
* @param object $item The original attribute object. |
|
474
|
|
|
* @param WP_REST_Request $request Request used to generate the response. |
|
475
|
|
|
*/ |
|
476
|
|
|
return apply_filters( 'woocommerce_rest_prepare_product_attribute', $response, $item, $request ); |
|
477
|
|
|
} |
|
478
|
|
|
|
|
479
|
|
|
/** |
|
480
|
|
|
* Prepare links for the request. |
|
481
|
|
|
* |
|
482
|
|
|
* @param object $attribute Attribute object. |
|
483
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
|
|
|
|
|
484
|
|
|
* @return array Links for the given attribute. |
|
485
|
|
|
*/ |
|
486
|
|
|
protected function prepare_links( $attribute ) { |
|
487
|
|
|
$base = '/' . $this->namespace . '/' . $this->rest_base; |
|
488
|
|
|
$links = array( |
|
489
|
|
|
'self' => array( |
|
490
|
|
|
'href' => rest_url( trailingslashit( $base ) . $attribute->attribute_id ), |
|
491
|
|
|
), |
|
492
|
|
|
'collection' => array( |
|
493
|
|
|
'href' => rest_url( $base ), |
|
494
|
|
|
), |
|
495
|
|
|
); |
|
496
|
|
|
|
|
497
|
|
|
return $links; |
|
498
|
|
|
} |
|
499
|
|
|
|
|
500
|
|
|
/** |
|
501
|
|
|
* Get the Attribute's schema, conforming to JSON Schema. |
|
502
|
|
|
* |
|
503
|
|
|
* @return array |
|
504
|
|
|
*/ |
|
505
|
|
|
public function get_item_schema() { |
|
506
|
|
|
$schema = array( |
|
507
|
|
|
'$schema' => 'http://json-schema.org/draft-04/schema#', |
|
508
|
|
|
'title' => 'product_attribute', |
|
509
|
|
|
'type' => 'object', |
|
510
|
|
|
'properties' => array( |
|
511
|
|
|
'id' => array( |
|
512
|
|
|
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ), |
|
513
|
|
|
'type' => 'integer', |
|
514
|
|
|
'context' => array( 'view', 'edit' ), |
|
515
|
|
|
'readonly' => true, |
|
516
|
|
|
), |
|
517
|
|
|
'name' => array( |
|
518
|
|
|
'description' => __( 'Attribute name.', 'woocommerce' ), |
|
519
|
|
|
'type' => 'string', |
|
520
|
|
|
'context' => array( 'view', 'edit' ), |
|
521
|
|
|
'arg_options' => array( |
|
522
|
|
|
'sanitize_callback' => 'sanitize_text_field', |
|
523
|
|
|
), |
|
524
|
|
|
), |
|
525
|
|
|
'slug' => array( |
|
526
|
|
|
'description' => __( 'An alphanumeric identifier for the resource unique to its type.', 'woocommerce' ), |
|
527
|
|
|
'type' => 'string', |
|
528
|
|
|
'context' => array( 'view', 'edit' ), |
|
529
|
|
|
'arg_options' => array( |
|
530
|
|
|
'sanitize_callback' => 'sanitize_title', |
|
531
|
|
|
), |
|
532
|
|
|
), |
|
533
|
|
|
'type' => array( |
|
534
|
|
|
'description' => __( 'Type of attribute.', 'woocommerce' ), |
|
535
|
|
|
'type' => 'string', |
|
536
|
|
|
'default' => 'select', |
|
537
|
|
|
'enum' => array_keys( wc_get_attribute_types() ), |
|
538
|
|
|
'context' => array( 'view', 'edit' ), |
|
539
|
|
|
), |
|
540
|
|
|
'order_by' => array( |
|
541
|
|
|
'description' => __( 'Default sort order.', 'woocommerce' ), |
|
542
|
|
|
'type' => 'string', |
|
543
|
|
|
'default' => 'menu_order', |
|
544
|
|
|
'enum' => array( 'menu_order', 'name', 'name_num', 'id' ), |
|
545
|
|
|
'context' => array( 'view', 'edit' ), |
|
546
|
|
|
), |
|
547
|
|
|
'has_archives' => array( |
|
548
|
|
|
'description' => __( 'Enable/Disable attribute archives.', 'woocommerce' ), |
|
549
|
|
|
'type' => 'boolean', |
|
550
|
|
|
'default' => false, |
|
551
|
|
|
'context' => array( 'view', 'edit' ), |
|
552
|
|
|
), |
|
553
|
|
|
), |
|
554
|
|
|
); |
|
555
|
|
|
|
|
556
|
|
|
return $this->add_additional_fields_schema( $schema ); |
|
557
|
|
|
} |
|
558
|
|
|
|
|
559
|
|
|
/** |
|
560
|
|
|
* Get the query params for collections |
|
561
|
|
|
* |
|
562
|
|
|
* @return array |
|
563
|
|
|
*/ |
|
564
|
|
|
public function get_collection_params() { |
|
565
|
|
|
$params = array(); |
|
566
|
|
|
$params['context'] = $this->get_context_param( array( 'default' => 'view' ) ); |
|
567
|
|
|
|
|
568
|
|
|
return $params; |
|
569
|
|
|
} |
|
570
|
|
|
|
|
571
|
|
|
/** |
|
572
|
|
|
* Get attribute name. |
|
573
|
|
|
* |
|
574
|
|
|
* @param WP_REST_Request $request Full details about the request. |
|
575
|
|
|
* @return int|WP_Error |
|
576
|
|
|
*/ |
|
577
|
|
|
protected function get_taxonomy( $request ) { |
|
578
|
|
|
if ( '' !== $this->attribute ) { |
|
579
|
|
|
return $this->attribute; |
|
580
|
|
|
} |
|
581
|
|
|
|
|
582
|
|
|
if ( $request['id'] ) { |
|
583
|
|
|
$name = wc_attribute_taxonomy_name_by_id( (int) $request['id'] ); |
|
584
|
|
|
|
|
585
|
|
|
$this->attribute = $name; |
|
586
|
|
|
} |
|
587
|
|
|
|
|
588
|
|
|
return $this->attribute; |
|
589
|
|
|
} |
|
590
|
|
|
|
|
591
|
|
|
/** |
|
592
|
|
|
* Get attribute data. |
|
593
|
|
|
* |
|
594
|
|
|
* @param int $id Attribute ID. |
|
595
|
|
|
* @return stdClass|WP_Error |
|
596
|
|
|
*/ |
|
597
|
|
|
protected function get_attribute( $id ) { |
|
598
|
|
|
global $wpdb; |
|
599
|
|
|
|
|
600
|
|
|
$attribute = $wpdb->get_row( $wpdb->prepare( " |
|
601
|
|
|
SELECT * |
|
602
|
|
|
FROM {$wpdb->prefix}woocommerce_attribute_taxonomies |
|
603
|
|
|
WHERE attribute_id = %d |
|
604
|
|
|
", $id ) ); |
|
605
|
|
|
|
|
606
|
|
|
if ( is_wp_error( $attribute ) || is_null( $attribute ) ) { |
|
607
|
|
|
return new WP_Error( 'woocommerce_rest_attribute_invalid', __( "Resource doesn't exist.", 'woocommerce' ), array( 'status' => 404 ) ); |
|
608
|
|
|
} |
|
609
|
|
|
|
|
610
|
|
|
return $attribute; |
|
611
|
|
|
} |
|
612
|
|
|
|
|
613
|
|
|
/** |
|
614
|
|
|
* Validate attribute slug. |
|
615
|
|
|
* |
|
616
|
|
|
* @param string $slug |
|
617
|
|
|
* @param bool $new_data |
|
618
|
|
|
* @return bool|WP_Error |
|
619
|
|
|
*/ |
|
620
|
|
|
protected function validate_attribute_slug( $slug, $new_data = true ) { |
|
621
|
|
|
if ( strlen( $slug ) >= 28 ) { |
|
622
|
|
|
return new WP_Error( 'woocommerce_rest_invalid_product_attribute_slug_too_long', sprintf( __( 'Slug "%s" is too long (28 characters max).', 'woocommerce' ), $slug ), array( 'status' => 400 ) ); |
|
623
|
|
|
} else if ( wc_check_if_attribute_name_is_reserved( $slug ) ) { |
|
624
|
|
|
return new WP_Error( 'woocommerce_rest_invalid_product_attribute_slug_reserved_name', sprintf( __( 'Slug "%s" is not allowed because it is a reserved term.', 'woocommerce' ), $slug ), array( 'status' => 400 ) ); |
|
625
|
|
|
} else if ( $new_data && taxonomy_exists( wc_attribute_taxonomy_name( $slug ) ) ) { |
|
626
|
|
|
return new WP_Error( 'woocommerce_rest_invalid_product_attribute_slug_already_exists', sprintf( __( 'Slug "%s" is already in use.', 'woocommerce' ), $slug ), array( 'status' => 400 ) ); |
|
627
|
|
|
} |
|
628
|
|
|
|
|
629
|
|
|
return true; |
|
630
|
|
|
} |
|
631
|
|
|
} |
|
632
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.