Completed
Push — master ( 889cf6...9ef6ea )
by Gerhard
29:38 queued 17:37
created

WC_Product::set_post_password()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
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 388
	 */
121 388
	public function __construct( $product = 0 ) {
122 388
		parent::__construct( $product );
123 384 View Code Duplication
		if ( is_numeric( $product ) && $product > 0 ) {
124 386
			$this->set_id( $product );
125
		} elseif ( $product instanceof self ) {
126 386
			$this->set_id( absint( $product->get_id() ) );
127
		} elseif ( ! empty( $product->ID ) ) {
128
			$this->set_id( absint( $product->ID ) );
129 386
		} else {
130
			$this->set_object_read( true );
131
		}
132 388
133 388
		$this->data_store = WC_Data_Store::load( 'product-' . $this->get_type() );
134 384
		if ( $this->get_id() > 0 ) {
135
			$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 16
	 */
147 16
	public function get_type() {
148
		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
	public function get_name( $context = 'view' ) {
159
		return $this->get_prop( 'name', $context );
160
	}
161
162
	/**
163
	 * Get product slug.
164
	 *
165 382
	 * @since  3.0.0
166 382
	 * @param  string $context What the value is for. Valid values are view and edit.
167
	 * @return string
168
	 */
169
	public function get_slug( $context = 'view' ) {
170
		return $this->get_prop( 'slug', $context );
171
	}
172
173
	/**
174
	 * Get product created date.
175
	 *
176 382
	 * @since  3.0.0
177 382
	 * @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
	public function get_date_created( $context = 'view' ) {
181
		return $this->get_prop( 'date_created', $context );
182
	}
183
184
	/**
185
	 * Get product modified date.
186
	 *
187 382
	 * @since  3.0.0
188 382
	 * @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 36
	 * @since  3.0.0
199 36
	 * @param  string $context What the value is for. Valid values are view and edit.
200
	 * @return string
201
	 */
202
	public function get_status( $context = 'view' ) {
203
		return $this->get_prop( 'status', $context );
204
	}
205
206
	/**
207
	 * If the product is featured.
208
	 *
209 382
	 * @since  3.0.0
210 382
	 * @param  string $context What the value is for. Valid values are view and edit.
211
	 * @return boolean
212
	 */
213
	public function get_featured( $context = 'view' ) {
214
		return $this->get_prop( 'featured', $context );
215
	}
216
217
	/**
218
	 * Get catalog visibility.
219
	 *
220 381
	 * @since  3.0.0
221 381
	 * @param  string $context What the value is for. Valid values are view and edit.
222
	 * @return string
223
	 */
224
	public function get_catalog_visibility( $context = 'view' ) {
225
		return $this->get_prop( 'catalog_visibility', $context );
226
	}
227
228
	/**
229
	 * Get product description.
230
	 *
231 381
	 * @since  3.0.0
232 381
	 * @param  string $context What the value is for. Valid values are view and edit.
233
	 * @return string
234
	 */
235
	public function get_description( $context = 'view' ) {
236
		return $this->get_prop( 'description', $context );
237
	}
238
239
	/**
240
	 * Get product short description.
241
	 *
242 382
	 * @since  3.0.0
243 382
	 * @param  string $context What the value is for. Valid values are view and edit.
244
	 * @return string
245
	 */
246
	public function get_short_description( $context = 'view' ) {
247
		return $this->get_prop( 'short_description', $context );
248
	}
249
250
	/**
251
	 * Get SKU (Stock-keeping unit) - product unique ID.
252
	 *
253 381
	 * @param  string $context What the value is for. Valid values are view and edit.
254 381
	 * @return string
255
	 */
256
	public function get_sku( $context = 'view' ) {
257
		return $this->get_prop( 'sku', $context );
258
	}
259
260
	/**
261
	 * Returns the product's active price.
262
	 *
263 381
	 * @param  string $context What the value is for. Valid values are view and edit.
264 381
	 * @return string price
265
	 */
266
	public function get_price( $context = 'view' ) {
267
		return $this->get_prop( 'price', $context );
268
	}
269
270
	/**
271
	 * Returns the product's regular price.
272
	 *
273 224
	 * @param  string $context What the value is for. Valid values are view and edit.
274 224
	 * @return string price
275
	 */
276
	public function get_regular_price( $context = 'view' ) {
277
		return $this->get_prop( 'regular_price', $context );
278
	}
279
280
	/**
281
	 * Returns the product's sale price.
282
	 *
283 382
	 * @param  string $context What the value is for. Valid values are view and edit.
284 382
	 * @return string price
285
	 */
286
	public function get_sale_price( $context = 'view' ) {
287
		return $this->get_prop( 'sale_price', $context );
288
	}
289
290
	/**
291
	 * Get date on sale from.
292
	 *
293 382
	 * @since  3.0.0
294 382
	 * @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
	public function get_date_on_sale_from( $context = 'view' ) {
298
		return $this->get_prop( 'date_on_sale_from', $context );
299
	}
300
301
	/**
302
	 * Get date on sale to.
303
	 *
304 382
	 * @since  3.0.0
305 382
	 * @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
	public function get_date_on_sale_to( $context = 'view' ) {
309
		return $this->get_prop( 'date_on_sale_to', $context );
310
	}
311
312
	/**
313
	 * Get number total of sales.
314
	 *
315 382
	 * @since  3.0.0
316 382
	 * @param  string $context What the value is for. Valid values are view and edit.
317
	 * @return int
318
	 */
319
	public function get_total_sales( $context = 'view' ) {
320
		return $this->get_prop( 'total_sales', $context );
321
	}
322
323
	/**
324
	 * Returns the tax status.
325
	 *
326 382
	 * @param  string $context What the value is for. Valid values are view and edit.
327 382
	 * @return string
328
	 */
329
	public function get_tax_status( $context = 'view' ) {
330
		return $this->get_prop( 'tax_status', $context );
331
	}
332
333
	/**
334
	 * Returns the tax class.
335
	 *
336 382
	 * @param  string $context What the value is for. Valid values are view and edit.
337 382
	 * @return string
338
	 */
339
	public function get_tax_class( $context = 'view' ) {
340
		return $this->get_prop( 'tax_class', $context );
341
	}
342
343
	/**
344
	 * Return if product manage stock.
345
	 *
346 381
	 * @since  3.0.0
347 381
	 * @param  string $context What the value is for. Valid values are view and edit.
348
	 * @return boolean
349
	 */
350
	public function get_manage_stock( $context = 'view' ) {
351
		return $this->get_prop( 'manage_stock', $context );
352
	}
353
354
	/**
355
	 * Returns number of items available for sale.
356
	 *
357 381
	 * @param  string $context What the value is for. Valid values are view and edit.
358 381
	 * @return int|null
359
	 */
360
	public function get_stock_quantity( $context = 'view' ) {
361
		return $this->get_prop( 'stock_quantity', $context );
362
	}
363
364
	/**
365
	 * Return the stock status.
366
	 *
367 381
	 * @param  string $context What the value is for. Valid values are view and edit.
368 381
	 * @since  3.0.0
369
	 * @return string
370
	 */
371
	public function get_stock_status( $context = 'view' ) {
372
		return $this->get_prop( 'stock_status', $context );
373
	}
374
375
	/**
376
	 * Get backorders.
377
	 *
378 382
	 * @param  string $context What the value is for. Valid values are view and edit.
379 382
	 * @since  3.0.0
380
	 * @return string yes no or notify
381
	 */
382
	public function get_backorders( $context = 'view' ) {
383
		return $this->get_prop( 'backorders', $context );
384
	}
385
386
	/**
387
	 * Get low stock amount.
388
	 *
389 381
	 * @param  string $context What the value is for. Valid values are view and edit.
390 381
	 * @since  3.5.0
391
	 * @return int|string Returns empty string if value not set
392
	 */
393
	public function get_low_stock_amount( $context = 'view' ) {
394
		return $this->get_prop( 'low_stock_amount', $context );
395
	}
396
397
	/**
398
	 * Return if should be sold individually.
399
	 *
400 382
	 * @param  string $context What the value is for. Valid values are view and edit.
401 382
	 * @since  3.0.0
402
	 * @return boolean
403
	 */
404
	public function get_sold_individually( $context = 'view' ) {
405
		return $this->get_prop( 'sold_individually', $context );
406
	}
407
408
	/**
409
	 * Returns the product's weight.
410
	 *
411 382
	 * @param  string $context What the value is for. Valid values are view and edit.
412 382
	 * @return string
413
	 */
414
	public function get_weight( $context = 'view' ) {
415
		return $this->get_prop( 'weight', $context );
416
	}
417
418
	/**
419
	 * Returns the product length.
420
	 *
421 381
	 * @param  string $context What the value is for. Valid values are view and edit.
422 381
	 * @return string
423
	 */
424
	public function get_length( $context = 'view' ) {
425
		return $this->get_prop( 'length', $context );
426
	}
427
428
	/**
429
	 * Returns the product width.
430
	 *
431 381
	 * @param  string $context What the value is for. Valid values are view and edit.
432 381
	 * @return string
433
	 */
434
	public function get_width( $context = 'view' ) {
435
		return $this->get_prop( 'width', $context );
436
	}
437
438
	/**
439
	 * Returns the product height.
440
	 *
441 381
	 * @param  string $context What the value is for. Valid values are view and edit.
442 381
	 * @return string
443
	 */
444
	public function get_height( $context = 'view' ) {
445
		return $this->get_prop( 'height', $context );
446
	}
447
448
	/**
449
	 * Returns formatted dimensions.
450
	 *
451 381
	 * @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 381
	 * @return string|array
453
	 */
454
	public function get_dimensions( $formatted = true ) {
455
		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
			'length' => $this->get_length(),
461 5
			'width'  => $this->get_width(),
462 5
			'height' => $this->get_height(),
463
		);
464
	}
465
466
	/**
467 5
	 * Get upsell IDs.
468 5
	 *
469 5
	 * @since  3.0.0
470
	 * @param  string $context What the value is for. Valid values are view and edit.
471
	 * @return array
472
	 */
473
	public function get_upsell_ids( $context = 'view' ) {
474
		return $this->get_prop( 'upsell_ids', $context );
475
	}
476
477
	/**
478
	 * Get cross sell IDs.
479
	 *
480 382
	 * @since  3.0.0
481 382
	 * @param  string $context What the value is for. Valid values are view and edit.
482
	 * @return array
483
	 */
484
	public function get_cross_sell_ids( $context = 'view' ) {
485
		return $this->get_prop( 'cross_sell_ids', $context );
486
	}
487
488
	/**
489
	 * Get parent ID.
490
	 *
491 382
	 * @since  3.0.0
492 382
	 * @param  string $context What the value is for. Valid values are view and edit.
493
	 * @return int
494
	 */
495
	public function get_parent_id( $context = 'view' ) {
496
		return $this->get_prop( 'parent_id', $context );
497
	}
498
499
	/**
500
	 * Return if reviews is allowed.
501
	 *
502 384
	 * @since  3.0.0
503 384
	 * @param  string $context What the value is for. Valid values are view and edit.
504
	 * @return bool
505
	 */
506
	public function get_reviews_allowed( $context = 'view' ) {
507
		return $this->get_prop( 'reviews_allowed', $context );
508
	}
509
510
	/**
511
	 * Get purchase note.
512
	 *
513 381
	 * @since  3.0.0
514 381
	 * @param  string $context What the value is for. Valid values are view and edit.
515
	 * @return string
516
	 */
517
	public function get_purchase_note( $context = 'view' ) {
518
		return $this->get_prop( 'purchase_note', $context );
519
	}
520
521
	/**
522
	 * Returns product attributes.
523
	 *
524 381
	 * @param  string $context What the value is for. Valid values are view and edit.
525 381
	 * @return array
526
	 */
527
	public function get_attributes( $context = 'view' ) {
528
		return $this->get_prop( 'attributes', $context );
529
	}
530
531
	/**
532
	 * Get default attributes.
533
	 *
534 382
	 * @since  3.0.0
535 382
	 * @param  string $context What the value is for. Valid values are view and edit.
536
	 * @return array
537
	 */
538
	public function get_default_attributes( $context = 'view' ) {
539
		return $this->get_prop( 'default_attributes', $context );
540
	}
541
542
	/**
543
	 * Get menu order.
544
	 *
545 382
	 * @since  3.0.0
546 382
	 * @param  string $context What the value is for. Valid values are view and edit.
547
	 * @return int
548
	 */
549
	public function get_menu_order( $context = 'view' ) {
550
		return $this->get_prop( 'menu_order', $context );
551
	}
552
553
	/**
554
	 * Get post password.
555
	 *
556 382
	 * @since  3.6.0
557 382
	 * @param  string $context What the value is for. Valid values are view and edit.
558
	 * @return int
559
	 */
560
	public function get_post_password( $context = 'view' ) {
561
		return $this->get_prop( 'post_password', $context );
562
	}
563
564
	/**
565
	 * Get category ids.
566
	 *
567 381
	 * @since  3.0.0
568 381
	 * @param  string $context What the value is for. Valid values are view and edit.
569
	 * @return array
570
	 */
571
	public function get_category_ids( $context = 'view' ) {
572
		return $this->get_prop( 'category_ids', $context );
573
	}
574
575
	/**
576
	 * Get tag ids.
577
	 *
578 381
	 * @since  3.0.0
579 381
	 * @param  string $context What the value is for. Valid values are view and edit.
580
	 * @return array
581
	 */
582
	public function get_tag_ids( $context = 'view' ) {
583
		return $this->get_prop( 'tag_ids', $context );
584
	}
585
586
	/**
587
	 * Get virtual.
588
	 *
589 379
	 * @since  3.0.0
590 379
	 * @param  string $context What the value is for. Valid values are view and edit.
591
	 * @return bool
592
	 */
593
	public function get_virtual( $context = 'view' ) {
594
		return $this->get_prop( 'virtual', $context );
595
	}
596
597
	/**
598
	 * Returns the gallery attachment ids.
599 382
	 *
600 382
	 * @param  string $context What the value is for. Valid values are view and edit.
601
	 * @return array
602
	 */
603
	public function get_gallery_image_ids( $context = 'view' ) {
604
		return $this->get_prop( 'gallery_image_ids', $context );
605
	}
606
607
	/**
608
	 * Get shipping class ID.
609
	 *
610 381
	 * @since  3.0.0
611 381
	 * @param  string $context What the value is for. Valid values are view and edit.
612
	 * @return int
613
	 */
614
	public function get_shipping_class_id( $context = 'view' ) {
615
		return $this->get_prop( 'shipping_class_id', $context );
616
	}
617
618
	/**
619
	 * Get downloads.
620
	 *
621 382
	 * @since  3.0.0
622 382
	 * @param  string $context What the value is for. Valid values are view and edit.
623
	 * @return array
624
	 */
625
	public function get_downloads( $context = 'view' ) {
626
		return $this->get_prop( 'downloads', $context );
627
	}
628
629
	/**
630
	 * Get download expiry.
631
	 *
632 382
	 * @since  3.0.0
633 382
	 * @param  string $context What the value is for. Valid values are view and edit.
634
	 * @return int
635
	 */
636
	public function get_download_expiry( $context = 'view' ) {
637
		return $this->get_prop( 'download_expiry', $context );
638
	}
639
640
	/**
641
	 * Get downloadable.
642
	 *
643 379
	 * @since  3.0.0
644 379
	 * @param  string $context What the value is for. Valid values are view and edit.
645
	 * @return bool
646
	 */
647
	public function get_downloadable( $context = 'view' ) {
648
		return $this->get_prop( 'downloadable', $context );
649
	}
650
651
	/**
652
	 * Get download limit.
653
	 *
654 382
	 * @since  3.0.0
655 382
	 * @param  string $context What the value is for. Valid values are view and edit.
656
	 * @return int
657
	 */
658
	public function get_download_limit( $context = 'view' ) {
659
		return $this->get_prop( 'download_limit', $context );
660
	}
661
662
	/**
663
	 * Get main image ID.
664
	 *
665 383
	 * @since  3.0.0
666 383
	 * @param  string $context What the value is for. Valid values are view and edit.
667
	 * @return string
668
	 */
669
	public function get_image_id( $context = 'view' ) {
670
		return $this->get_prop( 'image_id', $context );
671
	}
672
673
	/**
674
	 * Get rating count.
675 382
	 *
676 382
	 * @param  string $context What the value is for. Valid values are view and edit.
677
	 * @return array of counts
678
	 */
679
	public function get_rating_counts( $context = 'view' ) {
680
		return $this->get_prop( 'rating_counts', $context );
681
	}
682
683
	/**
684
	 * Get average rating.
685 382
	 *
686 382
	 * @param  string $context What the value is for. Valid values are view and edit.
687
	 * @return float
688
	 */
689
	public function get_average_rating( $context = 'view' ) {
690
		return $this->get_prop( 'average_rating', $context );
691
	}
692
693
	/**
694
	 * Get review count.
695 382
	 *
696 382
	 * @param  string $context What the value is for. Valid values are view and edit.
697
	 * @return int
698
	 */
699
	public function get_review_count( $context = 'view' ) {
700
		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 382
	 *
716 382
	 * @since 3.0.0
717
	 * @param string $name Product name.
718
	 */
719
	public function set_name( $name ) {
720
		$this->set_prop( 'name', $name );
721
	}
722
723
	/**
724
	 * Set product slug.
725 382
	 *
726 382
	 * @since 3.0.0
727
	 * @param string $slug Product slug.
728
	 */
729
	public function set_slug( $slug ) {
730
		$this->set_prop( 'slug', $slug );
731
	}
732
733
	/**
734
	 * Set product created date.
735 382
	 *
736 382
	 * @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
	public function set_date_created( $date = null ) {
740
		$this->set_date_prop( 'date_created', $date );
741
	}
742
743
	/**
744
	 * Set product modified date.
745 382
	 *
746 382
	 * @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
	public function set_date_modified( $date = null ) {
750
		$this->set_date_prop( 'date_modified', $date );
751
	}
752
753
	/**
754
	 * Set product status.
755 382
	 *
756 382
	 * @since 3.0.0
757
	 * @param string $status Product status.
758
	 */
759
	public function set_status( $status ) {
760
		$this->set_prop( 'status', $status );
761
	}
762
763
	/**
764
	 * Set if the product is featured.
765 381
	 *
766 381
	 * @since 3.0.0
767
	 * @param bool|string $featured Whether the product is featured or not.
768
	 */
769
	public function set_featured( $featured ) {
770
		$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 381
	 * @since  3.0.0
777 381
	 * @throws WC_Data_Exception Throws exception when invalid data is found.
778 381
	 * @param  string $visibility Options: 'hidden', 'visible', 'search' and 'catalog'.
779
	 */
780 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 381
		$options = array_keys( wc_get_product_visibility_options() );
782
		if ( ! in_array( $visibility, $options, true ) ) {
783
			$this->error( 'product_invalid_catalog_visibility', __( 'Invalid catalog visibility option.', 'woocommerce' ) );
784
		}
785
		$this->set_prop( 'catalog_visibility', $visibility );
786
	}
787
788
	/**
789
	 * Set product description.
790 382
	 *
791 382
	 * @since 3.0.0
792
	 * @param string $description Product description.
793
	 */
794
	public function set_description( $description ) {
795
		$this->set_prop( 'description', $description );
796
	}
797
798
	/**
799
	 * Set product short description.
800 381
	 *
801 381
	 * @since 3.0.0
802
	 * @param string $short_description Product short description.
803
	 */
804
	public function set_short_description( $short_description ) {
805
		$this->set_prop( 'short_description', $short_description );
806
	}
807
808
	/**
809
	 * Set SKU.
810
	 *
811 382
	 * @since  3.0.0
812 382
	 * @throws WC_Data_Exception Throws exception when invalid data is found.
813 382
	 * @param  string $sku Product SKU.
814 79
	 */
815
	public function set_sku( $sku ) {
816 79
		$sku = (string) $sku;
817
		if ( $this->get_object_read() && ! empty( $sku ) && ! wc_product_has_unique_sku( $this->get_id(), $sku ) ) {
818 382
			$sku_found = wc_get_product_id_by_sku( $sku );
819
820
			$this->error( 'product_invalid_sku', __( 'Invalid or duplicated SKU.', 'woocommerce' ), 400, array( 'resource_id' => $sku_found ) );
821
		}
822
		$this->set_prop( 'sku', $sku );
823
	}
824
825
	/**
826 382
	 * Set the product's active price.
827 382
	 *
828
	 * @param string $price Price.
829
	 */
830
	public function set_price( $price ) {
831
		$this->set_prop( 'price', wc_format_decimal( $price ) );
832
	}
833
834
	/**
835
	 * Set the product's regular price.
836 382
	 *
837 382
	 * @since 3.0.0
838
	 * @param string $price Regular price.
839
	 */
840
	public function set_regular_price( $price ) {
841
		$this->set_prop( 'regular_price', wc_format_decimal( $price ) );
842
	}
843
844
	/**
845
	 * Set the product's sale price.
846 382
	 *
847 382
	 * @since 3.0.0
848
	 * @param string $price sale price.
849
	 */
850
	public function set_sale_price( $price ) {
851
		$this->set_prop( 'sale_price', wc_format_decimal( $price ) );
852
	}
853
854
	/**
855
	 * Set date on sale from.
856 382
	 *
857 382
	 * @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
	public function set_date_on_sale_from( $date = null ) {
861
		$this->set_date_prop( 'date_on_sale_from', $date );
862
	}
863
864
	/**
865
	 * Set date on sale to.
866 382
	 *
867 382
	 * @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
	public function set_date_on_sale_to( $date = null ) {
871
		$this->set_date_prop( 'date_on_sale_to', $date );
872
	}
873
874
	/**
875
	 * Set number total of sales.
876 381
	 *
877 381
	 * @since 3.0.0
878
	 * @param int $total Total of sales.
879
	 */
880
	public function set_total_sales( $total ) {
881
		$this->set_prop( 'total_sales', absint( $total ) );
882
	}
883
884
	/**
885
	 * Set the tax status.
886
	 *
887 382
	 * @since  3.0.0
888
	 * @throws WC_Data_Exception Throws exception when invalid data is found.
889 382
	 * @param  string $status Tax status.
890
	 */
891
	public function set_tax_status( $status ) {
892
		$options = array(
893
			'taxable',
894
			'shipping',
895 382
			'none',
896 5
		);
897
898
		// Set default if empty.
899 382
		if ( empty( $status ) ) {
900
			$status = 'taxable';
901
		}
902
903 382
		if ( ! in_array( $status, $options, true ) ) {
904
			$this->error( 'product_invalid_tax_status', __( 'Invalid product tax status.', 'woocommerce' ) );
905
		}
906
907
		$this->set_prop( 'tax_status', $status );
908
	}
909
910
	/**
911
	 * Set the tax class.
912 382
	 *
913 382
	 * @since 3.0.0
914 382
	 * @param string $class Tax class.
915 382
	 */
916
	public function set_tax_class( $class ) {
917 382
		$class         = sanitize_title( $class );
918 381
		$class         = 'standard' === $class ? '' : $class;
919
		$valid_classes = $this->get_valid_tax_classes();
920
921 382
		if ( ! in_array( $class, $valid_classes, true ) ) {
922
			$class = '';
923
		}
924
925
		$this->set_prop( 'tax_class', $class );
926
	}
927
928
	/**
929 381
	 * Return an array of valid tax classes
930 381
	 *
931
	 * @return array valid tax classes
932
	 */
933
	protected function get_valid_tax_classes() {
934
		return WC_Tax::get_tax_class_slugs();
935
	}
936
937
	/**
938
	 * Set if product manage stock.
939 377
	 *
940 377
	 * @since 3.0.0
941
	 * @param bool $manage_stock Whether or not manage stock is enabled.
942
	 */
943
	public function set_manage_stock( $manage_stock ) {
944
		$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 382
	 *
950 382
	 * @since 3.0.0
951
	 * @param float|null $quantity Stock quantity.
952
	 */
953
	public function set_stock_quantity( $quantity ) {
954
		$this->set_prop( 'stock_quantity', '' !== $quantity ? wc_stock_amount( $quantity ) : null );
955
	}
956
957
	/**
958 377
	 * Set stock status.
959 377
	 *
960
	 * @param string $status New status.
961 377
	 */
962 377
	public function set_stock_status( $status = 'instock' ) {
963
		$valid_statuses = wc_get_product_stock_status_options();
964 60
965
		if ( isset( $valid_statuses[ $status ] ) ) {
966
			$this->set_prop( 'stock_status', $status );
967
		} else {
968
			$this->set_prop( 'stock_status', 'instock' );
969
		}
970
	}
971
972
	/**
973
	 * Set backorders.
974 377
	 *
975 377
	 * @since 3.0.0
976
	 * @param string $backorders Options: 'yes', 'no' or 'notify'.
977
	 */
978
	public function set_backorders( $backorders ) {
979
		$this->set_prop( 'backorders', $backorders );
980
	}
981
982
	/**
983
	 * Set low stock amount.
984 382
	 *
985 382
	 * @param int|string $amount Empty string if value not set.
986
	 * @since 3.5.0
987
	 */
988
	public function set_low_stock_amount( $amount ) {
989
		$this->set_prop( 'low_stock_amount', '' === $amount ? '' : absint( $amount ) );
990
	}
991
992
	/**
993
	 * Set if should be sold individually.
994 382
	 *
995 382
	 * @since 3.0.0
996
	 * @param bool $sold_individually Whether or not product is sold individually.
997
	 */
998
	public function set_sold_individually( $sold_individually ) {
999
		$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 382
	 *
1005 382
	 * @since 3.0.0
1006
	 * @param float|string $weight Total weight.
1007
	 */
1008
	public function set_weight( $weight ) {
1009
		$this->set_prop( 'weight', '' === $weight ? '' : wc_format_decimal( $weight ) );
1010
	}
1011
1012
	/**
1013
	 * Set the product length.
1014 382
	 *
1015 382
	 * @since 3.0.0
1016
	 * @param float|string $length Total length.
1017
	 */
1018
	public function set_length( $length ) {
1019
		$this->set_prop( 'length', '' === $length ? '' : wc_format_decimal( $length ) );
1020
	}
1021
1022
	/**
1023
	 * Set the product width.
1024 382
	 *
1025 382
	 * @since 3.0.0
1026
	 * @param float|string $width Total width.
1027
	 */
1028
	public function set_width( $width ) {
1029
		$this->set_prop( 'width', '' === $width ? '' : wc_format_decimal( $width ) );
1030
	}
1031
1032
	/**
1033
	 * Set the product height.
1034 382
	 *
1035 382
	 * @since 3.0.0
1036
	 * @param float|string $height Total height.
1037
	 */
1038
	public function set_height( $height ) {
1039
		$this->set_prop( 'height', '' === $height ? '' : wc_format_decimal( $height ) );
1040
	}
1041
1042
	/**
1043
	 * Set upsell IDs.
1044 381
	 *
1045 381
	 * @since 3.0.0
1046
	 * @param array $upsell_ids IDs from the up-sell products.
1047
	 */
1048
	public function set_upsell_ids( $upsell_ids ) {
1049
		$this->set_prop( 'upsell_ids', array_filter( (array) $upsell_ids ) );
1050
	}
1051
1052
	/**
1053
	 * Set crosssell IDs.
1054 382
	 *
1055 382
	 * @since 3.0.0
1056
	 * @param array $cross_sell_ids IDs from the cross-sell products.
1057
	 */
1058
	public function set_cross_sell_ids( $cross_sell_ids ) {
1059
		$this->set_prop( 'cross_sell_ids', array_filter( (array) $cross_sell_ids ) );
1060
	}
1061
1062
	/**
1063
	 * Set parent ID.
1064 382
	 *
1065 382
	 * @since 3.0.0
1066
	 * @param int $parent_id Product parent ID.
1067
	 */
1068
	public function set_parent_id( $parent_id ) {
1069
		$this->set_prop( 'parent_id', absint( $parent_id ) );
1070
	}
1071
1072
	/**
1073
	 * Set if reviews is allowed.
1074 382
	 *
1075 382
	 * @since 3.0.0
1076
	 * @param bool $reviews_allowed Reviews allowed or not.
1077
	 */
1078
	public function set_reviews_allowed( $reviews_allowed ) {
1079
		$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 381
	 *
1085 381
	 * @since 3.0.0
1086
	 * @param string $purchase_note Purchase note.
1087
	 */
1088
	public function set_purchase_note( $purchase_note ) {
1089
		$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 53
	 *
1104 53
	 * @since 3.0.0
1105 53
	 * @param array $raw_attributes Array of WC_Product_Attribute objects.
1106 53
	 */
1107 53
	public function set_attributes( $raw_attributes ) {
1108
		$attributes = array_fill_keys( array_keys( $this->get_attributes( 'edit' ) ), null );
1109
		foreach ( $raw_attributes as $attribute ) {
1110
			if ( is_a( $attribute, 'WC_Product_Attribute' ) ) {
1111 53
				$attributes[ sanitize_title( $attribute->get_name() ) ] = $attribute;
1112 53
			}
1113
		}
1114
1115
		uasort( $attributes, 'wc_product_attribute_uasort_comparison' );
1116
		$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 381
	 *
1122 381
	 * @since 3.0.0
1123
	 * @param array $default_attributes List of default attributes.
1124
	 */
1125
	public function set_default_attributes( $default_attributes ) {
1126
		$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 382
	 *
1132 382
	 * @since 3.0.0
1133
	 * @param int $menu_order Menu order.
1134
	 */
1135
	public function set_menu_order( $menu_order ) {
1136
		$this->set_prop( 'menu_order', intval( $menu_order ) );
1137
	}
1138
1139
	/**
1140
	 * Set post password.
1141 381
	 *
1142 381
	 * @since 3.6.0
1143
	 * @param int $post_password Post password.
1144
	 */
1145
	public function set_post_password( $post_password ) {
1146
		$this->set_prop( 'post_password', $post_password );
1147
	}
1148
1149
	/**
1150
	 * Set the product categories.
1151 381
	 *
1152 381
	 * @since 3.0.0
1153
	 * @param array $term_ids List of terms IDs.
1154
	 */
1155
	public function set_category_ids( $term_ids ) {
1156
		$this->set_prop( 'category_ids', array_unique( array_map( 'intval', $term_ids ) ) );
1157
	}
1158
1159
	/**
1160
	 * Set the product tags.
1161 382
	 *
1162 382
	 * @since 3.0.0
1163
	 * @param array $term_ids List of terms IDs.
1164
	 */
1165
	public function set_tag_ids( $term_ids ) {
1166
		$this->set_prop( 'tag_ids', array_unique( array_map( 'intval', $term_ids ) ) );
1167
	}
1168
1169
	/**
1170
	 * Set if the product is virtual.
1171 382
	 *
1172 382
	 * @since 3.0.0
1173
	 * @param bool|string $virtual Whether product is virtual or not.
1174
	 */
1175
	public function set_virtual( $virtual ) {
1176
		$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 382
	 *
1182 382
	 * @since 3.0.0
1183
	 * @param int $id Product shipping class id.
1184
	 */
1185
	public function set_shipping_class_id( $id ) {
1186
		$this->set_prop( 'shipping_class_id', absint( $id ) );
1187
	}
1188
1189
	/**
1190
	 * Set if the product is downloadable.
1191 3
	 *
1192 3
	 * @since 3.0.0
1193 3
	 * @param bool|string $downloadable Whether product is downloadable or not.
1194
	 */
1195 3
	public function set_downloadable( $downloadable ) {
1196 3
		$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 3
	}
1198
1199 1
	/**
1200
	 * Set downloads.
1201
	 *
1202 1
	 * @since 3.0.0
1203 1
	 * @param array $downloads_array Array of WC_Product_Download objects or arrays.
1204
	 */
1205
	public function set_downloads( $downloads_array ) {
1206 1
		$downloads = array();
1207 1
		$errors    = array();
1208 1
1209
		foreach ( $downloads_array as $download ) {
1210
			if ( is_a( $download, 'WC_Product_Download' ) ) {
1211
				$download_object = $download;
1212 3
			} else {
1213
				$download_object = new WC_Product_Download();
1214
1215
				// If we don't have a previous hash, generate UUID for download.
1216
				if ( empty( $download['download_id'] ) ) {
1217
					$download['download_id'] = wp_generate_uuid4();
1218
				}
1219
1220
				$download_object->set_id( $download['download_id'] );
1221 3
				$download_object->set_name( $download['name'] );
1222
				$download_object->set_file( $download['file'] );
1223
			}
1224
1225
			// Validate the file extension.
1226
			if ( ! $download_object->is_allowed_filetype() ) {
1227
				if ( $this->get_object_read() ) {
1228
					/* translators: %1$s: Downloadable file */
1229 3
					$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 3
			}
1233
1234
			// Validate the file exists.
1235
			if ( ! $download_object->file_exists() ) {
1236 3
				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
			$downloads[ $download_object->get_id() ] = $download_object;
1244
		}
1245 382
1246 382
		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
		$this->set_prop( 'downloads', $downloads );
1251
	}
1252
1253
	/**
1254
	 * Set download limit.
1255 382
	 *
1256 382
	 * @since 3.0.0
1257
	 * @param int|string $download_limit Product download limit.
1258
	 */
1259
	public function set_download_limit( $download_limit ) {
1260
		$this->set_prop( 'download_limit', -1 === (int) $download_limit || '' === $download_limit ? -1 : absint( $download_limit ) );
1261
	}
1262
1263
	/**
1264
	 * Set download expiry.
1265 382
	 *
1266 382
	 * @since 3.0.0
1267
	 * @param int|string $download_expiry Product download expiry.
1268 382
	 */
1269 6
	public function set_download_expiry( $download_expiry ) {
1270
		$this->set_prop( 'download_expiry', -1 === (int) $download_expiry || '' === $download_expiry ? -1 : absint( $download_expiry ) );
1271
	}
1272 382
1273
	/**
1274
	 * Set gallery attachment ids.
1275
	 *
1276
	 * @since 3.0.0
1277
	 * @param array $image_ids List of image ids.
1278
	 */
1279
	public function set_gallery_image_ids( $image_ids ) {
1280
		$image_ids = wp_parse_id_list( $image_ids );
1281 382
1282 382
		$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 381
	 */
1291 381
	public function set_image_id( $image_id = '' ) {
1292
		$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 381
	 */
1300 381
	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 381
	 */
1309 381
	public function set_average_rating( $average ) {
1310
		$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
	public function set_review_count( $count ) {
1319
		$this->set_prop( 'review_count', absint( $count ) );
1320
	}
1321
1322
	/*
1323 379
	|--------------------------------------------------------------------------
1324
	| Other Methods
1325 379
	|--------------------------------------------------------------------------
1326 377
	*/
1327 377
1328 377
	/**
1329
	 * Ensure properties are set correctly before save.
1330
	 *
1331 10
	 * @since 3.0.0
1332 6
	 */
1333
	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 8
		if ( ! $this->get_manage_stock() ) {
1336 2
			$this->set_stock_quantity( '' );
1337
			$this->set_backorders( 'no' );
1338
			$this->set_low_stock_amount( '' );
1339 7
1340 7
			// If we are stock managing and we don't have stock, force out of stock status.
1341 View Code Duplication
		} elseif ( $this->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount', 0 ) && 'no' === $this->get_backorders() ) {
1342
			$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
		} elseif ( $this->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount', 0 ) && 'no' !== $this->get_backorders() ) {
1346
			$this->set_stock_status( 'onbackorder' );
1347
1348
			// If the stock level is changing and we do now have enough, force in stock status.
1349
		} elseif ( $this->get_stock_quantity() > get_option( 'woocommerce_notify_no_stock_amount', 0 ) ) {
1350 379
			$this->set_stock_status( 'instock' );
1351 379
		}
1352
	}
1353 379
1354
	/**
1355 379
	 * Save data (either create or update depending on if we are working on an existing product).
1356
	 *
1357 379
	 * @since  3.0.0
1358 92
	 * @return int
1359
	 */
1360 379 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
		$this->validate_props();
1362 379
1363 58
		if ( $this->data_store ) {
1364
			// Trigger action before saving to the DB. Use a pointer to adjust object props before save.
1365
			do_action( 'woocommerce_before_' . $this->object_type . '_object_save', $this, $this->data_store );
1366 379
1367
			if ( $this->get_id() ) {
1368
				$this->data_store->update( $this );
1369
			} else {
1370
				$this->data_store->create( $this );
1371
			}
1372
			if ( $this->get_parent_id() ) {
1373
				wc_deferred_product_sync( $this->get_parent_id() );
1374
			}
1375
		}
1376
		return $this->get_id();
1377
	}
1378
1379
	/*
1380
	|--------------------------------------------------------------------------
1381
	| Conditionals
1382
	|--------------------------------------------------------------------------
1383
	*/
1384
1385
	/**
1386
	 * Check if a product supports a given feature.
1387
	 *
1388
	 * Product classes should override this to declare support (or lack of support) for a feature.
1389
	 *
1390
	 * @param  string $feature string The name of a feature to test support for.
1391
	 * @return bool True if the product supports the feature, false otherwise.
1392
	 * @since  2.5.0
1393 124
	 */
1394 124
	public function supports( $feature ) {
1395
		return apply_filters( 'woocommerce_product_supports', in_array( $feature, $this->supports, true ), $feature, $this );
1396
	}
1397
1398
	/**
1399
	 * Returns whether or not the product post exists.
1400
	 *
1401
	 * @return bool
1402
	 */
1403
	public function exists() {
1404
		return false !== $this->get_status();
1405 384
	}
1406 384
1407
	/**
1408
	 * Checks the product type.
1409
	 *
1410
	 * Backwards compatibility with downloadable/virtual.
1411
	 *
1412
	 * @param  string|array $type Array or string of types.
1413
	 * @return bool
1414 57
	 */
1415 57
	public function is_type( $type ) {
1416
		return ( $this->get_type() === $type || ( is_array( $type ) && in_array( $this->get_type(), $type, true ) ) );
1417
	}
1418
1419
	/**
1420
	 * Checks if a product is downloadable.
1421
	 *
1422
	 * @return bool
1423 53
	 */
1424 53
	public function is_downloadable() {
1425
		return apply_filters( 'woocommerce_is_downloadable', true === $this->get_downloadable(), $this );
1426
	}
1427
1428
	/**
1429
	 * Checks if a product is virtual (has no shipping).
1430
	 *
1431
	 * @return bool
1432 20
	 */
1433 20
	public function is_virtual() {
1434
		return apply_filters( 'woocommerce_is_virtual', true === $this->get_virtual(), $this );
1435
	}
1436
1437
	/**
1438
	 * Returns whether or not the product is featured.
1439
	 *
1440
	 * @return bool
1441 99
	 */
1442 99
	public function is_featured() {
1443
		return true === $this->get_featured();
1444
	}
1445
1446
	/**
1447
	 * Check if a product is sold individually (no quantities).
1448
	 *
1449
	 * @return bool
1450 9
	 */
1451 9
	public function is_sold_individually() {
1452
		return apply_filters( 'woocommerce_is_sold_individually', true === $this->get_sold_individually(), $this );
1453 9
	}
1454
1455 9
	/**
1456
	 * Returns whether or not the product is visible in the catalog.
1457
	 *
1458
	 * @return bool
1459 9
	 */
1460 7
	public function is_visible() {
1461
		$visible = 'visible' === $this->get_catalog_visibility() || ( is_search() && 'search' === $this->get_catalog_visibility() ) || ( ! is_search() && 'catalog' === $this->get_catalog_visibility() );
1462 7
1463
		if ( 'trash' === $this->get_status() ) {
1464
			$visible = false;
1465
		} elseif ( 'publish' !== $this->get_status() && ! current_user_can( 'edit_post', $this->get_id() ) ) {
1466
			$visible = false;
1467 9
		}
1468
1469
		if ( $this->get_parent_id() ) {
1470
			$parent_product = wc_get_product( $this->get_parent_id() );
1471 9
1472
			if ( $parent_product && 'publish' !== $parent_product->get_status() ) {
1473
				$visible = false;
1474
			}
1475
		}
1476
1477
		if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && ! $this->is_in_stock() ) {
1478
			$visible = false;
1479 110
		}
1480 110
1481
		return apply_filters( 'woocommerce_product_is_visible', $visible, $this->get_id() );
1482
	}
1483
1484
	/**
1485
	 * Returns false if the product cannot be bought.
1486
	 *
1487
	 * @return bool
1488
	 */
1489 379
	public function is_purchasable() {
1490 379
		return apply_filters( 'woocommerce_is_purchasable', $this->exists() && ( 'publish' === $this->get_status() || current_user_can( 'edit_post', $this->get_id() ) ) && '' !== $this->get_price(), $this );
1491 17
	}
1492
1493 17
	/**
1494 1
	 * Returns whether or not the product is on sale.
1495
	 *
1496
	 * @param  string $context What the value is for. Valid values are view and edit.
1497 17
	 * @return bool
1498 17
	 */
1499
	public function is_on_sale( $context = 'view' ) {
1500
		if ( '' !== (string) $this->get_sale_price( $context ) && $this->get_regular_price( $context ) > $this->get_sale_price( $context ) ) {
1501 378
			$on_sale = true;
1502
1503 379
			if ( $this->get_date_on_sale_from( $context ) && $this->get_date_on_sale_from( $context )->getTimestamp() > current_time( 'timestamp', true ) ) {
1504
				$on_sale = false;
1505
			}
1506
1507
			if ( $this->get_date_on_sale_to( $context ) && $this->get_date_on_sale_to( $context )->getTimestamp() + DAY_IN_SECONDS < current_time( 'timestamp', true ) ) {
1508
				$on_sale = false;
1509
			}
1510
		} else {
1511
			$on_sale = false;
1512
		}
1513
		return 'view' === $context ? apply_filters( 'woocommerce_product_is_on_sale', $on_sale, $this ) : $on_sale;
1514
	}
1515
1516
	/**
1517
	 * Returns whether or not the product has dimensions set.
1518
	 *
1519
	 * @return bool
1520 1
	 */
1521 1
	public function has_dimensions() {
1522
		return ( $this->get_length() || $this->get_height() || $this->get_width() ) && ! $this->get_virtual();
1523
	}
1524
1525
	/**
1526
	 * Returns whether or not the product has weight set.
1527
	 *
1528
	 * @return bool
1529
	 */
1530 105
	public function has_weight() {
1531 105
		return $this->get_weight() && ! $this->get_virtual();
1532
	}
1533
1534
	/**
1535
	 * Returns whether or not the product can be purchased.
1536
	 * This returns true for 'instock' and 'onbackorder' stock statuses.
1537
	 *
1538
	 * @return bool
1539 36
	 */
1540 36
	public function is_in_stock() {
1541
		return apply_filters( 'woocommerce_product_is_in_stock', 'outofstock' !== $this->get_stock_status(), $this );
1542
	}
1543
1544
	/**
1545
	 * Checks if a product needs shipping.
1546
	 *
1547
	 * @return bool
1548 134
	 */
1549 134
	public function needs_shipping() {
1550
		return apply_filters( 'woocommerce_product_needs_shipping', ! $this->is_virtual(), $this );
1551
	}
1552
1553
	/**
1554
	 * Returns whether or not the product is taxable.
1555
	 *
1556
	 * @return bool
1557 25
	 */
1558 25
	public function is_taxable() {
1559
		return apply_filters( 'woocommerce_product_is_taxable', $this->get_tax_status() === 'taxable' && wc_tax_enabled(), $this );
1560
	}
1561
1562
	/**
1563
	 * Returns whether or not the product shipping is taxable.
1564
	 *
1565
	 * @return bool
1566 135
	 */
1567 135
	public function is_shipping_taxable() {
1568 135
		return $this->needs_shipping() && ( $this->get_tax_status() === 'taxable' || $this->get_tax_status() === 'shipping' );
1569
	}
1570
1571
	/**
1572
	 * Returns whether or not the product is stock managed.
1573
	 *
1574
	 * @return bool
1575
	 */
1576
	public function managing_stock() {
1577
		if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) {
1578 41
			return $this->get_manage_stock();
1579 41
		}
1580
		return false;
1581
	}
1582
1583
	/**
1584
	 * Returns whether or not the product can be backordered.
1585
	 *
1586
	 * @return bool
1587 8
	 */
1588 8
	public function backorders_allowed() {
1589
		return apply_filters( 'woocommerce_product_backorders_allowed', ( 'yes' === $this->get_backorders() || 'notify' === $this->get_backorders() ), $this->get_id(), $this );
1590
	}
1591
1592
	/**
1593
	 * Returns whether or not the product needs to notify the customer on backorder.
1594
	 *
1595
	 * @return bool
1596
	 */
1597 34
	public function backorders_require_notification() {
1598 34
		return apply_filters( 'woocommerce_product_backorders_require_notification', ( $this->managing_stock() && 'notify' === $this->get_backorders() ), $this );
1599
	}
1600
1601
	/**
1602 34
	 * Check if a product is on backorder.
1603
	 *
1604
	 * @param  int $qty_in_cart (default: 0).
1605
	 * @return bool
1606
	 */
1607
	public function is_on_backorder( $qty_in_cart = 0 ) {
1608
		if ( 'onbackorder' === $this->get_stock_status() ) {
1609
			return true;
1610
		}
1611 77
1612 77
		return $this->managing_stock() && $this->backorders_allowed() && ( $this->get_stock_quantity() - $qty_in_cart ) < 0;
1613
	}
1614
1615
	/**
1616
	 * Returns whether or not the product has enough stock for the order.
1617
	 *
1618
	 * @param  mixed $quantity Quantity of a product added to an order.
1619
	 * @return bool
1620
	 */
1621
	public function has_enough_stock( $quantity ) {
1622
		return ! $this->managing_stock() || $this->backorders_allowed() || $this->get_stock_quantity() >= $quantity;
1623
	}
1624
1625
	/**
1626
	 * Returns whether or not the product has any visible attributes.
1627
	 *
1628
	 * @return boolean
1629
	 */
1630
	public function has_attributes() {
1631
		foreach ( $this->get_attributes() as $attribute ) {
1632
			if ( $attribute->get_visible() ) {
1633
				return true;
1634 6
			}
1635 6
		}
1636
		return false;
1637
	}
1638
1639
	/**
1640
	 * Returns whether or not the product has any child product.
1641
	 *
1642
	 * @return bool
1643
	 */
1644
	public function has_child() {
1645
		return 0 < count( $this->get_children() );
1646
	}
1647
1648
	/**
1649
	 * Does a child have dimensions?
1650
	 *
1651
	 * @since  3.0.0
1652
	 * @return bool
1653
	 */
1654
	public function child_has_dimensions() {
1655
		return false;
1656
	}
1657
1658
	/**
1659
	 * Does a child have a weight?
1660
	 *
1661
	 * @since  3.0.0
1662
	 * @return boolean
1663
	 */
1664
	public function child_has_weight() {
1665
		return false;
1666 3
	}
1667 3
1668
	/**
1669
	 * Check if downloadable product has a file attached.
1670
	 *
1671
	 * @since 1.6.2
1672
	 *
1673
	 * @param  string $download_id file identifier.
1674
	 * @return bool Whether downloadable product has a file attached.
1675
	 */
1676
	public function has_file( $download_id = '' ) {
1677
		return $this->is_downloadable() && $this->get_file( $download_id );
1678
	}
1679
1680
	/**
1681
	 * Returns whether or not the product has additional options that need
1682
	 * selecting before adding to cart.
1683
	 *
1684
	 * @since  3.0.0
1685
	 * @return boolean
1686
	 */
1687
	public function has_options() {
1688
		return false;
1689
	}
1690
1691
	/*
1692
	|--------------------------------------------------------------------------
1693
	| Non-CRUD Getters
1694
	|--------------------------------------------------------------------------
1695
	*/
1696
1697
	/**
1698
	 * Get the product's title. For products this is the product name.
1699
	 *
1700
	 * @return string
1701 23
	 */
1702 23
	public function get_title() {
1703
		return apply_filters( 'woocommerce_product_title', $this->get_name(), $this );
1704
	}
1705
1706
	/**
1707
	 * Product permalink.
1708
	 *
1709
	 * @return string
1710 5
	 */
1711 5
	public function get_permalink() {
1712
		return get_permalink( $this->get_id() );
1713
	}
1714
1715
	/**
1716
	 * Returns the children IDs if applicable. Overridden by child classes.
1717
	 *
1718
	 * @return array of IDs
1719
	 */
1720 5
	public function get_children() {
1721 5
		return array();
1722
	}
1723
1724
	/**
1725
	 * If the stock level comes from another product ID, this should be modified.
1726
	 *
1727
	 * @since  3.0.0
1728
	 * @return int
1729
	 */
1730
	public function get_stock_managed_by_id() {
1731 26
		return $this->get_id();
1732 26
	}
1733 2
1734 24
	/**
1735 3
	 * Returns the price in html format.
1736
	 *
1737 24
	 * @param string $deprecated Deprecated param.
1738
	 *
1739
	 * @return string
1740 26
	 */
1741
	public function get_price_html( $deprecated = '' ) {
1742
		if ( '' === $this->get_price() ) {
1743
			$price = apply_filters( 'woocommerce_empty_price_html', '', $this );
1744
		} elseif ( $this->is_on_sale() ) {
1745
			$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();
1746
		} else {
1747
			$price = wc_price( wc_get_price_to_display( $this ) ) . $this->get_price_suffix();
1748
		}
1749
1750
		return apply_filters( 'woocommerce_get_price_html', $price, $this );
1751
	}
1752
1753
	/**
1754
	 * Get product name with SKU or ID. Used within admin.
1755
	 *
1756
	 * @return string Formatted product name
1757
	 */
1758
	public function get_formatted_name() {
1759
		if ( $this->get_sku() ) {
1760
			$identifier = $this->get_sku();
1761
		} else {
1762
			$identifier = '#' . $this->get_id();
1763 5
		}
1764 5
		return sprintf( '%2$s (%1$s)', $identifier, $this->get_name() );
1765
	}
1766
1767
	/**
1768
	 * Get min quantity which can be purchased at once.
1769
	 *
1770
	 * @since  3.0.0
1771
	 * @return int
1772
	 */
1773 5
	public function get_min_purchase_quantity() {
1774 5
		return 1;
1775
	}
1776
1777
	/**
1778
	 * Get max quantity which can be purchased at once.
1779
	 *
1780
	 * @since  3.0.0
1781
	 * @return int Quantity or -1 if unlimited.
1782
	 */
1783
	public function get_max_purchase_quantity() {
1784
		return $this->is_sold_individually() ? 1 : ( $this->backorders_allowed() || ! $this->managing_stock() ? -1 : $this->get_stock_quantity() );
1785
	}
1786
1787
	/**
1788
	 * Get the add to url used mainly in loops.
1789
	 *
1790
	 * @return string
1791 1
	 */
1792 1
	public function add_to_cart_url() {
1793
		return apply_filters( 'woocommerce_product_add_to_cart_url', $this->get_permalink(), $this );
1794
	}
1795
1796
	/**
1797
	 * Get the add to cart button text for the single page.
1798
	 *
1799
	 * @return string
1800
	 */
1801
	public function single_add_to_cart_text() {
1802
		return apply_filters( 'woocommerce_product_single_add_to_cart_text', __( 'Add to cart', 'woocommerce' ), $this );
1803
	}
1804
1805
	/**
1806
	 * Get the add to cart button text.
1807
	 *
1808
	 * @return string
1809
	 */
1810
	public function add_to_cart_text() {
1811
		return apply_filters( 'woocommerce_product_add_to_cart_text', __( 'Read more', 'woocommerce' ), $this );
1812
	}
1813
1814
	/**
1815
	 * Get the add to cart button text description - used in aria tags.
1816
	 *
1817
	 * @since  3.3.0
1818
	 * @return string
1819
	 */
1820
	public function add_to_cart_description() {
1821
		/* translators: %s: Product title */
1822
		return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( __( 'Read more about &ldquo;%s&rdquo;', 'woocommerce' ), $this->get_name() ), $this );
1823 4
	}
1824 4
1825 2
	/**
1826 3
	 * Returns the main product image.
1827 1
	 *
1828 1
	 * @param  string $size (default: 'woocommerce_thumbnail').
1829 2
	 * @param  array  $attr Image attributes.
1830 1
	 * @param  bool   $placeholder True to return $placeholder if no image is found, or false to return an empty string.
1831
	 * @return string
1832 1
	 */
1833
	public function get_image( $size = 'woocommerce_thumbnail', $attr = array(), $placeholder = true ) {
1834
		$image = '';
1835 4
		if ( $this->get_image_id() ) {
1836
			$image = wp_get_attachment_image( $this->get_image_id(), $size, false, $attr );
1837
		} elseif ( $this->get_parent_id() ) {
1838
			$parent_product = wc_get_product( $this->get_parent_id() );
1839
			if ( $parent_product ) {
1840
				$image = $parent_product->get_image( $size, $attr, $placeholder );
1841
			}
1842
		}
1843 43
1844 43
		if ( ! $image && $placeholder ) {
1845 3
			$image = wc_placeholder_img( $size );
1846
		}
1847 3
1848 3
		return apply_filters( 'woocommerce_product_get_image', $image, $this, $size, $attr, $placeholder, $image );
1849
	}
1850
1851 42
	/**
1852
	 * Returns the product shipping class SLUG.
1853
	 *
1854
	 * @return string
1855
	 */
1856
	public function get_shipping_class() {
1857
		if ( $class_id = $this->get_shipping_class_id() ) { // @phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found, WordPress.CodeAnalysis.AssignmentInCondition.Found
1858
			$term = get_term_by( 'id', $class_id, 'product_shipping_class' );
1859
1860
			if ( $term && ! is_wp_error( $term ) ) {
1861
				return $term->slug;
1862
			}
1863
		}
1864
		return '';
1865
	}
1866
1867
	/**
1868
	 * Returns a single product attribute as a string.
1869
	 *
1870
	 * @param  string $attribute to get.
1871
	 * @return string
1872
	 */
1873
	public function get_attribute( $attribute ) {
1874
		$attributes = $this->get_attributes();
1875
		$attribute  = sanitize_title( $attribute );
1876
1877
		if ( isset( $attributes[ $attribute ] ) ) {
1878
			$attribute_object = $attributes[ $attribute ];
1879
		} elseif ( isset( $attributes[ 'pa_' . $attribute ] ) ) {
1880 40
			$attribute_object = $attributes[ 'pa_' . $attribute ];
1881 40
		} else {
1882
			return '';
1883 40
		}
1884 40
		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() );
1885
	}
1886
1887
	/**
1888
	 * Get the total amount (COUNT) of ratings, or just the count for one rating e.g. number of 5 star ratings.
1889
	 *
1890
	 * @param  int $value Optional. Rating value to get the count for. By default returns the count of all rating values.
1891
	 * @return int
1892
	 */
1893
	public function get_rating_count( $value = null ) {
1894
		$counts = $this->get_rating_counts();
1895
1896
		if ( is_null( $value ) ) {
1897
			return array_sum( $counts );
1898 2
		} elseif ( isset( $counts[ $value ] ) ) {
1899 2
			return absint( $counts[ $value ] );
1900
		} else {
1901 2
			return 0;
1902 1
		}
1903 2
	}
1904 2
1905
	/**
1906
	 * Get a file by $download_id.
1907
	 *
1908
	 * @param  string $download_id file identifier.
1909 2
	 * @return array|false if not found
1910
	 */
1911
	public function get_file( $download_id = '' ) {
1912
		$files = $this->get_downloads();
1913
1914
		if ( '' === $download_id ) {
1915
			$file = count( $files ) ? current( $files ) : false;
1916
		} elseif ( isset( $files[ $download_id ] ) ) {
1917
			$file = $files[ $download_id ];
1918
		} else {
1919
			$file = false;
1920
		}
1921
1922
		return apply_filters( 'woocommerce_product_file', $file, $this, $download_id );
1923
	}
1924
1925
	/**
1926
	 * Get file download path identified by $download_id.
1927
	 *
1928
	 * @param  string $download_id file identifier.
1929
	 * @return string
1930
	 */
1931
	public function get_file_download_path( $download_id ) {
1932
		$files     = $this->get_downloads();
1933 24
		$file_path = isset( $files[ $download_id ] ) ? $files[ $download_id ]->get_file() : '';
1934 24
1935
		// allow overriding based on the particular file being requested.
1936 24
		return apply_filters( 'woocommerce_product_file_download_path', $file_path, $this, $download_id );
1937
	}
1938
1939
	/**
1940
	 * Get the suffix to display after prices > 0.
1941
	 *
1942
	 * @param  string  $price to calculate, left blank to just use get_price().
1943
	 * @param  integer $qty   passed on to get_price_including_tax() or get_price_excluding_tax().
1944
	 * @return string
1945
	 */
1946 24
	public function get_price_suffix( $price = '', $qty = 1 ) {
1947
		$html = '';
1948
1949
		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
1950
			if ( '' === $price ) {
1951
				$price = $this->get_price();
1952
			}
1953
			$replacements = array(
1954 5
				'{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
1955 5
				'{price_excluding_tax}' => wc_price( wc_get_price_excluding_tax( $this, array( 'qty' => $qty, 'price' => $price ) ) ), // @phpcs:ignore WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
1956 5
			);
1957 5
			$html         = str_replace( array_keys( $replacements ), array_values( $replacements ), ' <small class="woocommerce-price-suffix">' . wp_kses_post( $suffix ) . '</small>' );
1958 5
		}
1959
		return apply_filters( 'woocommerce_get_price_suffix', $html, $this, $price, $qty );
1960
	}
1961
1962
	/**
1963
	 * Returns the availability of the product.
1964
	 *
1965
	 * @return string[]
1966 5
	 */
1967 5
	public function get_availability() {
1968
		return apply_filters(
1969 5
			'woocommerce_get_availability',
1970
			array(
1971 5
				'availability' => $this->get_availability_text(),
1972
				'class'        => $this->get_availability_class(),
1973
			),
1974 5
			$this
1975
		);
1976 5
	}
1977
1978
	/**
1979
	 * Get availability text based on stock status.
1980
	 *
1981
	 * @return string
1982
	 */
1983
	protected function get_availability_text() {
1984 5
		if ( ! $this->is_in_stock() ) {
1985 5
			$availability = __( 'Out of stock', 'woocommerce' );
1986
		} elseif ( $this->managing_stock() && $this->is_on_backorder( 1 ) ) {
1987 5
			$availability = $this->backorders_require_notification() ? __( 'Available on backorder', 'woocommerce' ) : '';
1988
		} elseif ( $this->managing_stock() ) {
1989
			$availability = wc_format_stock_for_display( $this );
1990 5
		} else {
1991
			$availability = '';
1992 5
		}
1993
		return apply_filters( 'woocommerce_get_availability_text', $availability, $this );
1994
	}
1995
1996
	/**
1997
	 * Get availability classname based on stock status.
1998
	 *
1999
	 * @return string
2000
	 */
2001
	protected function get_availability_class() {
2002
		if ( ! $this->is_in_stock() ) {
2003
			$class = 'out-of-stock';
2004
		} elseif ( $this->managing_stock() && $this->is_on_backorder( 1 ) ) {
2005
			$class = 'available-on-backorder';
2006
		} else {
2007
			$class = 'in-stock';
2008
		}
2009
		return apply_filters( 'woocommerce_get_availability_class', $class, $this );
2010
	}
2011
}
2012