Completed
Push — master ( f15353...c01a09 )
by Gerhard
29:12 queued 23:46
created

WC_Product::get_availability_text()   B

Complexity

Conditions 8
Paths 6

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 11.0764

Importance

Changes 0
Metric Value
cc 8
nc 6
nop 0
dl 0
loc 14
ccs 7
cts 11
cp 0.6364
crap 11.0764
rs 8.4444
c 0
b 0
f 0
1
<?php
2
/**
3
 * WooCommerce product base class.
4
 *
5
 * @package WooCommerce/Abstracts
6
 */
7
8
if ( ! defined( 'ABSPATH' ) ) {
9
	exit;
10
}
11
12
/**
13
 * Legacy product contains all deprecated methods for this class and can be
14
 * removed in the future.
15
 */
16
require_once WC_ABSPATH . 'includes/legacy/abstract-wc-legacy-product.php';
17
18
/**
19
 * Abstract Product Class
20
 *
21
 * The WooCommerce product class handles individual product data.
22
 *
23
 * @version 3.0.0
24
 * @package WooCommerce/Abstracts
25
 */
26
class WC_Product extends WC_Abstract_Legacy_Product {
27
28
	/**
29
	 * This is the name of this object type.
30
	 *
31
	 * @var string
32
	 */
33
	protected $object_type = 'product';
34
35
	/**
36
	 * Post type.
37
	 *
38
	 * @var string
39
	 */
40
	protected $post_type = 'product';
41
42
	/**
43
	 * Cache group.
44
	 *
45
	 * @var string
46
	 */
47
	protected $cache_group = 'products';
48
49
	/**
50
	 * Stores product data.
51
	 *
52
	 * @var array
53
	 */
54
	protected $data = array(
55
		'name'               => '',
56
		'slug'               => '',
57
		'date_created'       => null,
58
		'date_modified'      => null,
59
		'status'             => false,
60
		'featured'           => false,
61
		'catalog_visibility' => 'visible',
62
		'description'        => '',
63
		'short_description'  => '',
64
		'sku'                => '',
65
		'price'              => '',
66
		'regular_price'      => '',
67
		'sale_price'         => '',
68
		'date_on_sale_from'  => null,
69
		'date_on_sale_to'    => null,
70
		'total_sales'        => '0',
71
		'tax_status'         => 'taxable',
72
		'tax_class'          => '',
73
		'manage_stock'       => false,
74
		'stock_quantity'     => null,
75
		'stock_status'       => 'instock',
76
		'backorders'         => 'no',
77
		'low_stock_amount'   => '',
78
		'sold_individually'  => false,
79
		'weight'             => '',
80
		'length'             => '',
81
		'width'              => '',
82
		'height'             => '',
83
		'upsell_ids'         => array(),
84
		'cross_sell_ids'     => array(),
85
		'parent_id'          => 0,
86
		'reviews_allowed'    => true,
87
		'purchase_note'      => '',
88
		'attributes'         => array(),
89
		'default_attributes' => array(),
90
		'menu_order'         => 0,
91
		'post_password'      => '',
92
		'virtual'            => false,
93
		'downloadable'       => false,
94
		'category_ids'       => array(),
95
		'tag_ids'            => array(),
96
		'shipping_class_id'  => 0,
97
		'downloads'          => array(),
98
		'image_id'           => '',
99
		'gallery_image_ids'  => array(),
100
		'download_limit'     => -1,
101
		'download_expiry'    => -1,
102
		'rating_counts'      => array(),
103
		'average_rating'     => 0,
104
		'review_count'       => 0,
105
	);
106
107
	/**
108
	 * Supported features such as 'ajax_add_to_cart'.
109
	 *
110
	 * @var array
111
	 */
112
	protected $supports = array();
113
114
	/**
115
	 * Get the product if ID is passed, otherwise the product is new and empty.
116
	 * This class should NOT be instantiated, but the wc_get_product() function
117
	 * should be used. It is possible, but the wc_get_product() is preferred.
118
	 *
119
	 * @param int|WC_Product|object $product Product to init.
120
	 */
121 267
	public function __construct( $product = 0 ) {
122 267
		parent::__construct( $product );
123 267 View Code Duplication
		if ( is_numeric( $product ) && $product > 0 ) {
124 243
			$this->set_id( $product );
125 265
		} elseif ( $product instanceof self ) {
126
			$this->set_id( absint( $product->get_id() ) );
127 265
		} elseif ( ! empty( $product->ID ) ) {
128
			$this->set_id( absint( $product->ID ) );
129
		} else {
130 265
			$this->set_object_read( true );
131
		}
132
133 267
		$this->data_store = WC_Data_Store::load( 'product-' . $this->get_type() );
134 267
		if ( $this->get_id() > 0 ) {
135 243
			$this->data_store->read( $this );
136
		}
137
	}
138
139
	/**
140
	 * Get internal type. Should return string and *should be overridden* by child classes.
141
	 *
142
	 * The product_type property is deprecated but is used here for BW compatibility with child classes which may be defining product_type and not have a get_type method.
143
	 *
144
	 * @since  3.0.0
145
	 * @return string
146
	 */
147 17
	public function get_type() {
148 17
		return isset( $this->product_type ) ? $this->product_type : 'simple';
149
	}
150
151
	/**
152
	 * Get product name.
153
	 *
154
	 * @since  3.0.0
155
	 * @param  string $context What the value is for. Valid values are view and edit.
156
	 * @return string
157
	 */
158 261
	public function get_name( $context = 'view' ) {
159 261
		return $this->get_prop( 'name', $context );
160
	}
161
162
	/**
163
	 * Get product slug.
164
	 *
165
	 * @since  3.0.0
166
	 * @param  string $context What the value is for. Valid values are view and edit.
167
	 * @return string
168
	 */
169 261
	public function get_slug( $context = 'view' ) {
170 261
		return $this->get_prop( 'slug', $context );
171
	}
172
173
	/**
174
	 * Get product created date.
175
	 *
176
	 * @since  3.0.0
177
	 * @param  string $context What the value is for. Valid values are view and edit.
178
	 * @return WC_DateTime|NULL object if the date is set or null if there is no date.
179
	 */
180 261
	public function get_date_created( $context = 'view' ) {
181 261
		return $this->get_prop( 'date_created', $context );
182
	}
183
184
	/**
185
	 * Get product modified date.
186
	 *
187
	 * @since  3.0.0
188
	 * @param  string $context What the value is for. Valid values are view and edit.
189
	 * @return WC_DateTime|NULL object if the date is set or null if there is no date.
190
	 */
191
	public function get_date_modified( $context = 'view' ) {
192
		return $this->get_prop( 'date_modified', $context );
193
	}
194
195
	/**
196
	 * Get product status.
197
	 *
198
	 * @since  3.0.0
199
	 * @param  string $context What the value is for. Valid values are view and edit.
200
	 * @return string
201
	 */
202 261
	public function get_status( $context = 'view' ) {
203 261
		return $this->get_prop( 'status', $context );
204
	}
205
206
	/**
207
	 * If the product is featured.
208
	 *
209
	 * @since  3.0.0
210
	 * @param  string $context What the value is for. Valid values are view and edit.
211
	 * @return boolean
212
	 */
213 260
	public function get_featured( $context = 'view' ) {
214 260
		return $this->get_prop( 'featured', $context );
215
	}
216
217
	/**
218
	 * Get catalog visibility.
219
	 *
220
	 * @since  3.0.0
221
	 * @param  string $context What the value is for. Valid values are view and edit.
222
	 * @return string
223
	 */
224 260
	public function get_catalog_visibility( $context = 'view' ) {
225 260
		return $this->get_prop( 'catalog_visibility', $context );
226
	}
227
228
	/**
229
	 * Get product description.
230
	 *
231
	 * @since  3.0.0
232
	 * @param  string $context What the value is for. Valid values are view and edit.
233
	 * @return string
234
	 */
235 261
	public function get_description( $context = 'view' ) {
236 261
		return $this->get_prop( 'description', $context );
237
	}
238
239
	/**
240
	 * Get product short description.
241
	 *
242
	 * @since  3.0.0
243
	 * @param  string $context What the value is for. Valid values are view and edit.
244
	 * @return string
245
	 */
246 260
	public function get_short_description( $context = 'view' ) {
247 260
		return $this->get_prop( 'short_description', $context );
248
	}
249
250
	/**
251
	 * Get SKU (Stock-keeping unit) - product unique ID.
252
	 *
253
	 * @param  string $context What the value is for. Valid values are view and edit.
254
	 * @return string
255
	 */
256 260
	public function get_sku( $context = 'view' ) {
257 260
		return $this->get_prop( 'sku', $context );
258
	}
259
260
	/**
261
	 * Returns the product's active price.
262
	 *
263
	 * @param  string $context What the value is for. Valid values are view and edit.
264
	 * @return string price
265
	 */
266 158
	public function get_price( $context = 'view' ) {
267 158
		return $this->get_prop( 'price', $context );
268
	}
269
270
	/**
271
	 * Returns the product's regular price.
272
	 *
273
	 * @param  string $context What the value is for. Valid values are view and edit.
274
	 * @return string price
275
	 */
276 261
	public function get_regular_price( $context = 'view' ) {
277 261
		return $this->get_prop( 'regular_price', $context );
278
	}
279
280
	/**
281
	 * Returns the product's sale price.
282
	 *
283
	 * @param  string $context What the value is for. Valid values are view and edit.
284
	 * @return string price
285
	 */
286 261
	public function get_sale_price( $context = 'view' ) {
287 261
		return $this->get_prop( 'sale_price', $context );
288
	}
289
290
	/**
291
	 * Get date on sale from.
292
	 *
293
	 * @since  3.0.0
294
	 * @param  string $context What the value is for. Valid values are view and edit.
295
	 * @return WC_DateTime|NULL object if the date is set or null if there is no date.
296
	 */
297 261
	public function get_date_on_sale_from( $context = 'view' ) {
298 261
		return $this->get_prop( 'date_on_sale_from', $context );
299
	}
300
301
	/**
302
	 * Get date on sale to.
303
	 *
304
	 * @since  3.0.0
305
	 * @param  string $context What the value is for. Valid values are view and edit.
306
	 * @return WC_DateTime|NULL object if the date is set or null if there is no date.
307
	 */
308 261
	public function get_date_on_sale_to( $context = 'view' ) {
309 261
		return $this->get_prop( 'date_on_sale_to', $context );
310
	}
311
312
	/**
313
	 * Get number total of sales.
314
	 *
315
	 * @since  3.0.0
316
	 * @param  string $context What the value is for. Valid values are view and edit.
317
	 * @return int
318
	 */
319 261
	public function get_total_sales( $context = 'view' ) {
320 261
		return $this->get_prop( 'total_sales', $context );
321
	}
322
323
	/**
324
	 * Returns the tax status.
325
	 *
326
	 * @param  string $context What the value is for. Valid values are view and edit.
327
	 * @return string
328
	 */
329 261
	public function get_tax_status( $context = 'view' ) {
330 261
		return $this->get_prop( 'tax_status', $context );
331
	}
332
333
	/**
334
	 * Returns the tax class.
335
	 *
336
	 * @param  string $context What the value is for. Valid values are view and edit.
337
	 * @return string
338
	 */
339 260
	public function get_tax_class( $context = 'view' ) {
340 260
		return $this->get_prop( 'tax_class', $context );
341
	}
342
343
	/**
344
	 * Return if product manage stock.
345
	 *
346
	 * @since  3.0.0
347
	 * @param  string $context What the value is for. Valid values are view and edit.
348
	 * @return boolean
349
	 */
350 260
	public function get_manage_stock( $context = 'view' ) {
351 260
		return $this->get_prop( 'manage_stock', $context );
352
	}
353
354
	/**
355
	 * Returns number of items available for sale.
356
	 *
357
	 * @param  string $context What the value is for. Valid values are view and edit.
358
	 * @return int|null
359
	 */
360 260
	public function get_stock_quantity( $context = 'view' ) {
361 260
		return $this->get_prop( 'stock_quantity', $context );
362
	}
363
364
	/**
365
	 * Return the stock status.
366
	 *
367
	 * @param  string $context What the value is for. Valid values are view and edit.
368
	 * @since  3.0.0
369
	 * @return string
370
	 */
371 261
	public function get_stock_status( $context = 'view' ) {
372 261
		return $this->get_prop( 'stock_status', $context );
373
	}
374
375
	/**
376
	 * Get backorders.
377
	 *
378
	 * @param  string $context What the value is for. Valid values are view and edit.
379
	 * @since  3.0.0
380
	 * @return string yes no or notify
381
	 */
382 260
	public function get_backorders( $context = 'view' ) {
383 260
		return $this->get_prop( 'backorders', $context );
384
	}
385
386
	/**
387
	 * Get low stock amount.
388
	 *
389
	 * @param  string $context What the value is for. Valid values are view and edit.
390
	 * @since  3.5.0
391
	 * @return int|string Returns empty string if value not set
392
	 */
393 261
	public function get_low_stock_amount( $context = 'view' ) {
394 261
		return $this->get_prop( 'low_stock_amount', $context );
395
	}
396
397
	/**
398
	 * Return if should be sold individually.
399
	 *
400
	 * @param  string $context What the value is for. Valid values are view and edit.
401
	 * @since  3.0.0
402
	 * @return boolean
403
	 */
404 261
	public function get_sold_individually( $context = 'view' ) {
405 261
		return $this->get_prop( 'sold_individually', $context );
406
	}
407
408
	/**
409
	 * Returns the product's weight.
410
	 *
411
	 * @param  string $context What the value is for. Valid values are view and edit.
412
	 * @return string
413
	 */
414 260
	public function get_weight( $context = 'view' ) {
415 260
		return $this->get_prop( 'weight', $context );
416
	}
417
418
	/**
419
	 * Returns the product length.
420
	 *
421
	 * @param  string $context What the value is for. Valid values are view and edit.
422
	 * @return string
423
	 */
424 260
	public function get_length( $context = 'view' ) {
425 260
		return $this->get_prop( 'length', $context );
426
	}
427
428
	/**
429
	 * Returns the product width.
430
	 *
431
	 * @param  string $context What the value is for. Valid values are view and edit.
432
	 * @return string
433
	 */
434 260
	public function get_width( $context = 'view' ) {
435 260
		return $this->get_prop( 'width', $context );
436
	}
437
438
	/**
439
	 * Returns the product height.
440
	 *
441
	 * @param  string $context What the value is for. Valid values are view and edit.
442
	 * @return string
443
	 */
444 260
	public function get_height( $context = 'view' ) {
445 260
		return $this->get_prop( 'height', $context );
446
	}
447
448
	/**
449
	 * Returns formatted dimensions.
450
	 *
451
	 * @param  bool $formatted True by default for legacy support - will be false/not set in future versions to return the array only. Use wc_format_dimensions for formatted versions instead.
452
	 * @return string|array
453
	 */
454 5
	public function get_dimensions( $formatted = true ) {
455 5
		if ( $formatted ) {
456
			wc_deprecated_argument( 'WC_Product::get_dimensions', '3.0', 'By default, get_dimensions has an argument set to true so that HTML is returned. This is to support the legacy version of the method. To get HTML dimensions, instead use wc_format_dimensions() function. Pass false to this method to return an array of dimensions. This will be the new default behavior in future versions.' );
457
			return apply_filters( 'woocommerce_product_dimensions', wc_format_dimensions( $this->get_dimensions( false ) ), $this );
0 ignored issues
show
Bug introduced by
It seems like $this->get_dimensions(false) targeting WC_Product::get_dimensions() can also be of type string; however, wc_format_dimensions() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
458
		}
459
		return array(
460 5
			'length' => $this->get_length(),
461 5
			'width'  => $this->get_width(),
462 5
			'height' => $this->get_height(),
463
		);
464
	}
465
466
	/**
467
	 * Get upsell IDs.
468
	 *
469
	 * @since  3.0.0
470
	 * @param  string $context What the value is for. Valid values are view and edit.
471
	 * @return array
472
	 */
473 261
	public function get_upsell_ids( $context = 'view' ) {
474 261
		return $this->get_prop( 'upsell_ids', $context );
475
	}
476
477
	/**
478
	 * Get cross sell IDs.
479
	 *
480
	 * @since  3.0.0
481
	 * @param  string $context What the value is for. Valid values are view and edit.
482
	 * @return array
483
	 */
484 261
	public function get_cross_sell_ids( $context = 'view' ) {
485 261
		return $this->get_prop( 'cross_sell_ids', $context );
486
	}
487
488
	/**
489
	 * Get parent ID.
490
	 *
491
	 * @since  3.0.0
492
	 * @param  string $context What the value is for. Valid values are view and edit.
493
	 * @return int
494
	 */
495 263
	public function get_parent_id( $context = 'view' ) {
496 263
		return $this->get_prop( 'parent_id', $context );
497
	}
498
499
	/**
500
	 * Return if reviews is allowed.
501
	 *
502
	 * @since  3.0.0
503
	 * @param  string $context What the value is for. Valid values are view and edit.
504
	 * @return bool
505
	 */
506 260
	public function get_reviews_allowed( $context = 'view' ) {
507 260
		return $this->get_prop( 'reviews_allowed', $context );
508
	}
509
510
	/**
511
	 * Get purchase note.
512
	 *
513
	 * @since  3.0.0
514
	 * @param  string $context What the value is for. Valid values are view and edit.
515
	 * @return string
516
	 */
517 260
	public function get_purchase_note( $context = 'view' ) {
518 260
		return $this->get_prop( 'purchase_note', $context );
519
	}
520
521
	/**
522
	 * Returns product attributes.
523
	 *
524
	 * @param  string $context What the value is for. Valid values are view and edit.
525
	 * @return array
526
	 */
527 261
	public function get_attributes( $context = 'view' ) {
528 261
		return $this->get_prop( 'attributes', $context );
529
	}
530
531
	/**
532
	 * Get default attributes.
533
	 *
534
	 * @since  3.0.0
535
	 * @param  string $context What the value is for. Valid values are view and edit.
536
	 * @return array
537
	 */
538 261
	public function get_default_attributes( $context = 'view' ) {
539 261
		return $this->get_prop( 'default_attributes', $context );
540
	}
541
542
	/**
543
	 * Get menu order.
544
	 *
545
	 * @since  3.0.0
546
	 * @param  string $context What the value is for. Valid values are view and edit.
547
	 * @return int
548
	 */
549 261
	public function get_menu_order( $context = 'view' ) {
550 261
		return $this->get_prop( 'menu_order', $context );
551
	}
552
553
	/**
554
	 * Get post password.
555
	 *
556
	 * @since  3.6.0
557
	 * @param  string $context What the value is for. Valid values are view and edit.
558
	 * @return int
559
	 */
560 260
	public function get_post_password( $context = 'view' ) {
561 260
		return $this->get_prop( 'post_password', $context );
562
	}
563
564
	/**
565
	 * Get category ids.
566
	 *
567
	 * @since  3.0.0
568
	 * @param  string $context What the value is for. Valid values are view and edit.
569
	 * @return array
570
	 */
571 260
	public function get_category_ids( $context = 'view' ) {
572 260
		return $this->get_prop( 'category_ids', $context );
573
	}
574
575
	/**
576
	 * Get tag ids.
577
	 *
578
	 * @since  3.0.0
579
	 * @param  string $context What the value is for. Valid values are view and edit.
580
	 * @return array
581
	 */
582 260
	public function get_tag_ids( $context = 'view' ) {
583 260
		return $this->get_prop( 'tag_ids', $context );
584
	}
585
586
	/**
587
	 * Get virtual.
588
	 *
589
	 * @since  3.0.0
590
	 * @param  string $context What the value is for. Valid values are view and edit.
591
	 * @return bool
592
	 */
593 258
	public function get_virtual( $context = 'view' ) {
594 258
		return $this->get_prop( 'virtual', $context );
595
	}
596
597
	/**
598
	 * Returns the gallery attachment ids.
599
	 *
600
	 * @param  string $context What the value is for. Valid values are view and edit.
601
	 * @return array
602
	 */
603 261
	public function get_gallery_image_ids( $context = 'view' ) {
604 261
		return $this->get_prop( 'gallery_image_ids', $context );
605
	}
606
607
	/**
608
	 * Get shipping class ID.
609
	 *
610
	 * @since  3.0.0
611
	 * @param  string $context What the value is for. Valid values are view and edit.
612
	 * @return int
613
	 */
614 260
	public function get_shipping_class_id( $context = 'view' ) {
615 260
		return $this->get_prop( 'shipping_class_id', $context );
616
	}
617
618
	/**
619
	 * Get downloads.
620
	 *
621
	 * @since  3.0.0
622
	 * @param  string $context What the value is for. Valid values are view and edit.
623
	 * @return array
624
	 */
625 261
	public function get_downloads( $context = 'view' ) {
626 261
		return $this->get_prop( 'downloads', $context );
627
	}
628
629
	/**
630
	 * Get download expiry.
631
	 *
632
	 * @since  3.0.0
633
	 * @param  string $context What the value is for. Valid values are view and edit.
634
	 * @return int
635
	 */
636 261
	public function get_download_expiry( $context = 'view' ) {
637 261
		return $this->get_prop( 'download_expiry', $context );
638
	}
639
640
	/**
641
	 * Get downloadable.
642
	 *
643
	 * @since  3.0.0
644
	 * @param  string $context What the value is for. Valid values are view and edit.
645
	 * @return bool
646
	 */
647 258
	public function get_downloadable( $context = 'view' ) {
648 258
		return $this->get_prop( 'downloadable', $context );
649
	}
650
651
	/**
652
	 * Get download limit.
653
	 *
654
	 * @since  3.0.0
655
	 * @param  string $context What the value is for. Valid values are view and edit.
656
	 * @return int
657
	 */
658 261
	public function get_download_limit( $context = 'view' ) {
659 261
		return $this->get_prop( 'download_limit', $context );
660
	}
661
662
	/**
663
	 * Get main image ID.
664
	 *
665
	 * @since  3.0.0
666
	 * @param  string $context What the value is for. Valid values are view and edit.
667
	 * @return string
668
	 */
669 262
	public function get_image_id( $context = 'view' ) {
670 262
		return $this->get_prop( 'image_id', $context );
671
	}
672
673
	/**
674
	 * Get rating count.
675
	 *
676
	 * @param  string $context What the value is for. Valid values are view and edit.
677
	 * @return array of counts
678
	 */
679 261
	public function get_rating_counts( $context = 'view' ) {
680 261
		return $this->get_prop( 'rating_counts', $context );
681
	}
682
683
	/**
684
	 * Get average rating.
685
	 *
686
	 * @param  string $context What the value is for. Valid values are view and edit.
687
	 * @return float
688
	 */
689 261
	public function get_average_rating( $context = 'view' ) {
690 261
		return $this->get_prop( 'average_rating', $context );
691
	}
692
693
	/**
694
	 * Get review count.
695
	 *
696
	 * @param  string $context What the value is for. Valid values are view and edit.
697
	 * @return int
698
	 */
699 261
	public function get_review_count( $context = 'view' ) {
700 261
		return $this->get_prop( 'review_count', $context );
701
	}
702
703
	/*
704
	|--------------------------------------------------------------------------
705
	| Setters
706
	|--------------------------------------------------------------------------
707
	|
708
	| Functions for setting product data. These should not update anything in the
709
	| database itself and should only change what is stored in the class
710
	| object.
711
	*/
712
713
	/**
714
	 * Set product name.
715
	 *
716
	 * @since 3.0.0
717
	 * @param string $name Product name.
718
	 */
719 244
	public function set_name( $name ) {
720 244
		$this->set_prop( 'name', $name );
721
	}
722
723
	/**
724
	 * Set product slug.
725
	 *
726
	 * @since 3.0.0
727
	 * @param string $slug Product slug.
728
	 */
729 241
	public function set_slug( $slug ) {
730 241
		$this->set_prop( 'slug', $slug );
731
	}
732
733
	/**
734
	 * Set product created date.
735
	 *
736
	 * @since 3.0.0
737
	 * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date.
738
	 */
739 261
	public function set_date_created( $date = null ) {
740 261
		$this->set_date_prop( 'date_created', $date );
741
	}
742
743
	/**
744
	 * Set product modified date.
745
	 *
746
	 * @since 3.0.0
747
	 * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date.
748
	 */
749 241
	public function set_date_modified( $date = null ) {
750 241
		$this->set_date_prop( 'date_modified', $date );
751
	}
752
753
	/**
754
	 * Set product status.
755
	 *
756
	 * @since 3.0.0
757
	 * @param string $status Product status.
758
	 */
759 242
	public function set_status( $status ) {
760 242
		$this->set_prop( 'status', $status );
761
	}
762
763
	/**
764
	 * Set if the product is featured.
765
	 *
766
	 * @since 3.0.0
767
	 * @param bool|string $featured Whether the product is featured or not.
768
	 */
769 236
	public function set_featured( $featured ) {
770 236
		$this->set_prop( 'featured', wc_string_to_bool( $featured ) );
0 ignored issues
show
Bug introduced by
It seems like $featured defined by parameter $featured on line 769 can also be of type boolean; however, wc_string_to_bool() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
771
	}
772
773
	/**
774
	 * Set catalog visibility.
775
	 *
776
	 * @since  3.0.0
777
	 * @throws WC_Data_Exception Throws exception when invalid data is found.
778
	 * @param  string $visibility Options: 'hidden', 'visible', 'search' and 'catalog'.
779
	 */
780 236 View Code Duplication
	public function set_catalog_visibility( $visibility ) {
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...
781 236
		$options = array_keys( wc_get_product_visibility_options() );
782 236
		if ( ! in_array( $visibility, $options, true ) ) {
783
			$this->error( 'product_invalid_catalog_visibility', __( 'Invalid catalog visibility option.', 'woocommerce' ) );
784
		}
785 236
		$this->set_prop( 'catalog_visibility', $visibility );
786
	}
787
788
	/**
789
	 * Set product description.
790
	 *
791
	 * @since 3.0.0
792
	 * @param string $description Product description.
793
	 */
794 242
	public function set_description( $description ) {
795 242
		$this->set_prop( 'description', $description );
796
	}
797
798
	/**
799
	 * Set product short description.
800
	 *
801
	 * @since 3.0.0
802
	 * @param string $short_description Product short description.
803
	 */
804 235
	public function set_short_description( $short_description ) {
805 235
		$this->set_prop( 'short_description', $short_description );
806
	}
807
808
	/**
809
	 * Set SKU.
810
	 *
811
	 * @since  3.0.0
812
	 * @throws WC_Data_Exception Throws exception when invalid data is found.
813
	 * @param  string $sku Product SKU.
814
	 */
815 220
	public function set_sku( $sku ) {
816 220
		$sku = (string) $sku;
817 220
		if ( $this->get_object_read() && ! empty( $sku ) && ! wc_product_has_unique_sku( $this->get_id(), $sku ) ) {
818 67
			$sku_found = wc_get_product_id_by_sku( $sku );
819
820 67
			$this->error( 'product_invalid_sku', __( 'Invalid or duplicated SKU.', 'woocommerce' ), 400, array( 'resource_id' => $sku_found ) );
821
		}
822 220
		$this->set_prop( 'sku', $sku );
823
	}
824
825
	/**
826
	 * Set the product's active price.
827
	 *
828
	 * @param string $price Price.
829
	 */
830 236
	public function set_price( $price ) {
831 236
		$this->set_prop( 'price', wc_format_decimal( $price ) );
832
	}
833
834
	/**
835
	 * Set the product's regular price.
836
	 *
837
	 * @since 3.0.0
838
	 * @param string $price Regular price.
839
	 */
840 236
	public function set_regular_price( $price ) {
841 236
		$this->set_prop( 'regular_price', wc_format_decimal( $price ) );
842
	}
843
844
	/**
845
	 * Set the product's sale price.
846
	 *
847
	 * @since 3.0.0
848
	 * @param string $price sale price.
849
	 */
850 42
	public function set_sale_price( $price ) {
851 42
		$this->set_prop( 'sale_price', wc_format_decimal( $price ) );
852
	}
853
854
	/**
855
	 * Set date on sale from.
856
	 *
857
	 * @since 3.0.0
858
	 * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date.
859
	 */
860 34
	public function set_date_on_sale_from( $date = null ) {
861 34
		$this->set_date_prop( 'date_on_sale_from', $date );
862
	}
863
864
	/**
865
	 * Set date on sale to.
866
	 *
867
	 * @since 3.0.0
868
	 * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date.
869
	 */
870 33
	public function set_date_on_sale_to( $date = null ) {
871 33
		$this->set_date_prop( 'date_on_sale_to', $date );
872
	}
873
874
	/**
875
	 * Set number total of sales.
876
	 *
877
	 * @since 3.0.0
878
	 * @param int $total Total of sales.
879
	 */
880 236
	public function set_total_sales( $total ) {
881 236
		$this->set_prop( 'total_sales', absint( $total ) );
882
	}
883
884
	/**
885
	 * Set the tax status.
886
	 *
887
	 * @since  3.0.0
888
	 * @throws WC_Data_Exception Throws exception when invalid data is found.
889
	 * @param  string $status Tax status.
890
	 */
891 242
	public function set_tax_status( $status ) {
892
		$options = array(
893 242
			'taxable',
894
			'shipping',
895
			'none',
896
		);
897
898
		// Set default if empty.
899 242
		if ( empty( $status ) ) {
900 3
			$status = 'taxable';
901
		}
902
903 242
		if ( ! in_array( $status, $options, true ) ) {
904
			$this->error( 'product_invalid_tax_status', __( 'Invalid product tax status.', 'woocommerce' ) );
905
		}
906
907 242
		$this->set_prop( 'tax_status', $status );
908
	}
909
910
	/**
911
	 * Set the tax class.
912
	 *
913
	 * @since 3.0.0
914
	 * @param string $class Tax class.
915
	 */
916 242
	public function set_tax_class( $class ) {
917 242
		$class         = sanitize_title( $class );
918 242
		$class         = 'standard' === $class ? '' : $class;
919 242
		$valid_classes = $this->get_valid_tax_classes();
920
921 242
		if ( ! in_array( $class, $valid_classes, true ) ) {
922 237
			$class = '';
923
		}
924
925 242
		$this->set_prop( 'tax_class', $class );
926
	}
927
928
	/**
929
	 * Return an array of valid tax classes
930
	 *
931
	 * @return array valid tax classes
932
	 */
933 237
	protected function get_valid_tax_classes() {
934 237
		return WC_Tax::get_tax_class_slugs();
935
	}
936
937
	/**
938
	 * Set if product manage stock.
939
	 *
940
	 * @since 3.0.0
941
	 * @param bool $manage_stock Whether or not manage stock is enabled.
942
	 */
943 242
	public function set_manage_stock( $manage_stock ) {
944 242
		$this->set_prop( 'manage_stock', wc_string_to_bool( $manage_stock ) );
0 ignored issues
show
Documentation introduced by
$manage_stock is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
945
	}
946
947
	/**
948
	 * Set number of items available for sale.
949
	 *
950
	 * @since 3.0.0
951
	 * @param float|null $quantity Stock quantity.
952
	 */
953 261
	public function set_stock_quantity( $quantity ) {
954 261
		$this->set_prop( 'stock_quantity', '' !== $quantity ? wc_stock_amount( $quantity ) : null );
955
	}
956
957
	/**
958
	 * Set stock status.
959
	 *
960
	 * @param string $status New status.
961
	 */
962 243
	public function set_stock_status( $status = 'instock' ) {
963 243
		$valid_statuses = wc_get_product_stock_status_options();
964
965 243
		if ( isset( $valid_statuses[ $status ] ) ) {
966 241
			$this->set_prop( 'stock_status', $status );
967
		} else {
968 32
			$this->set_prop( 'stock_status', 'instock' );
969
		}
970
	}
971
972
	/**
973
	 * Set backorders.
974
	 *
975
	 * @since 3.0.0
976
	 * @param string $backorders Options: 'yes', 'no' or 'notify'.
977
	 */
978 257
	public function set_backorders( $backorders ) {
979 257
		$this->set_prop( 'backorders', $backorders );
980
	}
981
982
	/**
983
	 * Set low stock amount.
984
	 *
985
	 * @param int|string $amount Empty string if value not set.
986
	 * @since 3.5.0
987
	 */
988 259
	public function set_low_stock_amount( $amount ) {
989 259
		$this->set_prop( 'low_stock_amount', '' === $amount ? '' : absint( $amount ) );
990
	}
991
992
	/**
993
	 * Set if should be sold individually.
994
	 *
995
	 * @since 3.0.0
996
	 * @param bool $sold_individually Whether or not product is sold individually.
997
	 */
998 242
	public function set_sold_individually( $sold_individually ) {
999 242
		$this->set_prop( 'sold_individually', wc_string_to_bool( $sold_individually ) );
0 ignored issues
show
Documentation introduced by
$sold_individually is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1000
	}
1001
1002
	/**
1003
	 * Set the product's weight.
1004
	 *
1005
	 * @since 3.0.0
1006
	 * @param float|string $weight Total weight.
1007
	 */
1008 216
	public function set_weight( $weight ) {
1009 216
		$this->set_prop( 'weight', '' === $weight ? '' : wc_format_decimal( $weight ) );
1010
	}
1011
1012
	/**
1013
	 * Set the product length.
1014
	 *
1015
	 * @since 3.0.0
1016
	 * @param float|string $length Total length.
1017
	 */
1018 33
	public function set_length( $length ) {
1019 33
		$this->set_prop( 'length', '' === $length ? '' : wc_format_decimal( $length ) );
1020
	}
1021
1022
	/**
1023
	 * Set the product width.
1024
	 *
1025
	 * @since 3.0.0
1026
	 * @param float|string $width Total width.
1027
	 */
1028 34
	public function set_width( $width ) {
1029 34
		$this->set_prop( 'width', '' === $width ? '' : wc_format_decimal( $width ) );
1030
	}
1031
1032
	/**
1033
	 * Set the product height.
1034
	 *
1035
	 * @since 3.0.0
1036
	 * @param float|string $height Total height.
1037
	 */
1038 34
	public function set_height( $height ) {
1039 34
		$this->set_prop( 'height', '' === $height ? '' : wc_format_decimal( $height ) );
1040
	}
1041
1042
	/**
1043
	 * Set upsell IDs.
1044
	 *
1045
	 * @since 3.0.0
1046
	 * @param array $upsell_ids IDs from the up-sell products.
1047
	 */
1048 2
	public function set_upsell_ids( $upsell_ids ) {
1049 2
		$this->set_prop( 'upsell_ids', array_filter( (array) $upsell_ids ) );
1050
	}
1051
1052
	/**
1053
	 * Set crosssell IDs.
1054
	 *
1055
	 * @since 3.0.0
1056
	 * @param array $cross_sell_ids IDs from the cross-sell products.
1057
	 */
1058 33
	public function set_cross_sell_ids( $cross_sell_ids ) {
1059 33
		$this->set_prop( 'cross_sell_ids', array_filter( (array) $cross_sell_ids ) );
1060
	}
1061
1062
	/**
1063
	 * Set parent ID.
1064
	 *
1065
	 * @since 3.0.0
1066
	 * @param int $parent_id Product parent ID.
1067
	 */
1068 241
	public function set_parent_id( $parent_id ) {
1069 241
		$this->set_prop( 'parent_id', absint( $parent_id ) );
1070
	}
1071
1072
	/**
1073
	 * Set if reviews is allowed.
1074
	 *
1075
	 * @since 3.0.0
1076
	 * @param bool $reviews_allowed Reviews allowed or not.
1077
	 */
1078 242
	public function set_reviews_allowed( $reviews_allowed ) {
1079 242
		$this->set_prop( 'reviews_allowed', wc_string_to_bool( $reviews_allowed ) );
0 ignored issues
show
Documentation introduced by
$reviews_allowed is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1080
	}
1081
1082
	/**
1083
	 * Set purchase note.
1084
	 *
1085
	 * @since 3.0.0
1086
	 * @param string $purchase_note Purchase note.
1087
	 */
1088 2
	public function set_purchase_note( $purchase_note ) {
1089 2
		$this->set_prop( 'purchase_note', $purchase_note );
1090
	}
1091
1092
	/**
1093
	 * Set product attributes.
1094
	 *
1095
	 * Attributes are made up of:
1096
	 *     id - 0 for product level attributes. ID for global attributes.
1097
	 *     name - Attribute name.
1098
	 *     options - attribute value or array of term ids/names.
1099
	 *     position - integer sort order.
1100
	 *     visible - If visible on frontend.
1101
	 *     variation - If used for variations.
1102
	 * Indexed by unqiue key to allow clearing old ones after a set.
1103
	 *
1104
	 * @since 3.0.0
1105
	 * @param array $raw_attributes Array of WC_Product_Attribute objects.
1106
	 */
1107 23
	public function set_attributes( $raw_attributes ) {
1108 23
		$attributes = array_fill_keys( array_keys( $this->get_attributes( 'edit' ) ), null );
1109 23
		foreach ( $raw_attributes as $attribute ) {
1110 23
			if ( is_a( $attribute, 'WC_Product_Attribute' ) ) {
1111 23
				$attributes[ sanitize_title( $attribute->get_name() ) ] = $attribute;
1112
			}
1113
		}
1114
1115 23
		uasort( $attributes, 'wc_product_attribute_uasort_comparison' );
1116 23
		$this->set_prop( 'attributes', $attributes );
1117
	}
1118
1119
	/**
1120
	 * Set default attributes. These will be saved as strings and should map to attribute values.
1121
	 *
1122
	 * @since 3.0.0
1123
	 * @param array $default_attributes List of default attributes.
1124
	 */
1125 3
	public function set_default_attributes( $default_attributes ) {
1126 3
		$this->set_prop( 'default_attributes', array_map( 'strval', array_filter( (array) $default_attributes, 'wc_array_filter_default_attributes' ) ) );
1127
	}
1128
1129
	/**
1130
	 * Set menu order.
1131
	 *
1132
	 * @since 3.0.0
1133
	 * @param int $menu_order Menu order.
1134
	 */
1135 241
	public function set_menu_order( $menu_order ) {
1136 241
		$this->set_prop( 'menu_order', intval( $menu_order ) );
1137
	}
1138
1139
	/**
1140
	 * Set post password.
1141
	 *
1142
	 * @since 3.6.0
1143
	 * @param int $post_password Post password.
1144
	 */
1145 235
	public function set_post_password( $post_password ) {
1146 235
		$this->set_prop( 'post_password', $post_password );
1147
	}
1148
1149
	/**
1150
	 * Set the product categories.
1151
	 *
1152
	 * @since 3.0.0
1153
	 * @param array $term_ids List of terms IDs.
1154
	 */
1155 236
	public function set_category_ids( $term_ids ) {
1156 236
		$this->set_prop( 'category_ids', array_unique( array_map( 'intval', $term_ids ) ) );
1157
	}
1158
1159
	/**
1160
	 * Set the product tags.
1161
	 *
1162
	 * @since 3.0.0
1163
	 * @param array $term_ids List of terms IDs.
1164
	 */
1165 236
	public function set_tag_ids( $term_ids ) {
1166 236
		$this->set_prop( 'tag_ids', array_unique( array_map( 'intval', $term_ids ) ) );
1167
	}
1168
1169
	/**
1170
	 * Set if the product is virtual.
1171
	 *
1172
	 * @since 3.0.0
1173
	 * @param bool|string $virtual Whether product is virtual or not.
1174
	 */
1175 242
	public function set_virtual( $virtual ) {
1176 242
		$this->set_prop( 'virtual', wc_string_to_bool( $virtual ) );
0 ignored issues
show
Bug introduced by
It seems like $virtual defined by parameter $virtual on line 1175 can also be of type boolean; however, wc_string_to_bool() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
1177
	}
1178
1179
	/**
1180
	 * Set shipping class ID.
1181
	 *
1182
	 * @since 3.0.0
1183
	 * @param int $id Product shipping class id.
1184
	 */
1185 242
	public function set_shipping_class_id( $id ) {
1186 242
		$this->set_prop( 'shipping_class_id', absint( $id ) );
1187
	}
1188
1189
	/**
1190
	 * Set if the product is downloadable.
1191
	 *
1192
	 * @since 3.0.0
1193
	 * @param bool|string $downloadable Whether product is downloadable or not.
1194
	 */
1195 243
	public function set_downloadable( $downloadable ) {
1196 243
		$this->set_prop( 'downloadable', wc_string_to_bool( $downloadable ) );
0 ignored issues
show
Bug introduced by
It seems like $downloadable defined by parameter $downloadable on line 1195 can also be of type boolean; however, wc_string_to_bool() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
1197
	}
1198
1199
	/**
1200
	 * Set downloads.
1201
	 *
1202
	 * @since 3.0.0
1203
	 * @param array $downloads_array Array of WC_Product_Download objects or arrays.
1204
	 */
1205 3
	public function set_downloads( $downloads_array ) {
1206 3
		$downloads = array();
1207 3
		$errors    = array();
1208
1209 3
		foreach ( $downloads_array as $download ) {
1210 3
			if ( is_a( $download, 'WC_Product_Download' ) ) {
1211 3
				$download_object = $download;
1212
			} else {
1213 1
				$download_object = new WC_Product_Download();
1214
1215
				// If we don't have a previous hash, generate UUID for download.
1216 1
				if ( empty( $download['download_id'] ) ) {
1217 1
					$download['download_id'] = wp_generate_uuid4();
1218
				}
1219
1220 1
				$download_object->set_id( $download['download_id'] );
1221 1
				$download_object->set_name( $download['name'] );
1222 1
				$download_object->set_file( $download['file'] );
1223
			}
1224
1225
			// Validate the file extension.
1226 3
			if ( ! $download_object->is_allowed_filetype() ) {
1227
				if ( $this->get_object_read() ) {
1228
					/* translators: %1$s: Downloadable file */
1229
					$errors[] = sprintf( __( 'The downloadable file %1$s cannot be used as it does not have an allowed file type. Allowed types include: %2$s', 'woocommerce' ), '<code>' . basename( $download_object->get_file() ) . '</code>', '<code>' . implode( ', ', array_keys( $download_object->get_allowed_mime_types() ) ) . '</code>' );
1230
				}
1231
				continue;
1232
			}
1233
1234
			// Validate the file exists.
1235 3
			if ( ! $download_object->file_exists() ) {
1236
				if ( $this->get_object_read() ) {
1237
					/* translators: %s: Downloadable file */
1238
					$errors[] = sprintf( __( 'The downloadable file %s cannot be used as it does not exist on the server.', 'woocommerce' ), '<code>' . $download_object->get_file() . '</code>' );
1239
				}
1240
				continue;
1241
			}
1242
1243 3
			$downloads[ $download_object->get_id() ] = $download_object;
1244
		}
1245
1246 3
		if ( $errors ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $errors of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1247
			$this->error( 'product_invalid_download', $errors[0] );
1248
		}
1249
1250 3
		$this->set_prop( 'downloads', $downloads );
1251
	}
1252
1253
	/**
1254
	 * Set download limit.
1255
	 *
1256
	 * @since 3.0.0
1257
	 * @param int|string $download_limit Product download limit.
1258
	 */
1259 242
	public function set_download_limit( $download_limit ) {
1260 242
		$this->set_prop( 'download_limit', -1 === (int) $download_limit || '' === $download_limit ? -1 : absint( $download_limit ) );
1261
	}
1262
1263
	/**
1264
	 * Set download expiry.
1265
	 *
1266
	 * @since 3.0.0
1267
	 * @param int|string $download_expiry Product download expiry.
1268
	 */
1269 242
	public function set_download_expiry( $download_expiry ) {
1270 242
		$this->set_prop( 'download_expiry', -1 === (int) $download_expiry || '' === $download_expiry ? -1 : absint( $download_expiry ) );
1271
	}
1272
1273
	/**
1274
	 * Set gallery attachment ids.
1275
	 *
1276
	 * @since 3.0.0
1277
	 * @param array $image_ids List of image ids.
1278
	 */
1279 241
	public function set_gallery_image_ids( $image_ids ) {
1280 241
		$image_ids = wp_parse_id_list( $image_ids );
1281
1282 241
		$this->set_prop( 'gallery_image_ids', $image_ids );
1283
	}
1284
1285
	/**
1286
	 * Set main image ID.
1287
	 *
1288
	 * @since 3.0.0
1289
	 * @param int|string $image_id Product image id.
1290
	 */
1291 34
	public function set_image_id( $image_id = '' ) {
1292 34
		$this->set_prop( 'image_id', $image_id );
1293
	}
1294
1295
	/**
1296
	 * Set rating counts. Read only.
1297
	 *
1298
	 * @param array $counts Product rating counts.
1299
	 */
1300
	public function set_rating_counts( $counts ) {
1301
		$this->set_prop( 'rating_counts', array_filter( array_map( 'absint', (array) $counts ) ) );
1302
	}
1303
1304
	/**
1305
	 * Set average rating. Read only.
1306
	 *
1307
	 * @param float $average Product average rating.
1308
	 */
1309 236
	public function set_average_rating( $average ) {
1310 236
		$this->set_prop( 'average_rating', wc_format_decimal( $average ) );
1311
	}
1312
1313
	/**
1314
	 * Set review count. Read only.
1315
	 *
1316
	 * @param int $count Product review count.
1317
	 */
1318 236
	public function set_review_count( $count ) {
1319 236
		$this->set_prop( 'review_count', absint( $count ) );
1320
	}
1321
1322
	/*
1323
	|--------------------------------------------------------------------------
1324
	| Other Methods
1325
	|--------------------------------------------------------------------------
1326
	*/
1327
1328
	/**
1329
	 * Ensure properties are set correctly before save.
1330
	 *
1331
	 * @since 3.0.0
1332
	 */
1333 258
	public function validate_props() {
1334
		// Before updating, ensure stock props are all aligned. Qty, backorders and low stock amount are not needed if not stock managed.
1335 258
		if ( ! $this->get_manage_stock() ) {
1336 256
			$this->set_stock_quantity( '' );
1337 256
			$this->set_backorders( 'no' );
1338 256
			$this->set_low_stock_amount( '' );
1339
1340
			// If we are stock managing and we don't have stock, force out of stock status.
1341 8 View Code Duplication
		} elseif ( $this->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount', 0 ) && 'no' === $this->get_backorders() ) {
1342 4
			$this->set_stock_status( 'outofstock' );
1343
1344
			// If we are stock managing, backorders are allowed, and we don't have stock, force on backorder status.
1345 8
		} elseif ( $this->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount', 0 ) && 'no' !== $this->get_backorders() ) {
1346 2
			$this->set_stock_status( 'onbackorder' );
1347
1348
			// If the stock level is changing and we do now have enough, force in stock status.
1349 7
		} elseif ( $this->get_stock_quantity() > get_option( 'woocommerce_notify_no_stock_amount', 0 ) ) {
1350 7
			$this->set_stock_status( 'instock' );
1351
		}
1352
	}
1353
1354
	/**
1355
	 * Save data (either create or update depending on if we are working on an existing product).
1356
	 *
1357
	 * @since  3.0.0
1358
	 * @return int
1359
	 */
1360 258 View Code Duplication
	public function save() {
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...
1361 258
		$this->validate_props();
1362
1363 258
		if ( ! $this->data_store ) {
1364
			return $this->get_id();
1365
		}
1366
1367
		/**
1368
		 * Trigger action before saving to the DB. Allows you to adjust object props before save.
1369
		 *
1370
		 * @param WC_Data          $this The object being saved.
1371
		 * @param WC_Data_Store_WP $data_store THe data store persisting the data.
1372
		 */
1373 258
		do_action( 'woocommerce_before_' . $this->object_type . '_object_save', $this, $this->data_store );
1374
1375 258
		if ( $this->get_id() ) {
1376 84
			$this->data_store->update( $this );
1377
		} else {
1378 258
			$this->data_store->create( $this );
1379
		}
1380
1381 258
		if ( $this->get_parent_id() ) {
1382 30
			wc_deferred_product_sync( $this->get_parent_id() );
1383
		}
1384
1385
		/**
1386
		 * Trigger action after saving to the DB.
1387
		 *
1388
		 * @param WC_Data          $this The object being saved.
1389
		 * @param WC_Data_Store_WP $data_store THe data store persisting the data.
1390
		 */
1391 258
		do_action( 'woocommerce_after_' . $this->object_type . '_object_save', $this, $this->data_store );
1392
1393 258
		return $this->get_id();
1394
	}
1395
1396
	/*
1397
	|--------------------------------------------------------------------------
1398
	| Conditionals
1399
	|--------------------------------------------------------------------------
1400
	*/
1401
1402
	/**
1403
	 * Check if a product supports a given feature.
1404
	 *
1405
	 * Product classes should override this to declare support (or lack of support) for a feature.
1406
	 *
1407
	 * @param  string $feature string The name of a feature to test support for.
1408
	 * @return bool True if the product supports the feature, false otherwise.
1409
	 * @since  2.5.0
1410
	 */
1411
	public function supports( $feature ) {
1412
		return apply_filters( 'woocommerce_product_supports', in_array( $feature, $this->supports, true ), $feature, $this );
1413
	}
1414
1415
	/**
1416
	 * Returns whether or not the product post exists.
1417
	 *
1418
	 * @return bool
1419
	 */
1420 93
	public function exists() {
1421 93
		return false !== $this->get_status();
1422
	}
1423
1424
	/**
1425
	 * Checks the product type.
1426
	 *
1427
	 * Backwards compatibility with downloadable/virtual.
1428
	 *
1429
	 * @param  string|array $type Array or string of types.
1430
	 * @return bool
1431
	 */
1432 263
	public function is_type( $type ) {
1433 263
		return ( $this->get_type() === $type || ( is_array( $type ) && in_array( $this->get_type(), $type, true ) ) );
1434
	}
1435
1436
	/**
1437
	 * Checks if a product is downloadable.
1438
	 *
1439
	 * @return bool
1440
	 */
1441 19
	public function is_downloadable() {
1442 19
		return apply_filters( 'woocommerce_is_downloadable', true === $this->get_downloadable(), $this );
1443
	}
1444
1445
	/**
1446
	 * Checks if a product is virtual (has no shipping).
1447
	 *
1448
	 * @return bool
1449
	 */
1450 21
	public function is_virtual() {
1451 21
		return apply_filters( 'woocommerce_is_virtual', true === $this->get_virtual(), $this );
1452
	}
1453
1454
	/**
1455
	 * Returns whether or not the product is featured.
1456
	 *
1457
	 * @return bool
1458
	 */
1459
	public function is_featured() {
1460
		return true === $this->get_featured();
1461
	}
1462
1463
	/**
1464
	 * Check if a product is sold individually (no quantities).
1465
	 *
1466
	 * @return bool
1467
	 */
1468 84
	public function is_sold_individually() {
1469 84
		return apply_filters( 'woocommerce_is_sold_individually', true === $this->get_sold_individually(), $this );
1470
	}
1471
1472
	/**
1473
	 * Returns whether or not the product is visible in the catalog.
1474
	 *
1475
	 * @return bool
1476
	 */
1477 2
	public function is_visible() {
1478 2
		$visible = 'visible' === $this->get_catalog_visibility() || ( is_search() && 'search' === $this->get_catalog_visibility() ) || ( ! is_search() && 'catalog' === $this->get_catalog_visibility() );
1479
1480 2
		if ( 'trash' === $this->get_status() ) {
1481
			$visible = false;
1482 2
		} elseif ( 'publish' !== $this->get_status() && ! current_user_can( 'edit_post', $this->get_id() ) ) {
1483
			$visible = false;
1484
		}
1485
1486 2
		if ( $this->get_parent_id() ) {
1487
			$parent_product = wc_get_product( $this->get_parent_id() );
1488
1489
			if ( $parent_product && 'publish' !== $parent_product->get_status() ) {
1490
				$visible = false;
1491
			}
1492
		}
1493
1494 2
		if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && ! $this->is_in_stock() ) {
1495
			$visible = false;
1496
		}
1497
1498 2
		return apply_filters( 'woocommerce_product_is_visible', $visible, $this->get_id() );
1499
	}
