Completed
Push — master ( 7f2ea5...5630d2 )
by Mike
09:46
created

ProductVariationSchema::get_schema()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 372
Code Lines 295

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 295
nc 1
nop 0
dl 0
loc 372
rs 8
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Product variation schema.
4
 *
5
 * @package WooCommerce/RestApi
6
 */
7
8
namespace WooCommerce\RestApi\Controllers\Version4\Schema;
9
10
defined( 'ABSPATH' ) || exit;
11
12
/**
13
 * ProductVariationSchema class.
14
 */
15
class ProductVariationSchema extends ProductSchema {
16
17
	/**
18
	 * Return schema for products.
19
	 *
20
	 * @return array
21
	 */
22
	public static function get_schema() {
23
		$weight_unit    = get_option( 'woocommerce_weight_unit' );
24
		$dimension_unit = get_option( 'woocommerce_dimension_unit' );
25
		$schema         = array(
26
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
27
			'title'      => 'product_variation',
28
			'type'       => 'object',
29
			'properties' => array(
30
				'id'                    => array(
31
					'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
32
					'type'        => 'integer',
33
					'context'     => array( 'view', 'edit' ),
34
					'readonly'    => true,
35
				),
36
				'name'                  => array(
37
					'description' => __( 'Product parent name.', 'woocommerce' ),
38
					'type'        => 'string',
39
					'context'     => array( 'view', 'edit' ),
40
				),
41
				'type'                  => array(
42
					'description' => __( 'Product type.', 'woocommerce' ),
43
					'type'        => 'string',
44
					'default'     => 'variation',
45
					'enum'        => array( 'variation' ),
46
					'context'     => array( 'view', 'edit' ),
47
				),
48
				'parent_id'             => array(
49
					'description' => __( 'Product parent ID.', 'woocommerce' ),
50
					'type'        => 'integer',
51
					'context'     => array( 'view', 'edit' ),
52
				),
53
				'date_created'          => array(
54
					'description' => __( "The date the variation was created, in the site's timezone.", 'woocommerce' ),
55
					'type'        => 'date-time',
56
					'context'     => array( 'view', 'edit' ),
57
					'readonly'    => true,
58
				),
59
				'date_modified'         => array(
60
					'description' => __( "The date the variation was last modified, in the site's timezone.", 'woocommerce' ),
61
					'type'        => 'date-time',
62
					'context'     => array( 'view', 'edit' ),
63
					'readonly'    => true,
64
				),
65
				'description'           => array(
66
					'description' => __( 'Variation description.', 'woocommerce' ),
67
					'type'        => 'string',
68
					'context'     => array( 'view', 'edit' ),
69
					'arg_options' => array(
70
						'sanitize_callback' => 'wp_filter_post_kses',
71
					),
72
				),
73
				'permalink'             => array(
74
					'description' => __( 'Variation URL.', 'woocommerce' ),
75
					'type'        => 'string',
76
					'format'      => 'uri',
77
					'context'     => array( 'view', 'edit' ),
78
					'readonly'    => true,
79
				),
80
				'sku'                   => array(
81
					'description' => __( 'Unique identifier.', 'woocommerce' ),
82
					'type'        => 'string',
83
					'context'     => array( 'view', 'edit' ),
84
					'arg_options' => array(
85
						'sanitize_callback' => 'wc_clean',
86
					),
87
				),
88
				'price'                 => array(
89
					'description' => __( 'Current variation price.', 'woocommerce' ),
90
					'type'        => 'string',
91
					'context'     => array( 'view', 'edit' ),
92
					'readonly'    => true,
93
				),
94
				'regular_price'         => array(
95
					'description' => __( 'Variation regular price.', 'woocommerce' ),
96
					'type'        => 'string',
97
					'context'     => array( 'view', 'edit' ),
98
				),
99
				'sale_price'            => array(
100
					'description' => __( 'Variation sale price.', 'woocommerce' ),
101
					'type'        => 'string',
102
					'context'     => array( 'view', 'edit' ),
103
				),
104
				'date_on_sale_from'     => array(
105
					'description' => __( "Start date of sale price, in the site's timezone.", 'woocommerce' ),
106
					'type'        => 'date-time',
107
					'context'     => array( 'view', 'edit' ),
108
				),
109
				'date_on_sale_from_gmt' => array(
110
					'description' => __( 'Start date of sale price, as GMT.', 'woocommerce' ),
111
					'type'        => 'date-time',
112
					'context'     => array( 'view', 'edit' ),
113
				),
114
				'date_on_sale_to'       => array(
115
					'description' => __( "End date of sale price, in the site's timezone.", 'woocommerce' ),
116
					'type'        => 'date-time',
117
					'context'     => array( 'view', 'edit' ),
118
				),
119
				'date_on_sale_to_gmt'   => array(
120
					'description' => __( "End date of sale price, in the site's timezone.", 'woocommerce' ),
121
					'type'        => 'date-time',
122
					'context'     => array( 'view', 'edit' ),
123
				),
124
				'on_sale'               => array(
125
					'description' => __( 'Shows if the variation is on sale.', 'woocommerce' ),
126
					'type'        => 'boolean',
127
					'context'     => array( 'view', 'edit' ),
128
					'readonly'    => true,
129
				),
130
				'status'                => array(
131
					'description' => __( 'Variation status.', 'woocommerce' ),
132
					'type'        => 'string',
133
					'default'     => 'publish',
134
					'enum'        => array_keys( get_post_statuses() ),
135
					'context'     => array( 'view', 'edit' ),
136
				),
137
				'purchasable'           => array(
138
					'description' => __( 'Shows if the variation can be bought.', 'woocommerce' ),
139
					'type'        => 'boolean',
140
					'context'     => array( 'view', 'edit' ),
141
					'readonly'    => true,
142
				),
143
				'virtual'               => array(
144
					'description' => __( 'If the variation is virtual.', 'woocommerce' ),
145
					'type'        => 'boolean',
146
					'default'     => false,
147
					'context'     => array( 'view', 'edit' ),
148
				),
149
				'downloadable'          => array(
150
					'description' => __( 'If the variation is downloadable.', 'woocommerce' ),
151
					'type'        => 'boolean',
152
					'default'     => false,
153
					'context'     => array( 'view', 'edit' ),
154
				),
155
				'downloads'             => array(
156
					'description' => __( 'List of downloadable files.', 'woocommerce' ),
157
					'type'        => 'array',
158
					'context'     => array( 'view', 'edit' ),
159
					'items'       => array(
160
						'type'       => 'object',
161
						'properties' => array(
162
							'id'   => array(
163
								'description' => __( 'File ID.', 'woocommerce' ),
164
								'type'        => 'string',
165
								'context'     => array( 'view', 'edit' ),
166
							),
167
							'name' => array(
168
								'description' => __( 'File name.', 'woocommerce' ),
169
								'type'        => 'string',
170
								'context'     => array( 'view', 'edit' ),
171
							),
172
							'file' => array(
173
								'description' => __( 'File URL.', 'woocommerce' ),
174
								'type'        => 'string',
175
								'context'     => array( 'view', 'edit' ),
176
							),
177
						),
178
					),
179
				),
180
				'download_limit'        => array(
181
					'description' => __( 'Number of times downloadable files can be downloaded after purchase.', 'woocommerce' ),
182
					'type'        => 'integer',
183
					'default'     => -1,
184
					'context'     => array( 'view', 'edit' ),
185
				),
186
				'download_expiry'       => array(
187
					'description' => __( 'Number of days until access to downloadable files expires.', 'woocommerce' ),
188
					'type'        => 'integer',
189
					'default'     => -1,
190
					'context'     => array( 'view', 'edit' ),
191
				),
192
				'tax_status'            => array(
193
					'description' => __( 'Tax status.', 'woocommerce' ),
194
					'type'        => 'string',
195
					'default'     => 'taxable',
196
					'enum'        => array( 'taxable', 'shipping', 'none' ),
197
					'context'     => array( 'view', 'edit' ),
198
				),
199
				'tax_class'             => array(
200
					'description' => __( 'Tax class.', 'woocommerce' ),
201
					'type'        => 'string',
202
					'context'     => array( 'view', 'edit' ),
203
				),
204
				'manage_stock'          => array(
205
					'description' => __( 'Stock management at variation level.', 'woocommerce' ),
206
					'type'        => 'boolean',
207
					'default'     => false,
208
					'context'     => array( 'view', 'edit' ),
209
				),
210
				'stock_quantity'        => array(
211
					'description' => __( 'Stock quantity.', 'woocommerce' ),
212
					'type'        => 'integer',
213
					'context'     => array( 'view', 'edit' ),
214
				),
215
				'stock_status'          => array(
216
					'description' => __( 'Controls the stock status of the product.', 'woocommerce' ),
217
					'type'        => 'string',
218
					'default'     => 'instock',
219
					'enum'        => array_keys( wc_get_product_stock_status_options() ),
220
					'context'     => array( 'view', 'edit' ),
221
				),
222
				'backorders'            => array(
223
					'description' => __( 'If managing stock, this controls if backorders are allowed.', 'woocommerce' ),
224
					'type'        => 'string',
225
					'default'     => 'no',
226
					'enum'        => array( 'no', 'notify', 'yes' ),
227
					'context'     => array( 'view', 'edit' ),
228
				),
229
				'backorders_allowed'    => array(
230
					'description' => __( 'Shows if backorders are allowed.', 'woocommerce' ),
231
					'type'        => 'boolean',
232
					'context'     => array( 'view', 'edit' ),
233
					'readonly'    => true,
234
				),
235
				'backordered'           => array(
236
					'description' => __( 'Shows if the variation is on backordered.', 'woocommerce' ),
237
					'type'        => 'boolean',
238
					'context'     => array( 'view', 'edit' ),
239
					'readonly'    => true,
240
				),
241
				'weight'                => array(
242
					/* translators: %s: weight unit */
243
					'description' => sprintf( __( 'Variation weight (%s).', 'woocommerce' ), $weight_unit ),
0 ignored issues
show
Bug introduced by
It seems like $weight_unit can also be of type false; however, parameter $args of sprintf() 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

243
					'description' => sprintf( __( 'Variation weight (%s).', 'woocommerce' ), /** @scrutinizer ignore-type */ $weight_unit ),
Loading history...
244
					'type'        => 'string',
245
					'context'     => array( 'view', 'edit' ),
246
				),
247
				'dimensions'            => array(
248
					'description' => __( 'Variation dimensions.', 'woocommerce' ),
249
					'type'        => 'object',
250
					'context'     => array( 'view', 'edit' ),
251
					'properties'  => array(
252
						'length' => array(
253
							/* translators: %s: dimension unit */
254
							'description' => sprintf( __( 'Variation length (%s).', 'woocommerce' ), $dimension_unit ),
255
							'type'        => 'string',
256
							'context'     => array( 'view', 'edit' ),
257
						),
258
						'width'  => array(
259
							/* translators: %s: dimension unit */
260
							'description' => sprintf( __( 'Variation width (%s).', 'woocommerce' ), $dimension_unit ),
261
							'type'        => 'string',
262
							'context'     => array( 'view', 'edit' ),
263
						),
264
						'height' => array(
265
							/* translators: %s: dimension unit */
266
							'description' => sprintf( __( 'Variation height (%s).', 'woocommerce' ), $dimension_unit ),
267
							'type'        => 'string',
268
							'context'     => array( 'view', 'edit' ),
269
						),
270
					),
271
				),
272
				'shipping_class'        => array(
273
					'description' => __( 'Shipping class slug.', 'woocommerce' ),
274
					'type'        => 'string',
275
					'context'     => array( 'view', 'edit' ),
276
				),
277
				'shipping_class_id'     => array(
278
					'description' => __( 'Shipping class ID.', 'woocommerce' ),
279
					'type'        => 'string',
280
					'context'     => array( 'view', 'edit' ),
281
					'readonly'    => true,
282
				),
283
				'image'                 => array(
284
					'description' => __( 'Variation image data.', 'woocommerce' ),
285
					'type'        => 'object',
286
					'context'     => array( 'view', 'edit' ),
287
					'properties'  => array(
288
						'id'                => array(
289
							'description' => __( 'Image ID.', 'woocommerce' ),
290
							'type'        => 'integer',
291
							'context'     => array( 'view', 'edit' ),
292
						),
293
						'date_created'      => array(
294
							'description' => __( "The date the image was created, in the site's timezone.", 'woocommerce' ),
295
							'type'        => 'date-time',
296
							'context'     => array( 'view', 'edit' ),
297
							'readonly'    => true,
298
						),
299
						'date_created_gmt'  => array(
300
							'description' => __( 'The date the image was created, as GMT.', 'woocommerce' ),
301
							'type'        => 'date-time',
302
							'context'     => array( 'view', 'edit' ),
303
							'readonly'    => true,
304
						),
305
						'date_modified'     => array(
306
							'description' => __( "The date the image was last modified, in the site's timezone.", 'woocommerce' ),
307
							'type'        => 'date-time',
308
							'context'     => array( 'view', 'edit' ),
309
							'readonly'    => true,
310
						),
311
						'date_modified_gmt' => array(
312
							'description' => __( 'The date the image was last modified, as GMT.', 'woocommerce' ),
313
							'type'        => 'date-time',
314
							'context'     => array( 'view', 'edit' ),
315
							'readonly'    => true,
316
						),
317
						'src'               => array(
318
							'description' => __( 'Image URL.', 'woocommerce' ),
319
							'type'        => 'string',
320
							'format'      => 'uri',
321
							'context'     => array( 'view', 'edit' ),
322
						),
323
						'name'              => array(
324
							'description' => __( 'Image name.', 'woocommerce' ),
325
							'type'        => 'string',
326
							'context'     => array( 'view', 'edit' ),
327
						),
328
						'alt'               => array(
329
							'description' => __( 'Image alternative text.', 'woocommerce' ),
330
							'type'        => 'string',
331
							'context'     => array( 'view', 'edit' ),
332
						),
333
					),
334
				),
335
				'attributes'            => array(
336
					'description' => __( 'List of attributes.', 'woocommerce' ),
337
					'type'        => 'array',
338
					'context'     => array( 'view', 'edit' ),
339
					'items'       => array(
340
						'type'       => 'object',
341
						'properties' => array(
342
							'id'     => array(
343
								'description' => __( 'Attribute ID.', 'woocommerce' ),
344
								'type'        => 'integer',
345
								'context'     => array( 'view', 'edit' ),
346
							),
347
							'name'   => array(
348
								'description' => __( 'Attribute name.', 'woocommerce' ),
349
								'type'        => 'string',
350
								'context'     => array( 'view', 'edit' ),
351
							),
352
							'option' => array(
353
								'description' => __( 'Selected attribute term name.', 'woocommerce' ),
354
								'type'        => 'string',
355
								'context'     => array( 'view', 'edit' ),
356
							),
357
						),
358
					),
359
				),
360
				'menu_order'            => array(
361
					'description' => __( 'Menu order, used to custom sort products.', 'woocommerce' ),
362
					'type'        => 'integer',
363
					'context'     => array( 'view', 'edit' ),
364
				),
365
				'meta_data'             => array(
366
					'description' => __( 'Meta data.', 'woocommerce' ),
367
					'type'        => 'array',
368
					'context'     => array( 'view', 'edit' ),
369
					'items'       => array(
370
						'type'       => 'object',
371
						'properties' => array(
372
							'id'    => array(
373
								'description' => __( 'Meta ID.', 'woocommerce' ),
374
								'type'        => 'integer',
375
								'context'     => array( 'view', 'edit' ),
376
								'readonly'    => true,
377
							),
378
							'key'   => array(
379
								'description' => __( 'Meta key.', 'woocommerce' ),
380
								'type'        => 'string',
381
								'context'     => array( 'view', 'edit' ),
382
							),
383
							'value' => array(
384
								'description' => __( 'Meta value.', 'woocommerce' ),
385
								'type'        => 'mixed',
386
								'context'     => array( 'view', 'edit' ),
387
							),
388
						),
389
					),
390
				),
391
			),
392
		);
393
		return $schema;
394
	}
395
396
	/**
397
	 * Convert object to match data in the schema.
398
	 *
399
	 * @param \WC_Product_Variation $object Product instance.
400
	 * @param string                $context Request context. Options: 'view' and 'edit'.
401
	 * @return array
402
	 */
403
	public static function object_to_schema( $object, $context ) {
404
		$data = array(
405
			'id'                    => $object->get_id(),
406
			'name'                  => $object->get_name( $context ),
407
			'type'                  => $object->get_type(),
408
			'parent_id'             => $object->get_parent_id( $context ),
409
			'date_created'          => wc_rest_prepare_date_response( $object->get_date_created(), false ),
410
			'date_created_gmt'      => wc_rest_prepare_date_response( $object->get_date_created() ),
411
			'date_modified'         => wc_rest_prepare_date_response( $object->get_date_modified(), false ),
412
			'date_modified_gmt'     => wc_rest_prepare_date_response( $object->get_date_modified() ),
413
			'description'           => wc_format_content( $object->get_description() ),
414
			'permalink'             => $object->get_permalink(),
415
			'sku'                   => $object->get_sku(),
416
			'price'                 => $object->get_price(),
417
			'regular_price'         => $object->get_regular_price(),
418
			'sale_price'            => $object->get_sale_price(),
419
			'date_on_sale_from'     => wc_rest_prepare_date_response( $object->get_date_on_sale_from(), false ),
420
			'date_on_sale_from_gmt' => wc_rest_prepare_date_response( $object->get_date_on_sale_from() ),
421
			'date_on_sale_to'       => wc_rest_prepare_date_response( $object->get_date_on_sale_to(), false ),
422
			'date_on_sale_to_gmt'   => wc_rest_prepare_date_response( $object->get_date_on_sale_to() ),
423
			'on_sale'               => $object->is_on_sale(),
424
			'status'                => $object->get_status(),
425
			'purchasable'           => $object->is_purchasable(),
426
			'virtual'               => $object->is_virtual(),
427
			'downloadable'          => $object->is_downloadable(),
428
			'downloads'             => self::get_downloads( $object ),
429
			'download_limit'        => '' !== $object->get_download_limit() ? (int) $object->get_download_limit() : -1,
0 ignored issues
show
introduced by
The condition '' !== $object->get_download_limit() is always true.
Loading history...
430
			'download_expiry'       => '' !== $object->get_download_expiry() ? (int) $object->get_download_expiry() : -1,
0 ignored issues
show
introduced by
The condition '' !== $object->get_download_expiry() is always true.
Loading history...
431
			'tax_status'            => $object->get_tax_status(),
432
			'tax_class'             => $object->get_tax_class(),
433
			'manage_stock'          => $object->managing_stock(),
434
			'stock_quantity'        => $object->get_stock_quantity(),
435
			'stock_status'          => $object->get_stock_status(),
436
			'backorders'            => $object->get_backorders(),
437
			'backorders_allowed'    => $object->backorders_allowed(),
438
			'backordered'           => $object->is_on_backorder(),
439
			'weight'                => $object->get_weight(),
440
			'dimensions'            => array(
441
				'length' => $object->get_length(),
442
				'width'  => $object->get_width(),
443
				'height' => $object->get_height(),
444
			),
445
			'shipping_class'        => $object->get_shipping_class(),
446
			'shipping_class_id'     => $object->get_shipping_class_id(),
447
			'image'                 => self::get_image( $object ),
448
			'attributes'            => self::get_attributes( $object ),
449
			'menu_order'            => $object->get_menu_order(),
450
			'meta_data'             => $object->get_meta_data(),
451
		);
452
		return $data;
453
	}
454
455
	/**
456
	 * Take data in the format of the schema and convert to a product object.
457
	 *
458
	 * @param  \WP_REST_Request $request Request object.
459
	 * @return \WP_Error|\WC_Product_Variation
460
	 */
461
	public static function schema_to_object( $request ) {
462
		if ( isset( $request['id'] ) ) {
463
			$object = wc_get_product( absint( $request['id'] ) );
464
		} else {
465
			$object = new \WC_Product_Variation();
466
		}
467
468
		$object->set_parent_id( absint( $request['product_id'] ) );
469
470
		self::set_object_data( $object, $request );
471
472
		return $object;
473
	}
474
475
	/**
476
	 * Set object data from a request.
477
	 *
478
	 * @param \WC_Product_Variation $object Product object.
479
	 * @param \WP_REST_Request      $request Request object.
480
	 */
481
	protected static function set_object_data( &$object, $request ) {
482
		$props_to_set = [
483
			'status',
484
			'sku',
485
			'virtual',
486
			'downloadable',
487
			'download_limit',
488
			'download_expiry',
489
			'manage_stock',
490
			'stock_status',
491
			'backorders',
492
			'regular_price',
493
			'sale_price',
494
			'date_on_sale_from',
495
			'date_on_sale_from_gmt',
496
			'date_on_sale_to',
497
			'date_on_sale_to_gmt',
498
			'tax_class',
499
			'description',
500
			'menu_order',
501
			'stock_quantity',
502
		];
503
504
		foreach ( $props_to_set as $prop ) {
505
			if ( isset( $request[ $prop ] ) && is_callable( array( $object, "set_$prop" ) ) ) {
506
				$object->{"set_$prop"}( $request[ $prop ] );
507
			}
508
		}
509
510
		// Allow set meta_data.
511
		if ( isset( $request['meta_data'] ) ) {
512
			foreach ( $request['meta_data'] as $meta ) {
513
				$object->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' );
0 ignored issues
show
Bug introduced by
It seems like IssetNode ? $meta['id'] : '' can also be of type string; however, parameter $meta_id of WC_Data::update_meta_data() does only seem to accept integer, 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

513
				$object->update_meta_data( $meta['key'], $meta['value'], /** @scrutinizer ignore-type */ isset( $meta['id'] ) ? $meta['id'] : '' );
Loading history...
514
			}
515
		}
516
517
		// Check for featured/gallery images, upload it and set it.
518
		if ( isset( $request['image'] ) ) {
519
			self::set_image( $object, $request['image'] );
520
		}
521
522
		// Downloadable files.
523
		if ( isset( $request['downloads'] ) && is_array( $request['downloads'] ) ) {
524
			self::set_downloadable_files( $object, $request['downloads'] );
525
		}
526
527
		if ( isset( $request['attributes'] ) ) {
528
			self::set_attributes( $object, $request['attributes'] );
529
		}
530
531
		self::set_shipping_data( $object, $request );
532
	}
533
534
	/**
535
	 * Get the image for a product variation.
536
	 *
537
	 * @param \WC_Product_Variation $object Variation data.
538
	 * @return array
539
	 */
540
	protected static function get_image( $object ) {
541
		if ( ! $object->get_image_id() ) {
542
			return;
543
		}
544
545
		$attachment_id   = $object->get_image_id();
546
		$attachment_post = get_post( $attachment_id );
0 ignored issues
show
Bug introduced by
$attachment_id of type string is incompatible with the type WP_Post|integer|null expected by parameter $post of get_post(). ( Ignorable by Annotation )

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

546
		$attachment_post = get_post( /** @scrutinizer ignore-type */ $attachment_id );
Loading history...
547
		if ( is_null( $attachment_post ) ) {
548
			return;
549
		}
550
551
		$attachment = wp_get_attachment_image_src( $attachment_id, 'full' );
0 ignored issues
show
Bug introduced by
$attachment_id of type string is incompatible with the type integer expected by parameter $attachment_id of wp_get_attachment_image_src(). ( Ignorable by Annotation )

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

551
		$attachment = wp_get_attachment_image_src( /** @scrutinizer ignore-type */ $attachment_id, 'full' );
Loading history...
552
		if ( ! is_array( $attachment ) ) {
553
			return;
554
		}
555
556
		if ( ! isset( $image ) ) {
557
			return array(
558
				'id'                => (int) $attachment_id,
559
				'date_created'      => wc_rest_prepare_date_response( $attachment_post->post_date, false ),
560
				'date_created_gmt'  => wc_rest_prepare_date_response( strtotime( $attachment_post->post_date_gmt ) ),
561
				'date_modified'     => wc_rest_prepare_date_response( $attachment_post->post_modified, false ),
562
				'date_modified_gmt' => wc_rest_prepare_date_response( strtotime( $attachment_post->post_modified_gmt ) ),
563
				'src'               => current( $attachment ),
564
				'name'              => get_the_title( $attachment_id ),
0 ignored issues
show
Bug introduced by
$attachment_id of type string is incompatible with the type WP_Post|integer expected by parameter $post of get_the_title(). ( Ignorable by Annotation )

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

564
				'name'              => get_the_title( /** @scrutinizer ignore-type */ $attachment_id ),
Loading history...
565
				'alt'               => get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ),
0 ignored issues
show
Bug introduced by
$attachment_id of type string is incompatible with the type integer expected by parameter $post_id of get_post_meta(). ( Ignorable by Annotation )

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

565
				'alt'               => get_post_meta( /** @scrutinizer ignore-type */ $attachment_id, '_wp_attachment_image_alt', true ),
Loading history...
566
			);
567
		}
568
	}
