class-wc-widget-products.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <?php
  2. /**
  3. * List products. One widget to rule them all.
  4. *
  5. * @package WooCommerce/Widgets
  6. * @version 3.3.0
  7. */
  8. defined( 'ABSPATH' ) || exit;
  9. /**
  10. * Widget products.
  11. */
  12. class WC_Widget_Products extends WC_Widget {
  13. /**
  14. * Constructor.
  15. */
  16. public function __construct() {
  17. $this->widget_cssclass = 'woocommerce widget_products';
  18. $this->widget_description = __( "A list of your store's products.", 'woocommerce' );
  19. $this->widget_id = 'woocommerce_products';
  20. $this->widget_name = __( 'Products', 'woocommerce' );
  21. $this->settings = array(
  22. 'title' => array(
  23. 'type' => 'text',
  24. 'std' => __( 'Products', 'woocommerce' ),
  25. 'label' => __( 'Title', 'woocommerce' ),
  26. ),
  27. 'number' => array(
  28. 'type' => 'number',
  29. 'step' => 1,
  30. 'min' => 1,
  31. 'max' => '',
  32. 'std' => 5,
  33. 'label' => __( 'Number of products to show', 'woocommerce' ),
  34. ),
  35. 'show' => array(
  36. 'type' => 'select',
  37. 'std' => '',
  38. 'label' => __( 'Show', 'woocommerce' ),
  39. 'options' => array(
  40. '' => __( 'All products', 'woocommerce' ),
  41. 'featured' => __( 'Featured products', 'woocommerce' ),
  42. 'onsale' => __( 'On-sale products', 'woocommerce' ),
  43. ),
  44. ),
  45. 'orderby' => array(
  46. 'type' => 'select',
  47. 'std' => 'date',
  48. 'label' => __( 'Order by', 'woocommerce' ),
  49. 'options' => array(
  50. 'date' => __( 'Date', 'woocommerce' ),
  51. 'price' => __( 'Price', 'woocommerce' ),
  52. 'rand' => __( 'Random', 'woocommerce' ),
  53. 'sales' => __( 'Sales', 'woocommerce' ),
  54. ),
  55. ),
  56. 'order' => array(
  57. 'type' => 'select',
  58. 'std' => 'desc',
  59. 'label' => _x( 'Order', 'Sorting order', 'woocommerce' ),
  60. 'options' => array(
  61. 'asc' => __( 'ASC', 'woocommerce' ),
  62. 'desc' => __( 'DESC', 'woocommerce' ),
  63. ),
  64. ),
  65. 'hide_free' => array(
  66. 'type' => 'checkbox',
  67. 'std' => 0,
  68. 'label' => __( 'Hide free products', 'woocommerce' ),
  69. ),
  70. 'show_hidden' => array(
  71. 'type' => 'checkbox',
  72. 'std' => 0,
  73. 'label' => __( 'Show hidden products', 'woocommerce' ),
  74. ),
  75. );
  76. parent::__construct();
  77. }
  78. /**
  79. * Query the products and return them.
  80. *
  81. * @param array $args Arguments.
  82. * @param array $instance Widget instance.
  83. * @return WP_Query
  84. */
  85. public function get_products( $args, $instance ) {
  86. $number = ! empty( $instance['number'] ) ? absint( $instance['number'] ) : $this->settings['number']['std'];
  87. $show = ! empty( $instance['show'] ) ? sanitize_title( $instance['show'] ) : $this->settings['show']['std'];
  88. $orderby = ! empty( $instance['orderby'] ) ? sanitize_title( $instance['orderby'] ) : $this->settings['orderby']['std'];
  89. $order = ! empty( $instance['order'] ) ? sanitize_title( $instance['order'] ) : $this->settings['order']['std'];
  90. $product_visibility_term_ids = wc_get_product_visibility_term_ids();
  91. $query_args = array(
  92. 'posts_per_page' => $number,
  93. 'post_status' => 'publish',
  94. 'post_type' => 'product',
  95. 'no_found_rows' => 1,
  96. 'order' => $order,
  97. 'meta_query' => array(),
  98. 'tax_query' => array(
  99. 'relation' => 'AND',
  100. ),
  101. ); // WPCS: slow query ok.
  102. if ( empty( $instance['show_hidden'] ) ) {
  103. $query_args['tax_query'][] = array(
  104. 'taxonomy' => 'product_visibility',
  105. 'field' => 'term_taxonomy_id',
  106. 'terms' => is_search() ? $product_visibility_term_ids['exclude-from-search'] : $product_visibility_term_ids['exclude-from-catalog'],
  107. 'operator' => 'NOT IN',
  108. );
  109. $query_args['post_parent'] = 0;
  110. }
  111. if ( ! empty( $instance['hide_free'] ) ) {
  112. $query_args['meta_query'][] = array(
  113. 'key' => '_price',
  114. 'value' => 0,
  115. 'compare' => '>',
  116. 'type' => 'DECIMAL',
  117. );
  118. }
  119. if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
  120. $query_args['tax_query'] = array(
  121. array(
  122. 'taxonomy' => 'product_visibility',
  123. 'field' => 'term_taxonomy_id',
  124. 'terms' => $product_visibility_term_ids['outofstock'],
  125. 'operator' => 'NOT IN',
  126. ),
  127. ); // WPCS: slow query ok.
  128. }
  129. switch ( $show ) {
  130. case 'featured':
  131. $query_args['tax_query'][] = array(
  132. 'taxonomy' => 'product_visibility',
  133. 'field' => 'term_taxonomy_id',
  134. 'terms' => $product_visibility_term_ids['featured'],
  135. );
  136. break;
  137. case 'onsale':
  138. $product_ids_on_sale = wc_get_product_ids_on_sale();
  139. $product_ids_on_sale[] = 0;
  140. $query_args['post__in'] = $product_ids_on_sale;
  141. break;
  142. }
  143. switch ( $orderby ) {
  144. case 'price':
  145. $query_args['meta_key'] = '_price'; // WPCS: slow query ok.
  146. $query_args['orderby'] = 'meta_value_num';
  147. break;
  148. case 'rand':
  149. $query_args['orderby'] = 'rand';
  150. break;
  151. case 'sales':
  152. $query_args['meta_key'] = 'total_sales'; // WPCS: slow query ok.
  153. $query_args['orderby'] = 'meta_value_num';
  154. break;
  155. default:
  156. $query_args['orderby'] = 'date';
  157. }
  158. return new WP_Query( apply_filters( 'woocommerce_products_widget_query_args', $query_args ) );
  159. }
  160. /**
  161. * Output widget.
  162. *
  163. * @see WP_Widget
  164. *
  165. * @param array $args Arguments.
  166. * @param array $instance Widget instance.
  167. */
  168. public function widget( $args, $instance ) {
  169. if ( $this->get_cached_widget( $args ) ) {
  170. return;
  171. }
  172. ob_start();
  173. $products = $this->get_products( $args, $instance );
  174. if ( $products && $products->have_posts() ) {
  175. $this->widget_start( $args, $instance );
  176. echo wp_kses_post( apply_filters( 'woocommerce_before_widget_product_list', '<ul class="product_list_widget">' ) );
  177. $template_args = array(
  178. 'widget_id' => $args['widget_id'],
  179. 'show_rating' => true,
  180. );
  181. while ( $products->have_posts() ) {
  182. $products->the_post();
  183. wc_get_template( 'content-widget-product.php', $template_args );
  184. }
  185. echo wp_kses_post( apply_filters( 'woocommerce_after_widget_product_list', '</ul>' ) );
  186. $this->widget_end( $args );
  187. }
  188. wp_reset_postdata();
  189. echo $this->cache_widget( $args, ob_get_clean() ); // WPCS: XSS ok.
  190. }
  191. }