1500
1501
	/**
1502
	 * Returns false if the product cannot be bought.
1503
	 *
1504
	 * @return bool
1505
	 */
1506 83
	public function is_purchasable() {
1507 83
		return apply_filters( 'woocommerce_is_purchasable', $this->exists() && ( 'publish' === $this->get_status() || current_user_can( 'edit_post', $this->get_id() ) ) && '' !== $this->get_price(), $this );
1508
	}
1509
1510
	/**
1511
	 * Returns whether or not the product is on sale.
1512
	 *
1513
	 * @param  string $context What the value is for. Valid values are view and edit.
1514
	 * @return bool
1515
	 */
1516 236
	public function is_on_sale( $context = 'view' ) {
1517 236
		if ( '' !== (string) $this->get_sale_price( $context ) && $this->get_regular_price( $context ) > $this->get_sale_price( $context ) ) {
1518 13
			$on_sale = true;
1519
1520 13 View Code Duplication
			if ( $this->get_date_on_sale_from( $context ) && $this->get_date_on_sale_from( $context )->getTimestamp() > current_time( 'timestamp', true ) ) {
1521 1
				$on_sale = false;
1522
			}
1523
1524 13 View Code Duplication
			if ( $this->get_date_on_sale_to( $context ) && $this->get_date_on_sale_to( $context )->getTimestamp() < current_time( 'timestamp', true ) ) {
1525 13
				$on_sale = false;
1526
			}
1527
		} else {
1528 234
			$on_sale = false;
1529
		}
1530 236
		return 'view' === $context ? apply_filters( 'woocommerce_product_is_on_sale', $on_sale, $this ) : $on_sale;
1531
	}