569
570
	/**
571
	 * Set product object's attributes.
572
	 *
573
	 * @param \WC_Product_Variation $object Product object.
574
	 * @param array                 $raw_attributes Attribute data from request.
575
	 */
576
	protected static function set_attributes( &$object, $raw_attributes ) {
577
		$attributes = array();
578
		$parent     = wc_get_product( $object->get_parent_id() );
579
580
		if ( ! $parent ) {
0 ignored issues
show
introduced by
$parent is of type WC_Product, thus it always evaluated to true.
Loading history...
581
			return new \WP_Error(
582
				// Translators: %d parent ID.
583
				"woocommerce_rest_product_variation_invalid_parent", sprintf( __( 'Cannot set attributes due to invalid parent product.', 'woocommerce' ), $object->get_parent_id() ), array(
584
					'status' => 404,
585
				)
586
			);
587
		}
588
589
		$parent_attributes = $parent->get_attributes();
590
591
		foreach ( $raw_attributes as $attribute ) {
592
			$attribute_id   = 0;
593
			$attribute_name = '';
594
595
			// Check ID for global attributes or name for product attributes.
596
			if ( ! empty( $attribute['id'] ) ) {
597
				$attribute_id   = absint( $attribute['id'] );
598
				$attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id );
599
			} elseif ( ! empty( $attribute['name'] ) ) {
600
				$attribute_name = sanitize_title( $attribute['name'] );
601
			}
602
603
			if ( ! $attribute_id && ! $attribute_name ) {
604
				continue;
605
			}
606
607
			if ( ! isset( $parent_attributes[ $attribute_name ] ) || ! $parent_attributes[ $attribute_name ]->get_variation() ) {
608
				continue;
609
			}
610
611
			$attribute_key   = sanitize_title( $parent_attributes[ $attribute_name ]->get_name() );
612
			$attribute_value = isset( $attribute['option'] ) ? wc_clean( stripslashes( $attribute['option'] ) ) : '';
613
614
			if ( $parent_attributes[ $attribute_name ]->is_taxonomy() ) {
615
				// If dealing with a taxonomy, we need to get the slug from the name posted to the API.
616
				$term = get_term_by( 'name', $attribute_value, $attribute_name );
617
618
				if ( $term && ! is_wp_error( $term ) ) {
619
					$attribute_value = $term->slug;
620
				} else {
621
					$attribute_value = sanitize_title( $attribute_value );
622
				}
623
			}
624
625
			$attributes[ $attribute_key ] = $attribute_value;
626
		}
