WC_Product_Variation::get_image()   B
last analyzed

Complexity

Conditions 7
Paths 5

Size

Total Lines 14
Code Lines 12

Duplication

Lines 3
Ratio 21.43 %

Importance

Changes 0
Metric Value
cc 7
dl 3
loc 14
rs 8.2222
c 0
b 0
f 0
eloc 12
nc 5
nop 3
1
<?php
2
3
if ( ! defined( 'ABSPATH' ) ) {
4
	exit; // Exit if accessed directly
5
}
6
7
/**
8
 * Product Variation Class.
9
 *
10
 * The WooCommerce product variation class handles product variation data.
11
 *
12
 * @class       WC_Product_Variation
13
 * @version     2.2.0
14
 * @package     WooCommerce/Classes
15
 * @category    Class
16
 * @author      WooThemes
17
 */
18
class WC_Product_Variation extends WC_Product {
19
20
	/** @public int ID of the variation itself. */
21
	public $variation_id;
22
23
	/** @public object Parent Variable product object. */
24
	public $parent;
25
26
	/** @public string Stores the shipping class of the variation. */
27
	public $variation_shipping_class         = false;
28
29
	/** @public int Stores the shipping class ID of the variation. */
30
	public $variation_shipping_class_id      = false;
31
32
	/** @public unused vars @deprecated in 2.2 */
33
	public $variation_has_sku                = true;
34
	public $variation_has_length             = true;
35
	public $variation_has_width              = true;
36
	public $variation_has_height             = true;
37
	public $variation_has_weight             = true;
38
	public $variation_has_tax_class          = true;
39
	public $variation_has_downloadable_files = true;
40
41
	/** @private array Data which is only at variation level - no inheritance plus their default values if left blank. */
42
	protected $variation_level_meta_data = array(
43
		'downloadable'          => 'no',
44
		'virtual'               => 'no',
45
		'manage_stock'          => 'no',
46
		'sale_price_dates_from' => '',
47
		'sale_price_dates_to'   => '',
48
		'price'                 => '',
49
		'regular_price'         => '',
50
		'sale_price'            => '',
51
		'stock'                 => 0,
52
		'stock_status'          => 'instock',
53
		'downloadable_files'    => array()
54
	);
55
56
	/** @private array Data which can be at variation level, otherwise fallback to parent if not set. */
57
	protected $variation_inherited_meta_data = array(
58
		'tax_class'  => '',
59
		'backorders' => 'no',
60
		'sku'        => '',
61
		'weight'     => '',
62
		'length'     => '',
63
		'width'      => '',
64
		'height'     => ''
65
	);
66
67
	/**
68
	 * Loads required variation data.
69
	 *
70
	 * @param int $variation ID of the variation to load
71
	 * @param array $args Array of the arguments containing parent product data
72
	 */
73
	public function __construct( $variation, $args = array() ) {
74
		if ( is_object( $variation ) ) {
75
			$this->variation_id = absint( $variation->ID );
76
		} else {
77
			$this->variation_id = absint( $variation );
78
		}
79
80
		/* Get main product data from parent (args) */
81
		$this->id = ! empty( $args['parent_id'] ) ? intval( $args['parent_id'] ) : wp_get_post_parent_id( $this->variation_id );
82
83
		// The post doesn't have a parent id, therefore its invalid and we should prevent this being created.
84
		if ( empty( $this->id ) ) {
85
			throw new Exception( sprintf( 'No parent product set for variation #%d', $this->variation_id ), 422 );
86
		}
87
88
		$this->product_type = 'variation';
89
		$this->parent       = ! empty( $args['parent'] ) ? $args['parent'] : wc_get_product( $this->id );
90
		$this->post         = ! empty( $this->parent->post ) ? $this->parent->post : array();
91
	}
92
93
	/**
94
	 * __isset function.
95
	 *
96
	 * @param mixed $key
97
	 * @return bool
98
	 */
99
	public function __isset( $key ) {
100
		if ( in_array( $key, array_keys( $this->variation_level_meta_data ) ) ) {
101
			return metadata_exists( 'post', $this->variation_id, '_' . $key );
102
		} elseif ( in_array( $key, array_keys( $this->variation_inherited_meta_data ) ) ) {
103
			return metadata_exists( 'post', $this->variation_id, '_' . $key ) || metadata_exists( 'post', $this->id, '_' . $key );
104
		} else {
105
			return metadata_exists( 'post', $this->id, '_' . $key );
106
		}
107
	}
108
109
	/**
110
	 * Get method returns variation meta data if set, otherwise in most cases the data from the parent.
111
	 *
112
	 * @param string $key
113
	 * @return mixed
114
	 */
115
	public function __get( $key ) {
116
		if ( in_array( $key, array_keys( $this->variation_level_meta_data ) ) ) {
117
118
			$value = get_post_meta( $this->variation_id, '_' . $key, true );
119
120
			if ( '' === $value ) {
121
				$value = $this->variation_level_meta_data[ $key ];
122
			}
123
124
		} elseif ( in_array( $key, array_keys( $this->variation_inherited_meta_data ) ) ) {
125
126
			$value = metadata_exists( 'post', $this->variation_id, '_' . $key ) ? get_post_meta( $this->variation_id, '_' . $key, true ) : get_post_meta( $this->id, '_' . $key, true );
127
128
			// Handle meta data keys which can be empty at variation level to cause inheritance
129
			if ( '' === $value && in_array( $key, array( 'sku', 'weight', 'length', 'width', 'height' ) ) ) {
130
				$value = get_post_meta( $this->id, '_' . $key, true );
131
			}
132
133
			if ( '' === $value ) {
134
				$value = $this->variation_inherited_meta_data[ $key ];
135
			}
136
137
		} elseif ( 'variation_data' === $key ) {
138
			return $this->variation_data = wc_get_product_variation_attributes( $this->variation_id );
139
140
		} elseif ( 'variation_has_stock' === $key ) {
141
			return $this->managing_stock();
142
143
		} else {
144
			$value = metadata_exists( 'post', $this->variation_id, '_' . $key ) ? get_post_meta( $this->variation_id, '_' . $key, true ) : parent::__get( $key );
145
		}
146
147
		return $value;
148
	}
149
150
	/**
151
	 * Return the variation ID
152
	 *
153
	 * @since 2.5.0
154
	 * @return int variation (post) ID
155
	 */
156
	public function get_id() {
157
		return $this->variation_id;
158
	}
159
160
	/**
161
	 * Returns whether or not the product post exists.
162
	 *
163
	 * @return bool
164
	 */
165
	public function exists() {
166
		return ! empty( $this->id );
167
	}
168
169
	/**
170
	 * Wrapper for get_permalink. Adds this variations attributes to the URL.
171
	 *
172
	 * @param  $item_object item array If a cart or order item is passed, we can get a link containing the exact attributes selected for the variation, rather than the default attributes.
173
	 * @return string
174
	 */
175
	public function get_permalink( $item_object = null ) {
176
		if ( ! empty( $item_object['variation'] ) ) {
177
			$data = $item_object['variation'];
178
		} elseif ( ! empty( $item_object['item_meta_array'] ) ) {
179
			$data_keys    = array_map( 'wc_variation_attribute_name', wp_list_pluck( $item_object['item_meta_array'], 'key' ) );
180
			$data_values  = wp_list_pluck( $item_object['item_meta_array'], 'value' );
181
			$data         = array_intersect_key( array_combine( $data_keys, $data_values ), $this->variation_data );
182
		} else {
183
			$data = $this->variation_data;
184
		}
185
		return add_query_arg( array_map( 'urlencode', array_filter( $data ) ), get_permalink( $this->id ) );
186
	}
187
188
	/**
189
	 * Get the add to url used mainly in loops.
190
	 *
191
	 * @return string
192
	 */
193
	public function add_to_cart_url() {
194
		$variation_data = array_map( 'urlencode', $this->variation_data );
195
		$url            = $this->is_purchasable() && $this->is_in_stock() ? remove_query_arg( 'added-to-cart', add_query_arg( array_merge( array( 'variation_id' => $this->variation_id, 'add-to-cart' => $this->id ), $variation_data ) ) ) : get_permalink( $this->id );
196
197
		return apply_filters( 'woocommerce_product_add_to_cart_url', $url, $this );
198
	}
199
200
	/**
201
	 * Get the add to cart button text.
202
	 *
203
	 * @return string
204
	 */
205
	public function add_to_cart_text() {
206
		$text = $this->is_purchasable() && $this->is_in_stock() ? __( 'Add to cart', 'woocommerce' ) : __( 'Read More', 'woocommerce' );
207
208
		return apply_filters( 'woocommerce_product_add_to_cart_text', $text, $this );
209
	}
210
211
	/**
212
	 * Checks if this particular variation is visible. Invisible variations are enabled and can be selected, but no price / stock info is displayed.
213
	 * Instead, a suitable 'unavailable' message is displayed.
214
	 * Invisible by default: Disabled variations and variations with an empty price.
215
	 *
216
	 * @return bool
217
	 */
218
	public function variation_is_visible() {
219
		$visible = true;
220
221
		// Published == enabled checkbox
222
		if ( get_post_status( $this->variation_id ) != 'publish' ) {
223
			$visible = false;
224
		}
225
226
		// Price not set
227
		elseif ( $this->get_price() === "" ) {
228
			$visible = false;
229
		}
230
231
		return apply_filters( 'woocommerce_variation_is_visible', $visible, $this->variation_id, $this->id, $this );
232
	}
233
234
	/**
235
	 * Controls whether this particular variation will appear greyed-out (inactive) or not (active).
236
	 * Used by extensions to make incompatible variations appear greyed-out, etc.
237
	 * Other possible uses: prevent out-of-stock variations from being selected.
238
	 *
239
	 * @return bool
240
	 */
241
	public function variation_is_active() {
242
		return apply_filters( 'woocommerce_variation_is_active', true, $this );
243
	}
244
245
	/**
246
	 * Returns false if the product cannot be bought.
247
	 * Override abstract method so that: i) Disabled variations are not be purchasable by admins. ii) Enabled variations are not purchasable if the parent product is not purchasable.
248
	 *
249
	 * @return bool
250
	 */
251
	public function is_purchasable() {
252
		// Published == enabled checkbox
253
		if ( get_post_status( $this->variation_id ) != 'publish' ) {
254
			$purchasable = false;
255
		} else {
256
			$purchasable = parent::is_purchasable();
257
		}
258
		return apply_filters( 'woocommerce_variation_is_purchasable', $purchasable, $this );
259
	}
260
261
	/**
262
	 * Returns whether or not the variations parent is visible.
263
	 *
264
	 * @return bool
265
	 */
266
	public function parent_is_visible() {
267
		return $this->is_visible();
268
	}
269
270
	/**
271
	 * Get variation ID.
272
	 *
273
	 * @return int
274
	 */
275
	public function get_variation_id() {
276
		return absint( $this->variation_id );
277
	}
278
279
	/**
280
	 * Get variation attribute values.
281
	 *
282
	 * @return array of attributes and their values for this variation
283
	 */
284
	public function get_variation_attributes() {
285
		return $this->variation_data;
286
	}
287
288
	/**
289
	 * Check if all variation's attributes are set.
290
	 *
291
	 * @return boolean
292
	 */
293
	public function has_all_attributes_set() {
294
295
		$set = true;
296
297
		// undefined attributes have null strings as array values
298
		foreach( $this->get_variation_attributes() as $att ){
299
			if( ! $att ){
300
				$set = false;
301
				break;
302
			}
303
		}
304
305
		return $set;
306
307
	}
308
309
	/**
310
	 * Get variation price HTML. Prices are not inherited from parents.
311
	 *
312
	 * @return string containing the formatted price
313
	 */
314
	public function get_price_html( $price = '' ) {
315
316
		$display_price         = $this->get_display_price();
317
		$display_regular_price = $this->get_display_price( $this->get_regular_price() );
318
		$display_sale_price    = $this->get_display_price( $this->get_sale_price() );
319
320
		if ( $this->get_price() !== '' ) {
321
			if ( $this->is_on_sale() ) {
322
				$price = apply_filters( 'woocommerce_variation_sale_price_html', '<del>' . wc_price( $display_regular_price ) . '</del> <ins>' . wc_price( $display_sale_price ) . '</ins>' . $this->get_price_suffix(), $this );
323
			} elseif ( $this->get_price() > 0 ) {
324
				$price = apply_filters( 'woocommerce_variation_price_html', wc_price( $display_price ) . $this->get_price_suffix(), $this );
325
			} else {
326
				$price = apply_filters( 'woocommerce_variation_free_price_html', __( 'Free!', 'woocommerce' ), $this );
327
			}
328
		} else {
329
			$price = apply_filters( 'woocommerce_variation_empty_price_html', '', $this );
330
		}
331
332
		return apply_filters( 'woocommerce_get_variation_price_html', $price, $this );
333
	}
334
335
	/**
336
	 * Gets the main product image ID.
337
	 *
338
	 * @return int
339
	 */
340
	public function get_image_id() {
341
		if ( $this->variation_id && has_post_thumbnail( $this->variation_id ) ) {
342
			$image_id = get_post_thumbnail_id( $this->variation_id );
343
		} elseif ( has_post_thumbnail( $this->id ) ) {
344
			$image_id = get_post_thumbnail_id( $this->id );
345 View Code Duplication
		} elseif ( ( $parent_id = wp_get_post_parent_id( $this->id ) ) && has_post_thumbnail( $parent_id ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
346
			$image_id = get_post_thumbnail_id( $parent_id );
347
		} else {
348
			$image_id = 0;
349
		}
350
		return $image_id;
351
	}
352
353
	/**
354
	 * Gets the main product image.
355
	 *
356
	 * @param string $size (default: 'shop_thumbnail')
357
	 * @param bool True to return $placeholder if no image is found, or false to return an empty string.
358
	 * @return string
359
	 */
360
	public function get_image( $size = 'shop_thumbnail', $attr = array(), $placeholder = true ) {
361
		if ( $this->variation_id && has_post_thumbnail( $this->variation_id ) ) {
362
			$image = get_the_post_thumbnail( $this->variation_id, $size, $attr );
363
		} elseif ( has_post_thumbnail( $this->id ) ) {
364
			$image = get_the_post_thumbnail( $this->id, $size, $attr );
365 View Code Duplication
		} elseif ( ( $parent_id = wp_get_post_parent_id( $this->id ) ) && has_post_thumbnail( $parent_id ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
366
			$image = get_the_post_thumbnail( $parent_id, $size , $attr);
367
		} elseif ( $placeholder ) {
368
			$image = wc_placeholder_img( $size );
369
		} else {
370
			$image = '';
371
		}
372
		return $image;
373
	}
374
375
	/**
376
	 * Returns whether or not the product (or variation) is stock managed.
377
	 *
378
	 * @return bool|string Bool if managed at variation level, 'parent' if managed by the parent.
379
	 */
380
	public function managing_stock() {
381
		if ( 'yes' === get_option( 'woocommerce_manage_stock', 'yes' ) ) {
382
			if ( 'no' === $this->manage_stock ) {
383
				if ( $this->parent && $this->parent->managing_stock() ) {
384
					return 'parent';
385
				}
386
			} else {
387
				return true;
388
			}
389
		}
390
		return false;
391
	}
392
393
	/**
394
	 * Returns number of items available for sale from the variation, or parent.
395
	 *
396
	 * @return int
397
	 */
398
	public function get_stock_quantity() {
399
		return true === $this->managing_stock() ? wc_stock_amount( $this->stock ) : $this->parent->get_stock_quantity();
400
	}
401
402
	/**
403
	 * Returns the tax status. Always use parent data.
404
	 *
405
	 * @return string
406
	 */
407
	public function get_tax_status() {
408
		return $this->parent->get_tax_status();
409
	}
410
411
	/**
412
	 * Returns whether or not the product is in stock.
413
	 *
414
	 * @return bool
415
	 */
416 View Code Duplication
	public function is_in_stock() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
417
		$status = $this->stock_status === 'instock';
418
419
		/**
420
		 * Sanity check to ensure stock qty is not lower than 0 but still listed
421
		 * instock.
422
		 *
423
		 * Check is not required for products on backorder since they can be
424
		 * instock regardless of actual stock quantity.
425
		 */
426
		if ( true === $this->managing_stock() && ! $this->backorders_allowed() && $this->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount' ) ) {
427
			$status = false;
428
		}
429
430
		return apply_filters( 'woocommerce_variation_is_in_stock', $status );
431
	}
432
433
	/**
434
	 * Set stock level of the product variation.
435
	 *
436
	 * Uses queries rather than update_post_meta so we can do this in one query (to avoid stock issues).
437
	 * We cannot rely on the original loaded value in case another order was made since then.
438
	 *
439
	 * @param int $amount
440
	 * @param string $mode can be set, add, or subtract
441
	 * @return int new stock level
442
	 */
443
	public function set_stock( $amount = null, $mode = 'set' ) {
444
		global $wpdb;
445
446
		if ( ! is_null( $amount ) && true === $this->managing_stock() ) {
447
448
			// Ensure key exists
449
			add_post_meta( $this->variation_id, '_stock', 0, true );
450
451
			// Update stock in DB directly
452 View Code Duplication
			switch ( $mode ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
453
				case 'add' :
454
					$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = meta_value + %f WHERE post_id = %d AND meta_key='_stock'", $amount, $this->variation_id ) );
455
				break;
456
				case 'subtract' :
457
					$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = meta_value - %f WHERE post_id = %d AND meta_key='_stock'", $amount, $this->variation_id ) );
458
				break;
459
				default :
460
					$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = %f WHERE post_id = %d AND meta_key='_stock'", $amount, $this->variation_id ) );
461
				break;
462
			}
463
464
			// Clear caches
465
			wp_cache_delete( $this->variation_id, 'post_meta' );
466
467
			// Clear total stock transient
468
			delete_transient( 'wc_product_total_stock_' . $this->id . WC_Cache_Helper::get_transient_version( 'product' ) );
469
470
			// Stock status
471
			$this->check_stock_status();
472
473
			// Sync the parent
474
			WC_Product_Variable::sync( $this->id );
475
476
			// Trigger action
477
			do_action( 'woocommerce_variation_set_stock', $this );
478
479
		} elseif ( ! is_null( $amount ) ) {
480
			return $this->parent->set_stock( $amount, $mode );
481
		}
482
483
		return $this->get_stock_quantity();
484
	}
485
486
	/**
487
	 * Set stock status.
488
	 *
489
	 * @param string $status
490
	 */
491
	public function set_stock_status( $status ) {
492
		$status = 'outofstock' === $status ? 'outofstock' : 'instock';
493
494
		// Sanity check
495
		if ( true === $this->managing_stock() ) {
496
			if ( ! $this->backorders_allowed() && $this->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount' ) ) {
497
				$status = 'outofstock';
498
			}
499
		} elseif ( 'parent' === $this->managing_stock() ) {
500 View Code Duplication
			if ( ! $this->parent->backorders_allowed() && $this->parent->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
501
				$status = 'outofstock';
502
			}
503
		}
504
505
		if ( update_post_meta( $this->variation_id, '_stock_status', $status ) ) {
506
			do_action( 'woocommerce_variation_set_stock_status', $this->variation_id, $status );
507
508
			WC_Product_Variable::sync_stock_status( $this->id );
509
		}
510
	}
511
512
	/**
513
	 * Reduce stock level of the product.
514
	 *
515
	 * @param int $amount (default: 1) Amount to reduce by
516
	 * @return int stock level
517
	 */
518
	public function reduce_stock( $amount = 1 ) {
519
		if ( true === $this->managing_stock() ) {
520
			return $this->set_stock( $amount, 'subtract' );
521
		} else {
522
			return $this->parent->reduce_stock( $amount );
523
		}
524
	}
525
526
	/**
527
	 * Increase stock level of the product.
528
	 *
529
	 * @param int $amount (default: 1) Amount to increase by
530
	 * @return int stock level
531
	 */
532
	public function increase_stock( $amount = 1 ) {
533
		if ( true === $this->managing_stock() ) {
534
			return $this->set_stock( $amount, 'add' );
535
		} else {
536
			return $this->parent->increase_stock( $amount );
537
		}
538
	}
539
540
	/**
541
	 * Returns the availability of the product.
542
	 *
543
	 * @return string
544
	 */
545
	public function get_availability() {
546
		// Default to in-stock
547
		$availability = __( 'In stock', 'woocommerce' );
548
		$class        = 'in-stock';
549
550
		// If out of stock, this takes priority over all other settings.
551
		if ( ! $this->is_in_stock() ) {
552
			$availability = __( 'Out of stock', 'woocommerce' );
553
			$class        = 'out-of-stock';
554
555
		// Any further we can assume status is set to in stock.
556
		} elseif ( $this->managing_stock() && $this->is_on_backorder( 1 ) ) {
557
			$availability = __( 'Available on backorder', 'woocommerce' );
558
			$class        = 'available-on-backorder';
559
560 View Code Duplication
		} elseif ( true === $this->managing_stock() ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
561
			switch ( get_option( 'woocommerce_stock_format' ) ) {
562
				case 'no_amount' :
563
					$availability = __( 'In stock', 'woocommerce' );
564
				break;
565
				case 'low_amount' :
566
					if ( $this->get_stock_quantity() <= get_option( 'woocommerce_notify_low_stock_amount' ) ) {
567
						$availability = sprintf( __( 'Only %s left in stock', 'woocommerce' ), $this->get_stock_quantity() );
568
569
						if ( $this->backorders_allowed() && $this->backorders_require_notification() ) {
570
							$availability .= ' ' . __( '(also available on backorder)', 'woocommerce' );
571
						}
572
					} else {
573
						$availability = __( 'In stock', 'woocommerce' );
574
					}
575
				break;
576
				default :
577
					$availability = sprintf( __( '%s in stock', 'woocommerce' ), $this->get_stock_quantity() );
578
579
					if ( $this->backorders_allowed() && $this->backorders_require_notification() ) {
580
						$availability .= ' ' . __( '(also available on backorder)', 'woocommerce' );
581
					}
582
				break;
583
			}
584
		} elseif ( 'parent' === $this->managing_stock() ) {
585
			return parent::get_availability();
586
		}
587
588
		return apply_filters( 'woocommerce_get_availability', array( 'availability' => $availability, 'class' => $class ), $this );
589
	}
590
591
	/**
592
	 * Returns whether or not the product needs to notify the customer on backorder.
593
	 *
594
	 * @return bool
595
	 */
596
	public function backorders_require_notification() {
597
		if ( true === $this->managing_stock() ) {
598
			return parent::backorders_require_notification();
599
		} else {
600
			return $this->parent->backorders_require_notification();
601
		}
602
	}
603
604
	/**
605
	 * Is on backorder?
606
	 *
607
	 * @param int $qty_in_cart (default: 0)
608
	 * @return bool
609
	 */
610
	public function is_on_backorder( $qty_in_cart = 0 ) {
611
		if ( true === $this->managing_stock() ) {
612
			return parent::is_on_backorder( $qty_in_cart );
613
		} else {
614
			return $this->parent->is_on_backorder( $qty_in_cart );
615
		}
616
	}
617
618
	/**
619
	 * Returns whether or not the product has enough stock for the order.
620
	 *
621
	 * @param mixed $quantity
622
	 * @return bool
623
	 */
624
	public function has_enough_stock( $quantity ) {
625
		if ( true === $this->managing_stock() ) {
626
			return parent::has_enough_stock( $quantity );
627
		} else {
628
			return $this->parent->has_enough_stock( $quantity );
629
		}
630
	}
631
632
	/**
633
	 * Get the shipping class, and if not set, get the shipping class of the parent.
634
	 *
635
	 * @return string
636
	 */
637 View Code Duplication
	public function get_shipping_class() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
638
		if ( ! $this->variation_shipping_class ) {
639
			$classes = get_the_terms( $this->variation_id, 'product_shipping_class' );
640
641
			if ( $classes && ! is_wp_error( $classes ) ) {
642
				$this->variation_shipping_class = current( $classes )->slug;
643
			} else {
644
				$this->variation_shipping_class = parent::get_shipping_class();
0 ignored issues
show
Documentation Bug introduced by
The property $variation_shipping_class was declared of type boolean, but parent::get_shipping_class() is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
645
			}
646
		}
647
		return $this->variation_shipping_class;
648
	}
649
650
	/**
651
	 * Returns the product shipping class ID.
652
	 *
653
	 * @return int
654
	 */
655 View Code Duplication
	public function get_shipping_class_id() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
656
		if ( ! $this->variation_shipping_class_id ) {
657
			$classes = get_the_terms( $this->variation_id, 'product_shipping_class' );
658
659
			if ( $classes && ! is_wp_error( $classes ) ) {
660
				$this->variation_shipping_class_id = current( $classes )->term_id;
661
			} else {
662
				$this->variation_shipping_class_id = parent::get_shipping_class_id();
0 ignored issues
show
Documentation Bug introduced by
The property $variation_shipping_class_id was declared of type boolean, but parent::get_shipping_class_id() is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
663
			}
664
		}
665
		return absint( $this->variation_shipping_class_id );
666
	}