1532
1533
	/**
1534
	 * Returns whether or not the product has dimensions set.
1535
	 *
1536
	 * @return bool
1537
	 */
1538
	public function has_dimensions() {
1539
		return ( $this->get_length() || $this->get_height() || $this->get_width() ) && ! $this->get_virtual();
1540
	}
1541
1542
	/**
1543
	 * Returns whether or not the product has weight set.
1544
	 *
1545
	 * @return bool
1546
	 */
1547 1
	public function has_weight() {
1548 1
		return $this->get_weight() && ! $this->get_virtual();
1549
	}
1550
1551
	/**
1552
	 * Returns whether or not the product can be purchased.
1553
	 * This returns true for 'instock' and 'onbackorder' stock statuses.
1554
	 *
1555
	 * @return bool
1556
	 */
1557 83
	public function is_in_stock() {
1558 83
		return apply_filters( 'woocommerce_product_is_in_stock', 'outofstock' !== $this->get_stock_status(), $this );
1559
	}
1560
1561
	/**
1562
	 * Checks if a product needs shipping.
1563
	 *
1564
	 * @return bool
1565
	 */
1566 18
	public function needs_shipping() {
1567 18
		return apply_filters( 'woocommerce_product_needs_shipping', ! $this->is_virtual(), $this );
1568
	}
