1 <?php
2 3 4 5 6 7 8 9 10 11 12
13 class WC_Product {
14
15
16 public $id;
17
18
19 public $post;
20
21
22 public $product_type = null;
23
24 25 26 27 28 29
30 public function __construct( $product ) {
31 if ( is_numeric( $product ) ) {
32 $this->id = absint( $product );
33 $this->post = get_post( $this->id );
34 } elseif ( $product instanceof WC_Product ) {
35 $this->id = absint( $product->id );
36 $this->post = $product;
37 } elseif ( $product instanceof WP_Post || isset( $product->ID ) ) {
38 $this->id = absint( $product->ID );
39 $this->post = $product;
40 }
41 }
42
43 44 45 46 47 48 49
50 public function __isset( $key ) {
51 return metadata_exists( 'post', $this->id, '_' . $key );
52 }
53
54 55 56 57 58 59 60
61 public function __get( $key ) {
62
63
64 if ( in_array( $key, array( 'downloadable', 'virtual', 'backorders', 'manage_stock', 'featured', 'sold_individually' ) ) ) {
65 $value = ( $value = get_post_meta( $this->id, '_' . $key, true ) ) ? $value : 'no';
66
67 } elseif ( in_array( $key, array( 'product_attributes', 'crosssell_ids', 'upsell_ids' ) ) ) {
68 $value = ( $value = get_post_meta( $this->id, '_' . $key, true ) ) ? $value : array();
69
70 } elseif ( 'visibility' == $key ) {
71 $value = ( $value = get_post_meta( $this->id, '_visibility', true ) ) ? $value : 'hidden';
72
73 } elseif ( 'stock' == $key ) {
74 $value = ( $value = get_post_meta( $this->id, '_stock', true ) ) ? $value : 0;
75
76 } elseif ( 'stock_status' == $key ) {
77 $value = ( $value = get_post_meta( $this->id, '_stock_status', true ) ) ? $value : 'instock';
78
79 } elseif ( 'tax_status' == $key ) {
80 $value = ( $value = get_post_meta( $this->id, '_tax_status', true ) ) ? $value : 'taxable';
81
82 } else {
83 $value = get_post_meta( $this->id, '_' . $key, true );
84 }
85
86 return $value;
87 }
88
89 90 91 92 93 94
95 public function get_post_data() {
96 return $this->post;
97 }
98
99 100 101 102 103 104
105 public function get_gallery_attachment_ids() {
106 if ( ! isset( $this->product_image_gallery ) ) {
107
108 $attachment_ids = get_posts( 'post_parent=' . $this->id . '&numberposts=-1&post_type=attachment&orderby=menu_order&order=ASC&post_mime_type=image&fields=ids&meta_key=_woocommerce_exclude_image&meta_value=0' );
109 $attachment_ids = array_diff( $attachment_ids, array( get_post_thumbnail_id() ) );
110 $this->product_image_gallery = implode( ',', $attachment_ids );
111 }
112 return apply_filters( 'woocommerce_product_gallery_attachment_ids', array_filter( (array) explode( ',', $this->product_image_gallery ) ), $this );
113 }
114
115 116 117 118
119 public function get_permalink() {
120 return get_permalink( $this->id );
121 }
122
123 124 125 126 127
128 public function get_sku() {
129 return $this->sku;
130 }
131
132 133 134 135 136 137
138 public function get_stock_quantity() {
139 return $this->managing_stock() ? apply_filters( 'woocommerce_stock_amount', $this->stock ) : '';
140 }
141
142 143 144 145 146 147
148 public function get_total_stock() {
149 return $this->get_stock_quantity();
150 }
151
152 153 154 155 156 157
158 public function set_stock( $amount = null ) {
159 if ( is_null( $amount ) ) {
160 return 0;
161 }
162
163 if ( $this->managing_stock() ) {
164
165
166 $this->stock = apply_filters( 'woocommerce_stock_amount', $amount );
167
168
169 update_post_meta( $this->id, '_stock', $this->stock );
170
171
172 if ( ! $this->backorders_allowed() && $this->get_total_stock() <= get_option( 'woocommerce_notify_no_stock_amount' ) ) {
173 $this->set_stock_status( 'outofstock' );
174
175 } elseif ( $this->backorders_allowed() || $this->get_total_stock() > get_option( 'woocommerce_notify_no_stock_amount' ) ) {
176 $this->set_stock_status( 'instock' );
177 }
178
179
180 delete_transient( 'wc_product_total_stock_' . $this->id );
181
182
183 do_action( 'woocommerce_product_set_stock', $this );
184
185 return $this->get_stock_quantity();
186 }
187
188 return 0;
189 }
190
191 192 193 194 195 196
197 public function reduce_stock( $by = 1 ) {
198 return $this->set_stock( $this->stock - $by );
199 }
200
201 202 203 204 205 206
207 public function increase_stock( $by = 1 ) {
208 return $this->set_stock( $this->stock + $by );
209 }
210
211 212 213 214 215 216
217 public function set_stock_status( $status ) {
218 $status = ( 'outofstock' === $status ) ? 'outofstock' : 'instock';
219
220 if ( update_post_meta( $this->id, '_stock_status', $status ) ) {
221 do_action( 'woocommerce_product_set_stock_status', $this->id, $status );
222 }
223 }
224
225 226 227 228 229 230 231 232 233
234 public function is_type( $type ) {
235 return ( $this->product_type == $type || ( is_array( $type ) && in_array( $this->product_type, $type ) ) ) ? true : false;
236 }
237
238 239 240 241 242 243
244 public function is_downloadable() {
245 return $this->downloadable == 'yes' ? true : false;
246 }
247
248 249 250 251 252 253 254 255 256
257 public function has_file( $download_id = '' ) {
258 return ( $this->is_downloadable() && $this->get_file( $download_id ) ) ? true : false;
259 }
260
261 262 263 264 265 266 267
268 public function get_files() {
269 $downloadable_files = array_filter( isset( $this->downloadable_files ) ? (array) maybe_unserialize( $this->downloadable_files ) : array() );
270
271 if ( $downloadable_files ) {
272 foreach ( $downloadable_files as $key => $file ) {
273 if ( ! is_array( $file ) ) {
274 $downloadable_files[ $key ] = array(
275 'file' => $file,
276 'name' => ''
277 );
278 }
279
280
281 if ( empty( $file['name'] ) ) {
282 $downloadable_files[ $key ]['name'] = wc_get_filename_from_url( $file['file'] );
283 }
284
285
286 $downloadable_files[ $key ]['file'] = apply_filters( 'woocommerce_file_download_path', $downloadable_files[ $key ]['file'], $this, $key );
287 }
288 }
289
290 return apply_filters( 'woocommerce_product_files', $downloadable_files, $this );
291 }
292
293 294 295 296 297 298
299 public function get_file( $download_id = '' ) {
300 $files = $this->get_files();
301
302 if ( '' === $download_id ) {
303 $file = sizeof( $files ) ? current( $files ) : false;
304 } elseif ( isset( $files[ $download_id ] ) ) {
305 $file = $files[ $download_id ];
306 } else {
307 $file = false;
308 }
309
310
311 return apply_filters( 'woocommerce_product_file', $file, $this, $download_id );
312 }
313
314 315 316 317 318 319
320 public function get_file_download_path( $download_id ) {
321 $files = $this->get_files();
322
323 if ( isset( $files[ $download_id ] ) ) {
324 $file_path = $files[ $download_id ]['file'];
325 } else {
326 $file_path = '';
327 }
328
329
330 return apply_filters( 'woocommerce_product_file_download_path', $file_path, $this, $download_id );
331 }
332
333 334 335 336 337 338
339 public function is_virtual() {
340 return $this->virtual == 'yes' ? true : false;
341 }
342
343 344 345 346 347 348
349 public function needs_shipping() {
350 return apply_filters( 'woocommerce_product_needs_shipping', $this->is_virtual() ? false : true, $this );
351 }
352
353 354 355 356 357 358
359 public function is_sold_individually() {
360 $return = false;
361
362 if ( 'yes' == $this->sold_individually || ( ! $this->backorders_allowed() && $this->get_stock_quantity() == 1 ) ) {
363 $return = true;
364 }
365
366 return apply_filters( 'woocommerce_is_sold_individually', $return, $this );
367 }
368
369 370 371 372 373 374
375 public function get_children() {
376 return array();
377 }
378
379 380 381 382 383 384
385 public function has_child() {
386 return false;
387 }
388
389 390 391 392 393 394
395 public function exists() {
396 return empty( $this->post ) ? false : true;
397 }
398
399 400 401 402 403 404
405 public function is_taxable() {
406 $taxable = $this->tax_status == 'taxable' && get_option( 'woocommerce_calc_taxes' ) == 'yes' ? true : false;
407 return apply_filters( 'woocommerce_product_is_taxable', $taxable, $this );
408 }
409
410 411 412 413 414 415
416 public function is_shipping_taxable() {
417 return $this->tax_status=='taxable' || $this->tax_status=='shipping' ? true : false;
418 }
419
420 421 422 423 424 425
426 public function get_title() {
427 return apply_filters( 'woocommerce_product_title', $this->post->post_title, $this );
428 }
429
430 431 432 433 434 435
436 public function get_parent() {
437 return apply_filters('woocommerce_product_parent', $this->post->post_parent, $this);
438 }
439
440 441 442 443 444 445
446 public function add_to_cart_url() {
447 return apply_filters( 'woocommerce_product_add_to_cart_url', get_permalink( $this->id ), $this );
448 }
449
450 451 452 453 454 455
456 public function single_add_to_cart_text() {
457 return apply_filters( 'woocommerce_product_single_add_to_cart_text', __( 'Add to cart', 'woocommerce' ), $this );
458 }
459
460 461 462 463 464 465
466 public function add_to_cart_text() {
467 return apply_filters( 'woocommerce_product_add_to_cart_text', __( 'Read more', 'woocommerce' ), $this );
468 }
469
470 471 472 473 474 475
476 public function managing_stock() {
477 return ( ! isset( $this->manage_stock ) || $this->manage_stock == 'no' || get_option( 'woocommerce_manage_stock' ) !== 'yes' ) ? false : true;
478 }
479
480 481 482 483 484 485
486 public function is_in_stock() {
487 if ( $this->managing_stock() ) {
488
489 if ( $this->backorders_allowed() ) {
490 return true;
491 } else {
492 if ( $this->get_total_stock() <= get_option( 'woocommerce_notify_no_stock_amount' ) ) {
493 return false;
494 } else {
495 if ( $this->stock_status === 'instock' ) {
496 return true;
497 } else {
498 return false;
499 }
500 }
501 }
502
503 } else {
504
505 if ( $this->stock_status === 'instock' ) {
506 return true;
507 } else {
508 return false;
509 }
510
511 }
512 }
513
514 515 516 517 518 519
520 public function backorders_allowed() {
521 return $this->backorders === 'yes' || $this->backorders === 'notify' ? true : false;
522 }
523
524 525 526 527 528 529
530 public function backorders_require_notification() {
531 return $this->managing_stock() && $this->backorders === 'notify' ? true : false;
532 }
533
534 535 536 537 538 539 540
541 public function is_on_backorder( $qty_in_cart = 0 ) {
542 return $this->managing_stock() && $this->backorders_allowed() && ( $this->get_total_stock() - $qty_in_cart ) < 0 ? true : false;
543 }
544
545 546 547 548 549 550 551
552 public function has_enough_stock( $quantity ) {
553 return ! $this->managing_stock() || $this->backorders_allowed() || $this->stock >= $quantity ? true : false;
554 }
555
556 557 558 559 560 561
562 public function get_availability() {
563
564 $availability = $class = "";
565
566 if ( $this->managing_stock() ) {
567 if ( $this->is_in_stock() ) {
568
569 if ( $this->get_total_stock() > get_option( 'woocommerce_notify_no_stock_amount' ) ) {
570
571 $format_option = get_option( 'woocommerce_stock_format' );
572
573 switch ( $format_option ) {
574 case 'no_amount' :
575 $format = __( 'In stock', 'woocommerce' );
576 break;
577 case 'low_amount' :
578 $low_amount = get_option( 'woocommerce_notify_low_stock_amount' );
579
580 $format = ( $this->get_total_stock() <= $low_amount ) ? __( 'Only %s left in stock', 'woocommerce' ) : __( 'In stock', 'woocommerce' );
581 break;
582 default :
583 $format = __( '%s in stock', 'woocommerce' );
584 break;
585 }
586
587 $availability = sprintf( $format, $this->stock );
588
589 if ( $this->backorders_allowed() && $this->backorders_require_notification() ) {
590 $availability .= ' ' . __( '(backorders allowed)', 'woocommerce' );
591 }
592
593 } else {
594
595 if ( $this->backorders_allowed() ) {
596 if ( $this->backorders_require_notification() ) {
597 $availability = __( 'Available on backorder', 'woocommerce' );
598 $class = 'available-on-backorder';
599 } else {
600 $availability = __( 'In stock', 'woocommerce' );
601 }
602 } else {
603 $availability = __( 'Out of stock', 'woocommerce' );
604 $class = 'out-of-stock';
605 }
606
607 }
608
609 } elseif ( $this->backorders_allowed() ) {
610 $availability = __( 'Available on backorder', 'woocommerce' );
611 $class = 'available-on-backorder';
612 } else {
613 $availability = __( 'Out of stock', 'woocommerce' );
614 $class = 'out-of-stock';
615 }
616 } elseif ( ! $this->is_in_stock() ) {
617 $availability = __( 'Out of stock', 'woocommerce' );
618 $class = 'out-of-stock';
619 }
620
621 return apply_filters( 'woocommerce_get_availability', array( 'availability' => $availability, 'class' => $class ), $this );
622 }
623
624 625 626 627 628 629
630 public function is_featured() {
631 return $this->featured === 'yes' ? true : false;
632 }
633
634 635 636 637 638 639
640 public function is_visible() {
641
642 $visible = true;
643
644
645 if ( get_option( 'woocommerce_hide_out_of_stock_items' ) === 'yes' && ! $this->is_in_stock() ) {
646 $visible = false;
647
648
649 } elseif ( $this->visibility === 'hidden' ) {
650 $visible = false;
651 } elseif ( $this->visibility === 'visible' ) {
652 $visible = true;
653
654
655 } elseif ( $this->visibility === 'search' && is_search() ) {
656 $visible = true;
657 } elseif ( $this->visibility === 'search' && ! is_search() ) {
658 $visible = false;
659 } elseif ( $this->visibility === 'catalog' && is_search() ) {
660 $visible = false;
661 } elseif ( $this->visibility === 'catalog' && ! is_search() ) {
662 $visible = true;
663 }
664
665 return apply_filters( 'woocommerce_product_is_visible', $visible, $this->id );
666 }
667
668 669 670 671 672 673
674 public function is_on_sale() {
675 return ( $this->get_sale_price() != $this->get_regular_price() && $this->get_sale_price() == $this->get_price() );
676 }
677
678 679 680 681 682 683
684 public function get_weight() {
685 return ( $this->weight ) ? $this->weight : '';
686 }
687
688 689 690 691 692 693
694 public function is_purchasable() {
695
696 $purchasable = true;
697
698
699 if ( ! $this->exists() ) {
700 $purchasable = false;
701
702
703 } elseif ( $this->get_price() === '' ) {
704 $purchasable = false;
705
706
707 } elseif ( $this->post->post_status !== 'publish' && ! current_user_can( 'edit_post', $this->id ) ) {
708 $purchasable = false;
709 }
710
711 return apply_filters( 'woocommerce_is_purchasable', $purchasable, $this );
712 }
713
714 715 716 717 718 719 720
721 public function set_price( $price ) {
722 $this->price = $price;
723 }
724
725 726 727 728 729 730 731
732 public function adjust_price( $price ) {
733 $this->price = $this->price + $price;
734 }
735
736 737 738 739 740
741 public function get_sale_price() {
742 return apply_filters( 'woocommerce_get_sale_price', $this->sale_price, $this );
743 }
744
745 746 747 748 749
750 public function get_regular_price() {
751 return apply_filters( 'woocommerce_get_regular_price', $this->regular_price, $this );
752 }
753
754 755 756 757 758
759 public function get_price() {
760 return apply_filters( 'woocommerce_get_price', $this->price, $this );
761 }
762
763 764 765 766 767 768 769
770 public function get_price_including_tax( $qty = 1, $price = '' ) {
771 $_tax = new WC_Tax();
772
773 if ( ! $price ) {
774 $price = $this->get_price();
775 }
776
777 if ( $this->is_taxable() ) {
778
779 if ( get_option('woocommerce_prices_include_tax') === 'no' ) {
780
781 $tax_rates = $_tax->get_rates( $this->get_tax_class() );
782 $taxes = $_tax->calc_tax( $price * $qty, $tax_rates, false );
783 $tax_amount = $_tax->get_tax_total( $taxes );
784 $price = round( $price * $qty + $tax_amount, absint( get_option( 'woocommerce_price_num_decimals' ) ) );
785
786 } else {
787
788 $tax_rates = $_tax->get_rates( $this->get_tax_class() );
789 $base_tax_rates = $_tax->get_shop_base_rate( $this->tax_class );
790
791 if ( ! empty( WC()->customer ) && WC()->customer->is_vat_exempt() ) {
792
793 $base_taxes = $_tax->calc_tax( $price * $qty, $base_tax_rates, true );
794 $base_tax_amount = array_sum( $base_taxes );
795 $price = round( $price * $qty - $base_tax_amount, absint( get_option( 'woocommerce_price_num_decimals' ) ) );
796
797 } elseif ( $tax_rates !== $base_tax_rates ) {
798
799 $base_taxes = $_tax->calc_tax( $price * $qty, $base_tax_rates, true );
800 $modded_taxes = $_tax->calc_tax( ( $price * $qty ) - array_sum( $base_taxes ), $tax_rates, false );
801 $price = round( ( $price * $qty ) - array_sum( $base_taxes ) + array_sum( $modded_taxes ), absint( get_option( 'woocommerce_price_num_decimals' ) ) );
802
803 } else {
804
805 $price = $price * $qty;
806
807 }
808
809 }
810
811 } else {
812 $price = $price * $qty;
813 }
814
815 return apply_filters( 'woocommerce_get_price_including_tax', $price, $qty, $this );
816 }
817
818 819 820 821 822 823 824 825
826 public function get_price_excluding_tax( $qty = 1, $price = '' ) {
827
828 if ( ! $price ) {
829 $price = $this->get_price();
830 }
831
832 if ( $this->is_taxable() && get_option('woocommerce_prices_include_tax') === 'yes' ) {
833
834 $_tax = new WC_Tax();
835 $tax_rates = $_tax->get_shop_base_rate( $this->tax_class );
836 $taxes = $_tax->calc_tax( $price * $qty, $tax_rates, true );
837 $price = $_tax->round( $price * $qty - array_sum( $taxes ) );
838
839 } else {
840 $price = $price * $qty;
841 }
842
843 return apply_filters( 'woocommerce_get_price_excluding_tax', $price, $qty, $this );
844 }
845
846 847 848 849
850 public function get_price_suffix() {
851 $price_display_suffix = get_option( 'woocommerce_price_display_suffix' );
852
853 if ( $price_display_suffix ) {
854 $price_display_suffix = ' <small class="woocommerce-price-suffix">' . $price_display_suffix . '</small>';
855
856 $find = array(
857 '{price_including_tax}',
858 '{price_excluding_tax}'
859 );
860
861 $replace = array(
862 wc_price( $this->get_price_including_tax() ),
863 wc_price( $this->get_price_excluding_tax() )
864 );
865
866 $price_display_suffix = str_replace( $find, $replace, $price_display_suffix );
867 }
868
869 return apply_filters( 'woocommerce_get_price_suffix', $price_display_suffix, $this );
870 }
871
872 873 874 875 876 877 878
879 public function get_price_html( $price = '' ) {
880
881 $tax_display_mode = get_option( 'woocommerce_tax_display_shop' );
882 $display_price = $tax_display_mode == 'incl' ? $this->get_price_including_tax() : $this->get_price_excluding_tax();
883 $display_regular_price = $tax_display_mode == 'incl' ? $this->get_price_including_tax( 1, $this->get_regular_price() ) : $this->get_price_excluding_tax( 1, $this->get_regular_price() );
884 $display_sale_price = $tax_display_mode == 'incl' ? $this->get_price_including_tax( 1, $this->get_sale_price() ) : $this->get_price_excluding_tax( 1, $this->get_sale_price() );
885
886 if ( $this->get_price() > 0 ) {
887
888 if ( $this->is_on_sale() && $this->get_regular_price() ) {
889
890 $price .= $this->get_price_html_from_to( $display_regular_price, $display_price ) . $this->get_price_suffix();
891
892 $price = apply_filters( 'woocommerce_sale_price_html', $price, $this );
893
894 } else {
895
896 $price .= wc_price( $display_price ) . $this->get_price_suffix();
897
898 $price = apply_filters( 'woocommerce_price_html', $price, $this );
899
900 }
901
902 } elseif ( $this->get_price() === '' ) {
903
904 $price = apply_filters( 'woocommerce_empty_price_html', '', $this );
905
906 } elseif ( $this->get_price() == 0 ) {
907
908 if ( $this->is_on_sale() && $this->get_regular_price() ) {
909
910 $price .= $this->get_price_html_from_to( $display_regular_price, __( 'Free!', 'woocommerce' ) );
911
912 $price = apply_filters( 'woocommerce_free_sale_price_html', $price, $this );
913
914 } else {
915
916 $price = __( 'Free!', 'woocommerce' );
917
918 $price = apply_filters( 'woocommerce_free_price_html', $price, $this );
919
920 }
921 }
922
923 return apply_filters( 'woocommerce_get_price_html', $price, $this );
924 }
925
926 927 928 929 930
931 public function get_price_html_from_text() {
932 return '<span class="from">' . _x( 'From:', 'min_price', 'woocommerce' ) . ' </span>';
933 }
934
935 936 937 938 939 940 941
942 public function get_price_html_from_to( $from, $to ) {
943 return '<del>' . ( ( is_numeric( $from ) ) ? wc_price( $from ) : $from ) . '</del> <ins>' . ( ( is_numeric( $to ) ) ? wc_price( $to ) : $to ) . '</ins>';
944 }
945
946 947 948 949 950 951
952 public function get_tax_class() {
953 return apply_filters( 'woocommerce_product_tax_class', $this->tax_class, $this );
954 }
955
956 957 958 959 960 961
962 public function get_tax_status() {
963 return $this->tax_status;
964 }
965
966 967 968 969 970 971
972 public function get_average_rating() {
973 if ( false === ( $average_rating = get_transient( 'wc_average_rating_' . $this->id ) ) ) {
974
975 global $wpdb;
976
977 $average_rating = '';
978 $count = $this->get_rating_count();
979
980 if ( $count > 0 ) {
981
982 $ratings = $wpdb->get_var( $wpdb->prepare("
983 SELECT SUM(meta_value) FROM $wpdb->commentmeta
984 LEFT JOIN $wpdb->comments ON $wpdb->commentmeta.comment_id = $wpdb->comments.comment_ID
985 WHERE meta_key = 'rating'
986 AND comment_post_ID = %d
987 AND comment_approved = '1'
988 AND meta_value > 0
989 ", $this->id ) );
990
991 $average_rating = number_format( $ratings / $count, 2 );
992
993 }
994
995 set_transient( 'wc_average_rating_' . $this->id, $average_rating, YEAR_IN_SECONDS );
996 }
997
998 return $average_rating;
999 }
1000
1001 1002 1003 1004 1005 1006
1007 public function get_rating_count() {
1008 if ( false === ( $count = get_transient( 'wc_rating_count_' . $this->id ) ) ) {
1009
1010 global $wpdb;
1011
1012 $count = $wpdb->get_var( $wpdb->prepare("
1013 SELECT COUNT(meta_value) FROM $wpdb->commentmeta
1014 LEFT JOIN $wpdb->comments ON $wpdb->commentmeta.comment_id = $wpdb->comments.comment_ID
1015 WHERE meta_key = 'rating'
1016 AND comment_post_ID = %d
1017 AND comment_approved = '1'
1018 AND meta_value > 0
1019 ", $this->id ) );
1020
1021 set_transient( 'wc_rating_count_' . $this->id, $count, YEAR_IN_SECONDS );
1022 }
1023
1024 return $count;
1025 }
1026
1027 1028 1029 1030 1031 1032 1033
1034 public function get_rating_html( $rating = null ) {
1035
1036 if ( ! is_numeric( $rating ) ) {
1037 $rating = $this->get_average_rating();
1038 }
1039
1040 if ( $rating > 0 ) {
1041
1042 $rating_html = '<div class="star-rating" title="' . sprintf( __( 'Rated %s out of 5', 'woocommerce' ), $rating ) . '">';
1043
1044 $rating_html .= '<span style="width:' . ( ( $rating / 5 ) * 100 ) . '%"><strong class="rating">' . $rating . '</strong> ' . __( 'out of 5', 'woocommerce' ) . '</span>';
1045
1046 $rating_html .= '</div>';
1047
1048 return $rating_html;
1049 }
1050
1051 return '';
1052 }
1053
1054
1055 1056 1057 1058 1059 1060
1061 public function get_upsells() {
1062 return (array) maybe_unserialize( $this->upsell_ids );
1063 }
1064
1065 1066 1067 1068 1069 1070
1071 public function get_cross_sells() {
1072 return (array) maybe_unserialize( $this->crosssell_ids );
1073 }
1074
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
1085 public function get_categories( $sep = ', ', $before = '', $after = '' ) {
1086 return get_the_term_list( $this->id, 'product_cat', $before, $sep, $after );
1087 }
1088
1089 1090 1091 1092 1093 1094 1095 1096 1097
1098 public function get_tags( $sep = ', ', $before = '', $after = '' ) {
1099 return get_the_term_list( $this->id, 'product_tag', $before, $sep, $after );
1100 }
1101
1102 1103 1104 1105 1106 1107
1108 public function get_shipping_class() {
1109 if ( ! $this->shipping_class ) {
1110 $classes = get_the_terms( $this->id, 'product_shipping_class' );
1111
1112 if ( $classes && ! is_wp_error( $classes ) ) {
1113 $this->shipping_class = current( $classes )->slug;
1114 } else {
1115 $this->shipping_class = '';
1116 }
1117
1118 }
1119 return $this->shipping_class;
1120 }
1121
1122 1123 1124 1125 1126 1127
1128 public function get_shipping_class_id() {
1129 if ( ! $this->shipping_class_id ) {
1130 $classes = get_the_terms( $this->id, 'product_shipping_class' );
1131
1132 if ( $classes && ! is_wp_error( $classes ) ) {
1133 $this->shipping_class_id = current( $classes )->term_id;
1134 } else {
1135 $this->shipping_class_id = 0;
1136 }
1137 }
1138 return absint( $this->shipping_class_id );
1139 }
1140
1141 1142 1143 1144 1145 1146 1147
1148 public function get_related( $limit = 5 ) {
1149 global $wpdb;
1150
1151
1152 $tags_array = array(0);
1153 $cats_array = array(0);
1154
1155
1156 $terms = wp_get_post_terms( $this->id, 'product_tag' );
1157 foreach ( $terms as $term ) {
1158 $tags_array[] = $term->term_id;
1159 }
1160
1161
1162 $terms = wp_get_post_terms( $this->id, 'product_cat' );
1163 foreach ( $terms as $term ) {
1164 $cats_array[] = $term->term_id;
1165 }
1166
1167
1168 if ( sizeof( $cats_array ) == 1 && sizeof( $tags_array ) == 1 ) {
1169 return array();
1170 }
1171
1172
1173 $cats_array = array_map( 'absint', $cats_array );
1174 $tags_array = array_map( 'absint', $tags_array );
1175 $exclude_ids = array_map( 'absint', array_merge( array( 0, $this->id ), $this->get_upsells() ) );
1176
1177
1178 $query['fields'] = "SELECT DISTINCT ID FROM {$wpdb->posts} p";
1179 $query['join'] = " INNER JOIN {$wpdb->postmeta} pm ON ( pm.post_id = p.ID AND pm.meta_key='_visibility' )";
1180 $query['join'] .= " INNER JOIN {$wpdb->term_relationships} tr ON (p.ID = tr.object_id)";
1181 $query['join'] .= " INNER JOIN {$wpdb->term_taxonomy} tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id)";
1182 $query['join'] .= " INNER JOIN {$wpdb->terms} t ON (t.term_id = tt.term_id)";
1183
1184 if ( get_option( 'woocommerce_hide_out_of_stock_items' ) === 'yes' ) {
1185 $query['join'] .= " INNER JOIN {$wpdb->postmeta} pm2 ON ( pm2.post_id = p.ID AND pm2.meta_key='_stock_status' )";
1186 }
1187
1188 $query['where'] = " WHERE 1=1";
1189 $query['where'] .= " AND p.post_status = 'publish'";
1190 $query['where'] .= " AND p.post_type = 'product'";
1191 $query['where'] .= " AND p.ID NOT IN ( " . implode( ',', $exclude_ids ) . " )";
1192 $query['where'] .= " AND pm.meta_value IN ( 'visible', 'catalog' )";
1193
1194 if ( get_option( 'woocommerce_hide_out_of_stock_items' ) === 'yes' ) {
1195 $query['where'] .= " AND pm2.meta_value = 'instock'";
1196 }
1197
1198 if ( apply_filters( 'woocommerce_product_related_posts_relate_by_category', true ) ) {
1199 $query['where'] .= " AND ( tt.taxonomy = 'product_cat' AND t.term_id IN ( " . implode( ',', $cats_array ) . " ) )";
1200 $andor = 'OR';
1201 } else {
1202 $andor = 'AND';
1203 }
1204
1205
1206 if ( apply_filters( 'woocommerce_product_related_posts_relate_by_tag', true ) ) {
1207 $query['where'] .= " {$andor} ( tt.taxonomy = 'product_tag' AND t.term_id IN ( " . implode( ',', $tags_array ) . " ) )";
1208 $query['where'] .= " AND p.ID NOT IN ( " . implode( ',', $exclude_ids ) . " )";
1209 }
1210
1211 $query['orderby'] = " ORDER BY RAND()";
1212 $query['limits'] = " LIMIT " . absint( $limit ) . " ";
1213
1214
1215 $related_posts = $wpdb->get_col( implode( ' ', apply_filters( 'woocommerce_product_related_posts_query', $query ) ) );
1216
1217 return $related_posts;
1218 }
1219
1220 1221 1222 1223 1224 1225 1226
1227 public function get_attribute( $attr ) {
1228 $attributes = $this->get_attributes();
1229
1230 $attr = sanitize_title( $attr );
1231
1232 if ( isset( $attributes[ $attr ] ) || isset( $attributes[ 'pa_' . $attr ] ) ) {
1233
1234 $attribute = isset( $attributes[ $attr ] ) ? $attributes[ $attr ] : $attributes[ 'pa_' . $attr ];
1235
1236 if ( $attribute['is_taxonomy'] ) {
1237
1238 return implode( ', ', wc_get_product_terms( $this->id, $attribute['name'], array( 'fields' => 'names' ) ) );
1239
1240 } else {
1241
1242 return $attribute['value'];
1243
1244 }
1245
1246 }
1247
1248 return '';
1249 }
1250
1251 1252 1253 1254 1255 1256
1257 public function get_attributes() {
1258 return (array) maybe_unserialize( $this->product_attributes );
1259 }
1260
1261 1262 1263 1264 1265 1266
1267 public function has_attributes() {
1268 if ( sizeof( $this->get_attributes() ) > 0 ) {
1269 foreach ( $this->get_attributes() as $attribute ) {
1270 if ( isset( $attribute['is_visible'] ) && $attribute['is_visible'] ) {
1271 return true;
1272 }
1273 }
1274 }
1275 return false;
1276 }
1277
1278 1279 1280 1281 1282 1283
1284 public function enable_dimensions_display() {
1285 return apply_filters( 'wc_product_enable_dimensions_display', true );
1286 }
1287
1288 1289 1290 1291 1292 1293
1294 public function has_dimensions() {
1295 return $this->get_dimensions() ? true : false;
1296 }
1297
1298 1299 1300 1301 1302 1303
1304 public function has_weight() {
1305 return $this->get_weight() ? true : false;
1306 }
1307
1308 1309 1310 1311 1312 1313
1314 public function get_dimensions() {
1315 if ( ! $this->dimensions ) {
1316 $dimensions = array();
1317
1318 if ( $this->length ) {
1319 $dimensions[] = $this->length;
1320 }
1321
1322 if ( $this->width ) {
1323 $dimensions[] = $this->width;
1324 }
1325
1326 if ( $this->height ){
1327 $dimensions[] = $this->height;
1328 }
1329
1330 $this->dimensions = implode( ' x ', $dimensions );
1331
1332 if ( ! empty( $this->dimensions ) ) {
1333 $this->dimensions .= ' ' . get_option( 'woocommerce_dimension_unit' );
1334 }
1335
1336 }
1337 return $this->dimensions;
1338 }
1339
1340 1341 1342 1343 1344 1345
1346 public function list_attributes() {
1347 wc_get_template( 'single-product/product-attributes.php', array(
1348 'product' => $this
1349 ) );
1350 }
1351
1352 1353 1354 1355
1356 public function get_image_id() {
1357 if ( has_post_thumbnail( $this->id ) ) {
1358 $image_id = get_post_thumbnail_id( $this->id );
1359 } elseif ( ( $parent_id = wp_get_post_parent_id( $this->id ) ) && has_post_thumbnail( $parent_id ) ) {
1360 $image_id = get_post_thumbnail_id( $parent_id );
1361 } else {
1362 $image_id = 0;
1363 }
1364 return $image_id;
1365 }
1366
1367 1368 1369 1370 1371 1372 1373
1374 public function get_image( $size = 'shop_thumbnail', $attr = array() ) {
1375 $image = '';
1376
1377 if ( has_post_thumbnail( $this->id ) ) {
1378 $image = get_the_post_thumbnail( $this->id, $size, $attr );
1379 } elseif ( ( $parent_id = wp_get_post_parent_id( $this->id ) ) && has_post_thumbnail( $parent_id ) ) {
1380 $image = get_the_post_thumbnail( $parent_id, $size, $attr );
1381 } else {
1382 $image = wc_placeholder_img( $size );
1383 }
1384
1385 return $image;
1386 }
1387
1388 1389 1390 1391 1392 1393 1394
1395 public function get_formatted_name() {
1396
1397 if ( $this->get_sku() ) {
1398 $identifier = $this->get_sku();
1399 } else {
1400 $identifier = '#' . $this->id;
1401 }
1402
1403 return sprintf( __( '%s – %s', 'woocommerce' ), $identifier, $this->get_title() );
1404 }
1405 }
1406