667
668
	/**
669
	 * Get formatted variation data with WC < 2.4 back compat and proper formatting of text-based attribute names.
670
	 *
671
	 * @return string
672
	 */
673
	public function get_formatted_variation_attributes( $flat = false ) {
674
		$variation_data = $this->get_variation_attributes();
675
		$attributes     = $this->parent->get_attributes();
676
		$description    = array();
677
		$return         = '';
678
679
		if ( is_array( $variation_data ) ) {
680
681
			if ( ! $flat ) {
682
				$return = '<dl class="variation">';
683
			}
684
685
			foreach ( $attributes as $attribute ) {
686
687
				// Only deal with attributes that are variations
688
				if ( ! $attribute[ 'is_variation' ] ) {
689
					continue;
690
				}
691
692
				$variation_selected_value = isset( $variation_data[ 'attribute_' . sanitize_title( $attribute[ 'name' ] ) ] ) ? $variation_data[ 'attribute_' . sanitize_title( $attribute[ 'name' ] ) ] : '';
693
				$description_name         = esc_html( wc_attribute_label( $attribute[ 'name' ] ) );
694
				$description_value        = __( 'Any', 'woocommerce' );
695
696
				// Get terms for attribute taxonomy or value if its a custom attribute
697
				if ( $attribute[ 'is_taxonomy' ] ) {
698
699
					$post_terms = wp_get_post_terms( $this->id, $attribute[ 'name' ] );
700
701
					foreach ( $post_terms as $term ) {
702
						if ( $variation_selected_value === $term->slug ) {
703
							$description_value = esc_html( apply_filters( 'woocommerce_variation_option_name', $term->name ) );
704
						}
705
					}
706
707
				} else {
708
709
					$options = wc_get_text_attributes( $attribute[ 'value' ] );
710
711
					foreach ( $options as $option ) {
712
713
						if ( sanitize_title( $variation_selected_value ) === $variation_selected_value ) {
714
							if ( $variation_selected_value !== sanitize_title( $option ) ) {
715
								continue;
716
							}
717
						} else {
718
							if ( $variation_selected_value !== $option ) {
719
								continue;
720
							}
721
						}
722
723
						$description_value = esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) );
724
					}
725
				}
726
727
				if ( $flat ) {
728
					$description[] = $description_name . ': ' . rawurldecode( $description_value );
729
				} else {
730
					$description[] = '<dt>' . $description_name . ':</dt><dd>' . rawurldecode( $description_value ) . '</dd>';
731
				}
732
			}