1569
1570
	/**
1571
	 * Returns whether or not the product is taxable.
1572
	 *
1573
	 * @return bool
1574
	 */
1575 88
	public function is_taxable() {
1576 88
		return apply_filters( 'woocommerce_product_is_taxable', $this->get_tax_status() === 'taxable' && wc_tax_enabled(), $this );
1577
	}
1578
1579
	/**
1580
	 * Returns whether or not the product shipping is taxable.
1581
	 *
1582
	 * @return bool
1583
	 */
1584 6
	public function is_shipping_taxable() {
1585 6
		return $this->needs_shipping() && ( $this->get_tax_status() === 'taxable' || $this->get_tax_status() === 'shipping' );
1586
	}
1587
1588
	/**
1589
	 * Returns whether or not the product is stock managed.
1590
	 *
1591
	 * @return bool
1592
	 */
1593 103
	public function managing_stock() {
1594 103
		if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) {
1595 103
			return $this->get_manage_stock();
1596
		}
1597
		return false;
1598
	}
1599
1600
	/**
1601
	 * Returns whether or not the product can be backordered.
1602
	 *
1603
	 * @return bool
1604
	 */
1605 7
	public function backorders_allowed() {
1606 7
		return apply_filters( 'woocommerce_product_backorders_allowed', ( 'yes' === $this->get_backorders() || 'notify' === $this->get_backorders() ), $this->get_id(), $this );
1607
	}