627
628
		$object->set_attributes( $attributes );
629
	}
630
631
	/**
632
	 * Set product images.
633
	 *
634
	 * @throws \WC_REST_Exception REST API exceptions.
635
	 *
636
	 * @param \WC_Product_Variation $object Product instance.
637
	 * @param array                 $image  Image data.
638
	 */
639
	protected static function set_image( &$object, $image ) {
640
		if ( ! empty( $image ) ) {
641
			$attachment_id = isset( $image['id'] ) ? absint( $image['id'] ) : 0;
642
643
			if ( 0 === $attachment_id && isset( $image['src'] ) ) {
644
				$upload = wc_rest_upload_image_from_url( esc_url_raw( $image['src'] ) );
645
646
				if ( is_wp_error( $upload ) ) {
647
					if ( ! apply_filters( 'woocommerce_rest_suppress_image_upload_error', false, $upload, $object->get_id(), array( $image ) ) ) {
648
						throw new \WC_REST_Exception( 'woocommerce_variation_image_upload_error', $upload->get_error_message(), 400 );
649
					}
650
				}
651
652
				$attachment_id = wc_rest_set_uploaded_image_as_attachment( $upload, $object->get_id() );
0 ignored issues
show
Bug introduced by
It seems like $upload can also be of type WP_Error; however, parameter $upload of wc_rest_set_uploaded_image_as_attachment() does only seem to accept array, 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

652
				$attachment_id = wc_rest_set_uploaded_image_as_attachment( /** @scrutinizer ignore-type */ $upload, $object->get_id() );
Loading history...
653
			}
654
655
			if ( ! wp_attachment_is_image( $attachment_id ) ) {
656
				/* translators: %s: attachment ID */
657
				throw new \WC_REST_Exception( 'woocommerce_variation_invalid_image_id', sprintf( __( '#%s is an invalid image ID.', 'woocommerce' ), $attachment_id ), 400 );
658
			}
659
660
			$object->set_image_id( $attachment_id );
661
662
			// Set the image alt if present.
663
			if ( ! empty( $image['alt'] ) ) {
664
				update_post_meta( $attachment_id, '_wp_attachment_image_alt', wc_clean( $image['alt'] ) );
665
			}
666
667
			// Set the image name if present.
668
			if ( ! empty( $image['name'] ) ) {
669
				wp_update_post(
670
					array(
671
						'ID'         => $attachment_id,
672
						'post_title' => $image['name'],
673
					)
674
				);
675
			}
676
		} else {
677
			$object->set_image_id( '' );
678
		}
679
	}
680
}
681