733
734
			if ( $flat ) {
735
				$return .= implode( ', ', $description );
736
			} else {
737
				$return .= implode( '', $description );
738
			}
739
740
			if ( ! $flat ) {
741
				$return .= '</dl>';
742
			}
743
		}
744
745
		return $return;
746
	}
747
748
	/**
749
	 * Get product name with extra details such as SKU, price and attributes. Used within admin.
750
	 *
751
	 * @return string Formatted product name, including attributes and price
752
	 */
753
	public function get_formatted_name() {
754
		if ( $this->get_sku() ) {
755
			$identifier = $this->get_sku();
756
		} else {
757
			$identifier = '#' . $this->variation_id;
758
		}
759
760
		$formatted_attributes = $this->get_formatted_variation_attributes( true );
761
		$extra_data           = ' &ndash; ' . $formatted_attributes . ' &ndash; ' . wc_price( $this->get_price() );
762
763
		return sprintf( __( '%s &ndash; %s%s', 'woocommerce' ), $identifier, $this->get_title(), $extra_data );
764
	}
765
766
	/**
767
	 * Get product variation description.
768
	 *
769
	 * @return string
770
	 */
771
	public function get_variation_description() {
772
		return wpautop( do_shortcode( wp_kses_post( get_post_meta( $this->variation_id, '_variation_description', true ) ) ) );
773
	}
774
}
775