1608
1609
	/**
1610
	 * Returns whether or not the product needs to notify the customer on backorder.
1611
	 *
1612
	 * @return bool
1613
	 */
1614 9
	public function backorders_require_notification() {
1615 9
		return apply_filters( 'woocommerce_product_backorders_require_notification', ( $this->managing_stock() && 'notify' === $this->get_backorders() ), $this );
1616
	}
1617
1618
	/**
1619
	 * Check if a product is on backorder.
1620
	 *
1621
	 * @param  int $qty_in_cart (default: 0).
1622
	 * @return bool
1623
	 */
1624 5
	public function is_on_backorder( $qty_in_cart = 0 ) {
1625 5
		if ( 'onbackorder' === $this->get_stock_status() ) {
1626
			return true;
1627
		}
1628
1629 5
		return $this->managing_stock() && $this->backorders_allowed() && ( $this->get_stock_quantity() - $qty_in_cart ) < 0;
1630
	}
1631
1632
	/**
1633
	 * Returns whether or not the product has enough stock for the order.
1634
	 *
1635
	 * @param  mixed $quantity Quantity of a product added to an order.
1636
	 * @return bool
1637
	 */
1638 82
	public function has_enough_stock( $quantity ) {
1639 82
		return ! $this->managing_stock() || $this->backorders_allowed() || $this->get_stock_quantity() >= $quantity;
1640
	}
1641
1642
	/**
1643
	 * Returns whether or not the product has any visible attributes.
1644
	 *
1645
	 * @return boolean
1646
	 */
1647
	public function has_attributes() {
1648
		foreach ( $this->get_attributes() as $attribute ) {
1649
			if ( $attribute->get_visible() ) {
1650
				return true;
1651
			}
1652
		}
1653
		return false;
1654
	}
1655
1656
	/**
1657
	 * Returns whether or not the product has any child product.
1658
	 *
1659
	 * @return bool
1660
	 */
1661
	public function has_child() {
1662
		return 0 < count( $this->get_children() );
1663
	}
1664
1665
	/**
1666
	 * Does a child have dimensions?
1667
	 *
1668
	 * @since  3.0.0
1669
	 * @return bool
1670
	 */
1671
	public function child_has_dimensions() {
1672
		return false;
1673
	}
1674
1675
	/**
1676
	 * Does a child have a weight?
1677
	 *
1678
	 * @since  3.0.0
1679
	 * @return boolean
1680
	 */
1681
	public function child_has_weight() {
1682
		return false;
1683
	}
1684
1685
	/**
1686
	 * Check if downloadable product has a file attached.
1687
	 *
1688
	 * @since 1.6.2
1689
	 *
1690
	 * @param  string $download_id file identifier.
1691
	 * @return bool Whether downloadable product has a file attached.
1692
	 */
1693 3
	public function has_file( $download_id = '' ) {
1694 3
		return $this->is_downloadable() && $this->get_file( $download_id );
1695
	}
1696
1697
	/**
1698
	 * Returns whether or not the product has additional options that need
1699
	 * selecting before adding to cart.
1700
	 *
1701
	 * @since  3.0.0
1702
	 * @return boolean
1703
	 */
1704
	public function has_options() {
1705
		return false;
1706
	}
1707
1708
	/*
1709
	|--------------------------------------------------------------------------
1710
	| Non-CRUD Getters
1711
	|--------------------------------------------------------------------------
1712
	*/
1713
1714
	/**
1715
	 * Get the product's title. For products this is the product name.
1716
	 *
1717
	 * @return string
1718
	 */
1719
	public function get_title() {
1720
		return apply_filters( 'woocommerce_product_title', $this->get_name(), $this );
1721
	}
1722
1723
	/**
1724
	 * Product permalink.
1725
	 *
1726
	 * @return string
1727
	 */
1728 3
	public function get_permalink() {
1729 3
		return get_permalink( $this->get_id() );
1730
	}
1731
1732
	/**
1733
	 * Returns the children IDs if applicable. Overridden by child classes.
1734
	 *
1735
	 * @return array of IDs
1736
	 */
1737
	public function get_children() {
1738
		return array();
1739
	}
1740
1741
	/**
1742
	 * If the stock level comes from another product ID, this should be modified.
1743
	 *
1744
	 * @since  3.0.0
1745
	 * @return int
1746
	 */
1747 5
	public function get_stock_managed_by_id() {
1748 5
		return $this->get_id();
1749
	}
1750
1751
	/**
1752
	 * Returns the price in html format.
1753
	 *
1754
	 * @param string $deprecated Deprecated param.
1755
	 *
1756
	 * @return string
1757
	 */
1758 6
	public function get_price_html( $deprecated = '' ) {
1759 6
		if ( '' === $this->get_price() ) {
1760
			$price = apply_filters( 'woocommerce_empty_price_html', '', $this );
1761 6
		} elseif ( $this->is_on_sale() ) {
1762 1
			$price = wc_format_sale_price( wc_get_price_to_display( $this, array( 'price' => $this->get_regular_price() ) ), wc_get_price_to_display( $this ) ) . $this->get_price_suffix();
1763
		} else {
1764 6
			$price = wc_price( wc_get_price_to_display( $this ) ) . $this->get_price_suffix();
1765
		}
1766
1767 6
		return apply_filters( 'woocommerce_get_price_html', $price, $this );
1768
	}
1769
1770
	/**
1771
	 * Get product name with SKU or ID. Used within admin.
1772
	 *
1773
	 * @return string Formatted product name
1774
	 */
1775
	public function get_formatted_name() {
1776
		if ( $this->get_sku() ) {
1777
			$identifier = $this->get_sku();
1778
		} else {
1779
			$identifier = '#' . $this->get_id();
1780
		}
1781
		return sprintf( '%2$s (%1$s)', $identifier, $this->get_name() );
1782
	}
1783
1784
	/**
1785
	 * Get min quantity which can be purchased at once.
1786
	 *
1787
	 * @since  3.0.0
1788
	 * @return int
1789
	 */
1790 5
	public function get_min_purchase_quantity() {
1791 5
		return 1;
1792
	}
1793
1794
	/**
1795
	 * Get max quantity which can be purchased at once.
1796
	 *
1797
	 * @since  3.0.0
1798
	 * @return int Quantity or -1 if unlimited.
1799
	 */
1800 5
	public function get_max_purchase_quantity() {
1801 5
		return $this->is_sold_individually() ? 1 : ( $this->backorders_allowed() || ! $this->managing_stock() ? -1 : $this->get_stock_quantity() );
1802
	}
1803
1804
	/**
1805
	 * Get the add to url used mainly in loops.
1806
	 *
1807
	 * @return string
1808
	 */
1809
	public function add_to_cart_url() {
1810
		return apply_filters( 'woocommerce_product_add_to_cart_url', $this->get_permalink(), $this );
1811
	}
1812
1813
	/**
1814
	 * Get the add to cart button text for the single page.
1815
	 *
1816
	 * @return string
1817
	 */
1818 1
	public function single_add_to_cart_text() {
1819 1
		return apply_filters( 'woocommerce_product_single_add_to_cart_text', __( 'Add to cart', 'woocommerce' ), $this );
1820
	}
1821
1822
	/**
1823
	 * Get the add to cart button text.
1824
	 *
1825
	 * @return string
1826
	 */
1827
	public function add_to_cart_text() {
1828
		return apply_filters( 'woocommerce_product_add_to_cart_text', __( 'Read more', 'woocommerce' ), $this );
1829
	}
1830
1831
	/**
1832
	 * Get the add to cart button text description - used in aria tags.
1833
	 *
1834
	 * @since  3.3.0
1835
	 * @return string
1836
	 */
1837
	public function add_to_cart_description() {
1838
		/* translators: %s: Product title */
1839
		return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( __( 'Read more about &ldquo;%s&rdquo;', 'woocommerce' ), $this->get_name() ), $this );
1840
	}
1841
1842
	/**
1843
	 * Returns the main product image.
1844
	 *
1845
	 * @param  string $size (default: 'woocommerce_thumbnail').
1846
	 * @param  array  $attr Image attributes.
1847
	 * @param  bool   $placeholder True to return $placeholder if no image is found, or false to return an empty string.
1848
	 * @return string
1849
	 */
1850 4
	public function get_image( $size = 'woocommerce_thumbnail', $attr = array(), $placeholder = true ) {
1851 4
		$image = '';
1852 4
		if ( $this->get_image_id() ) {
1853 2
			$image = wp_get_attachment_image( $this->get_image_id(), $size, false, $attr );
1854 3
		} elseif ( $this->get_parent_id() ) {
1855 1
			$parent_product = wc_get_product( $this->get_parent_id() );
1856 1
			if ( $parent_product ) {
1857 1
				$image = $parent_product->get_image( $size, $attr, $placeholder );
1858
			}
1859
		}
1860
1861 4
		if ( ! $image && $placeholder ) {
1862 1
			$image = wc_placeholder_img( $size );
1863
		}
1864
1865 4
		return apply_filters( 'woocommerce_product_get_image', $image, $this, $size, $attr, $placeholder, $image );
1866
	}
1867
1868
	/**
1869
	 * Returns the product shipping class SLUG.
1870
	 *
1871
	 * @return string
1872
	 */
1873 10
	public function get_shipping_class() {
1874 10
		if ( $class_id = $this->get_shipping_class_id() ) { // @phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found, WordPress.CodeAnalysis.AssignmentInCondition.Found
1875
			$term = get_term_by( 'id', $class_id, 'product_shipping_class' );
1876
1877
			if ( $term && ! is_wp_error( $term ) ) {
1878
				return $term->slug;
1879
			}
1880
		}
1881 10
		return '';
1882
	}
1883
1884
	/**
1885
	 * Returns a single product attribute as a string.
1886
	 *
1887
	 * @param  string $attribute to get.
1888
	 * @return string
1889
	 */
1890
	public function get_attribute( $attribute ) {
1891
		$attributes = $this->get_attributes();
1892
		$attribute  = sanitize_title( $attribute );
1893
1894
		if ( isset( $attributes[ $attribute ] ) ) {
1895
			$attribute_object = $attributes[ $attribute ];
1896
		} elseif ( isset( $attributes[ 'pa_' . $attribute ] ) ) {
1897
			$attribute_object = $attributes[ 'pa_' . $attribute ];
1898
		} else {
1899
			return '';
1900
		}
1901
		return $attribute_object->is_taxonomy() ? implode( ', ', wc_get_product_terms( $this->get_id(), $attribute_object->get_name(), array( 'fields' => 'names' ) ) ) : wc_implode_text_attributes( $attribute_object->get_options() );
1902
	}
1903
1904
	/**
1905
	 * Get the total amount (COUNT) of ratings, or just the count for one rating e.g. number of 5 star ratings.
1906
	 *
1907
	 * @param  int $value Optional. Rating value to get the count for. By default returns the count of all rating values.
1908
	 * @return int
1909
	 */
1910
	public function get_rating_count( $value = null ) {
1911
		$counts = $this->get_rating_counts();
1912
1913
		if ( is_null( $value ) ) {
1914
			return array_sum( $counts );
1915
		} elseif ( isset( $counts[ $value ] ) ) {
1916
			return absint( $counts[ $value ] );
1917
		} else {
1918
			return 0;
1919
		}
1920
	}
1921
1922
	/**
1923
	 * Get a file by $download_id.
1924
	 *
1925
	 * @param  string $download_id file identifier.
1926
	 * @return array|false if not found
1927
	 */
1928 2
	public function get_file( $download_id = '' ) {
1929 2
		$files = $this->get_downloads();
1930
1931 2
		if ( '' === $download_id ) {
1932 1
			$file = count( $files ) ? current( $files ) : false;
1933 2
		} elseif ( isset( $files[ $download_id ] ) ) {
1934 2
			$file = $files[ $download_id ];
1935
		} else {
1936
			$file = false;
1937
		}
1938
1939 2
		return apply_filters( 'woocommerce_product_file', $file, $this, $download_id );
1940
	}
1941
1942
	/**
1943
	 * Get file download path identified by $download_id.
1944
	 *
1945
	 * @param  string $download_id file identifier.
1946
	 * @return string
1947
	 */
1948
	public function get_file_download_path( $download_id ) {
1949
		$files     = $this->get_downloads();
1950
		$file_path = isset( $files[ $download_id ] ) ? $files[ $download_id ]->get_file() : '';
1951
1952
		// allow overriding based on the particular file being requested.
1953
		return apply_filters( 'woocommerce_product_file_download_path', $file_path, $this, $download_id );
1954
	}
1955
1956
	/**
1957
	 * Get the suffix to display after prices > 0.
1958
	 *
1959
	 * @param  string  $price to calculate, left blank to just use get_price().
1960
	 * @param  integer $qty   passed on to get_price_including_tax() or get_price_excluding_tax().
1961
	 * @return string
1962
	 */
1963 6
	public function get_price_suffix( $price = '', $qty = 1 ) {
1964 6
		$html = '';
1965
1966 6
		if ( ( $suffix = get_option( 'woocommerce_price_display_suffix' ) ) && wc_tax_enabled() && 'taxable' === $this->get_tax_status() ) { // @phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found, WordPress.CodeAnalysis.AssignmentInCondition.Found
1967
			if ( '' === $price ) {
1968
				$price = $this->get_price();
1969
			}
1970
			$replacements = array(
1971
				'{price_including_tax}' => wc_price( wc_get_price_including_tax( $this, array( 'qty' => $qty, 'price' => $price ) ) ), // @phpcs:ignore WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine, WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
1972
				'{price_excluding_tax}' => wc_price( wc_get_price_excluding_tax( $this, array( 'qty' => $qty, 'price' => $price ) ) ), // @phpcs:ignore WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
1973
			);
1974
			$html         = str_replace( array_keys( $replacements ), array_values( $replacements ), ' <small class="woocommerce-price-suffix">' . wp_kses_post( $suffix ) . '</small>' );
1975
		}
1976 6
		return apply_filters( 'woocommerce_get_price_suffix', $html, $this, $price, $qty );
1977
	}
1978
1979
	/**
1980
	 * Returns the availability of the product.
1981
	 *
1982
	 * @return string[]
1983
	 */
1984 5
	public function get_availability() {
1985 5
		return apply_filters(
1986 5
			'woocommerce_get_availability',
1987
			array(
1988 5
				'availability' => $this->get_availability_text(),
1989 5
				'class'        => $this->get_availability_class(),
1990
			),
1991 5
			$this
1992
		);
1993
	}
1994
1995
	/**
1996
	 * Get availability text based on stock status.
1997
	 *
1998
	 * @return string
1999
	 */
2000 5
	protected function get_availability_text() {
2001 5
		if ( ! $this->is_in_stock() ) {
2002
			$availability = __( 'Out of stock', 'woocommerce' );
2003 5
		} elseif ( $this->managing_stock() && $this->is_on_backorder( 1 ) ) {
2004
			$availability = $this->backorders_require_notification() ? __( 'Available on backorder', 'woocommerce' ) : '';
2005 5
		} elseif ( ! $this->managing_stock() && $this->is_on_backorder( 1 ) ) {
2006
			$availability = __( 'Available on backorder', 'woocommerce' );
2007 5
		} elseif ( $this->managing_stock() ) {
2008
			$availability = wc_format_stock_for_display( $this );
2009
		} else {
2010 5
			$availability = '';
2011
		}
2012 5
		return apply_filters( 'woocommerce_get_availability_text', $availability, $this );
2013
	}
2014
2015
	/**
2016
	 * Get availability classname based on stock status.
2017
	 *
2018
	 * @return string
2019
	 */
2020 5
	protected function get_availability_class() {
2021 5
		if ( ! $this->is_in_stock() ) {
2022
			$class = 'out-of-stock';
2023 5
		} elseif ( ( $this->managing_stock() && $this->is_on_backorder( 1 ) ) || ( ! $this->managing_stock() && $this->is_on_backorder( 1 ) ) ) {
2024
			$class = 'available-on-backorder';
2025
		} else {
2026 5
			$class = 'in-stock';
2027
		}
2028 5
		return apply_filters( 'woocommerce_get_availability_class', $class, $this );
2029
	}
2030
}
2031