WC_Report_Sales_By_Category

WC_Report_Sales_By_Category.

Defined (1)

The class is defined in the following location(s).

/includes/admin/reports/class-wc-report-sales-by-category.php  
  1. class WC_Report_Sales_By_Category extends WC_Admin_Report { 
  2.  
  3. /** 
  4. * Chart colors. 
  5. * @var array 
  6. */ 
  7. public $chart_colours = array(); 
  8.  
  9. /** 
  10. * Categories ids. 
  11. * @var array 
  12. */ 
  13. public $show_categories = array(); 
  14.  
  15. /** 
  16. * Item sales. 
  17. * @var array 
  18. */ 
  19. private $item_sales = array(); 
  20.  
  21. /** 
  22. * Item sales and times. 
  23. * @var array 
  24. */ 
  25. private $item_sales_and_times = array(); 
  26.  
  27. /** 
  28. * Constructor. 
  29. */ 
  30. public function __construct() { 
  31. if ( isset( $_GET['show_categories'] ) ) { 
  32. $this->show_categories = is_array( $_GET['show_categories'] ) ? array_map( 'absint', $_GET['show_categories'] ) : array( absint( $_GET['show_categories'] ) ); 
  33.  
  34. /** 
  35. * Get all product ids in a category (and its children). 
  36. * @param int $category_id 
  37. * @return array 
  38. */ 
  39. public function get_products_in_category( $category_id ) { 
  40. $term_ids = get_term_children( $category_id, 'product_cat' ); 
  41. $term_ids[] = $category_id; 
  42. $product_ids = get_objects_in_term( $term_ids, 'product_cat' ); 
  43.  
  44. return array_unique( apply_filters( 'woocommerce_report_sales_by_category_get_products_in_category', $product_ids, $category_id ) ); 
  45.  
  46. /** 
  47. * Get the legend for the main chart sidebar. 
  48. * @return array 
  49. */ 
  50. public function get_chart_legend() { 
  51.  
  52. if ( empty( $this->show_categories ) ) { 
  53. return array(); 
  54.  
  55. $legend = array(); 
  56. $index = 0; 
  57.  
  58. foreach ( $this->show_categories as $category ) { 
  59.  
  60. $category = get_term( $category, 'product_cat' ); 
  61. $total = 0; 
  62. $product_ids = $this->get_products_in_category( $category->term_id ); 
  63.  
  64. foreach ( $product_ids as $id ) { 
  65.  
  66. if ( isset( $this->item_sales[ $id ] ) ) { 
  67. $total += $this->item_sales[ $id ]; 
  68.  
  69. $legend[] = array( 
  70. /** translators: 1: total items sold 2: category name */ 
  71. 'title' => sprintf( __( '%1$s sales in %2$s', 'woocommerce' ), '<strong>' . wc_price( $total ) . '</strong>', $category->name ),  
  72. 'color' => isset( $this->chart_colours[ $index ] ) ? $this->chart_colours[ $index ] : $this->chart_colours[0],  
  73. 'highlight_series' => $index,  
  74. ); 
  75.  
  76. $index++; 
  77.  
  78. return $legend; 
  79.  
  80. /** 
  81. * Output the report. 
  82. */ 
  83. public function output_report() { 
  84.  
  85. $ranges = array( 
  86. 'year' => __( 'Year', 'woocommerce' ),  
  87. 'last_month' => __( 'Last month', 'woocommerce' ),  
  88. 'month' => __( 'This month', 'woocommerce' ),  
  89. '7day' => __( 'Last 7 days', 'woocommerce' ),  
  90. ); 
  91.  
  92. $this->chart_colours = array( '#3498db', '#34495e', '#1abc9c', '#2ecc71', '#f1c40f', '#e67e22', '#e74c3c', '#2980b9', '#8e44ad', '#2c3e50', '#16a085', '#27ae60', '#f39c12', '#d35400', '#c0392b' ); 
  93.  
  94. $current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( $_GET['range'] ) : '7day'; 
  95.  
  96. if ( ! in_array( $current_range, array( 'custom', 'year', 'last_month', 'month', '7day' ) ) ) { 
  97. $current_range = '7day'; 
  98.  
  99. $this->check_current_range_nonce( $current_range ); 
  100. $this->calculate_current_range( $current_range ); 
  101.  
  102. // Get item sales data 
  103. if ( ! empty( $this->show_categories ) ) { 
  104. $order_items = $this->get_order_report_data( array( 
  105. 'data' => array( 
  106. '_product_id' => array( 
  107. 'type' => 'order_item_meta',  
  108. 'order_item_type' => 'line_item',  
  109. 'function' => '',  
  110. 'name' => 'product_id',  
  111. ),  
  112. '_line_total' => array( 
  113. 'type' => 'order_item_meta',  
  114. 'order_item_type' => 'line_item',  
  115. 'function' => 'SUM',  
  116. 'name' => 'order_item_amount',  
  117. ),  
  118. 'post_date' => array( 
  119. 'type' => 'post_data',  
  120. 'function' => '',  
  121. 'name' => 'post_date',  
  122. ),  
  123. ),  
  124. 'group_by' => 'ID, product_id, post_date',  
  125. 'query_type' => 'get_results',  
  126. 'filter_range' => true,  
  127. ) ); 
  128.  
  129. $this->item_sales = array(); 
  130. $this->item_sales_and_times = array(); 
  131.  
  132. if ( is_array( $order_items ) ) { 
  133.  
  134. foreach ( $order_items as $order_item ) { 
  135.  
  136. switch ( $this->chart_groupby ) { 
  137. case 'day' : 
  138. $time = strtotime( date( 'Ymd', strtotime( $order_item->post_date ) ) ) * 1000; 
  139. break; 
  140. case 'month' : 
  141. default : 
  142. $time = strtotime( date( 'Ym', strtotime( $order_item->post_date ) ) . '01' ) * 1000; 
  143. break; 
  144.  
  145. $this->item_sales_and_times[ $time ][ $order_item->product_id ] = isset( $this->item_sales_and_times[ $time ][ $order_item->product_id ] ) ? $this->item_sales_and_times[ $time ][ $order_item->product_id ] + $order_item->order_item_amount : $order_item->order_item_amount; 
  146.  
  147. $this->item_sales[ $order_item->product_id ] = isset( $this->item_sales[ $order_item->product_id ] ) ? $this->item_sales[ $order_item->product_id ] + $order_item->order_item_amount : $order_item->order_item_amount; 
  148.  
  149. include( WC()->plugin_path() . '/includes/admin/views/html-report-by-date.php' ); 
  150.  
  151. /** 
  152. * Get chart widgets. 
  153. * @return array 
  154. */ 
  155. public function get_chart_widgets() { 
  156.  
  157. return array( 
  158. array( 
  159. 'title' => __( 'Categories', 'woocommerce' ),  
  160. 'callback' => array( $this, 'category_widget' ),  
  161. ),  
  162. ); 
  163.  
  164. /** 
  165. * Output category widget. 
  166. */ 
  167. public function category_widget() { 
  168.  
  169. $categories = get_terms( 'product_cat', array( 'orderby' => 'name' ) ); 
  170. ?> 
  171. <form method="GET"> 
  172. <div> 
  173. <select multiple="multiple" data-placeholder="<?php esc_attr_e( 'Select categories…', 'woocommerce' ); ?>" class="wc-enhanced-select" id="show_categories" name="show_categories[]" style="width: 205px;"> 
  174. <?php 
  175. $r = array(); 
  176. $r['pad_counts'] = 1; 
  177. $r['hierarchical'] = 1; 
  178. $r['hide_empty'] = 1; 
  179. $r['value'] = 'id'; 
  180. $r['selected'] = $this->show_categories; 
  181.  
  182. include_once( WC()->plugin_path() . '/includes/walkers/class-product-cat-dropdown-walker.php' ); 
  183.  
  184. echo wc_walk_category_dropdown_tree( $categories, 0, $r ); 
  185. ?> 
  186. </select> 
  187. <a href="#" class="select_none"><?php _e( 'None', 'woocommerce' ); ?></a> 
  188. <a href="#" class="select_all"><?php _e( 'All', 'woocommerce' ); ?></a> 
  189. <input type="submit" class="submit button" value="<?php esc_attr_e( 'Show', 'woocommerce' ); ?>" /> 
  190. <input type="hidden" name="range" value="<?php if ( ! empty( $_GET['range'] ) ) echo esc_attr( $_GET['range'] ) ?>" /> 
  191. <input type="hidden" name="start_date" value="<?php if ( ! empty( $_GET['start_date'] ) ) echo esc_attr( $_GET['start_date'] ) ?>" /> 
  192. <input type="hidden" name="end_date" value="<?php if ( ! empty( $_GET['end_date'] ) ) echo esc_attr( $_GET['end_date'] ) ?>" /> 
  193. <input type="hidden" name="page" value="<?php if ( ! empty( $_GET['page'] ) ) echo esc_attr( $_GET['page'] ) ?>" /> 
  194. <input type="hidden" name="tab" value="<?php if ( ! empty( $_GET['tab'] ) ) echo esc_attr( $_GET['tab'] ) ?>" /> 
  195. <input type="hidden" name="report" value="<?php if ( ! empty( $_GET['report'] ) ) echo esc_attr( $_GET['report'] ) ?>" /> 
  196. </div> 
  197. <script type="text/javascript"> 
  198. jQuery(function() { 
  199. // Select all/None 
  200. jQuery( '.chart-widget' ).on( 'click', '.select_all', function() { 
  201. jQuery(this).closest( 'div' ).find( 'select option' ).attr( 'selected', 'selected' ); 
  202. jQuery(this).closest( 'div' ).find('select').change(); 
  203. return false; 
  204. }); 
  205.  
  206. jQuery( '.chart-widget').on( 'click', '.select_none', function() { 
  207. jQuery(this).closest( 'div' ).find( 'select option' ).removeAttr( 'selected' ); 
  208. jQuery(this).closest( 'div' ).find('select').change(); 
  209. return false; 
  210. }); 
  211. }); 
  212. </script> 
  213. </form> 
  214. <?php 
  215.  
  216. /** 
  217. * Output an export link. 
  218. */ 
  219. public function get_export_button() { 
  220.  
  221. $current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( $_GET['range'] ) : '7day'; 
  222. ?> 
  223. <a 
  224. href="#" 
  225. download="report-<?php echo esc_attr( $current_range ); ?>-<?php echo date_i18n( 'Y-m-d', current_time( 'timestamp' ) ); ?>.csv" 
  226. class="export_csv" 
  227. data-export="chart" 
  228. data-xaxes="<?php esc_attr_e( 'Date', 'woocommerce' ); ?>" 
  229. data-groupby="<?php echo $this->chart_groupby; ?>" 
  230. <?php _e( 'Export CSV', 'woocommerce' ); ?> 
  231. </a> 
  232. <?php 
  233.  
  234. /** 
  235. * Get the main chart. 
  236. * @return string 
  237. */ 
  238. public function get_main_chart() { 
  239. global $wp_locale; 
  240.  
  241. if ( empty( $this->show_categories ) ) { 
  242. ?> 
  243. <div class="chart-container"> 
  244. <p class="chart-prompt"><?php _e( 'Choose a category to view stats', 'woocommerce' ); ?></p> 
  245. </div> 
  246. <?php 
  247. } else { 
  248. $chart_data = array(); 
  249. $index = 0; 
  250.  
  251. foreach ( $this->show_categories as $category ) { 
  252.  
  253. $category = get_term( $category, 'product_cat' ); 
  254. $product_ids = $this->get_products_in_category( $category->term_id ); 
  255. $category_chart_data = array(); 
  256.  
  257. for ( $i = 0; $i <= $this->chart_interval; $i ++ ) { 
  258.  
  259. $interval_total = 0; 
  260.  
  261. switch ( $this->chart_groupby ) { 
  262. case 'day' : 
  263. $time = strtotime( date( 'Ymd', strtotime( "+{$i} DAY", $this->start_date ) ) ) * 1000; 
  264. break; 
  265. case 'month' : 
  266. default : 
  267. $time = strtotime( date( 'Ym', strtotime( "+{$i} MONTH", $this->start_date ) ) . '01' ) * 1000; 
  268. break; 
  269.  
  270. foreach ( $product_ids as $id ) { 
  271.  
  272. if ( isset( $this->item_sales_and_times[ $time ][ $id ] ) ) { 
  273. $interval_total += $this->item_sales_and_times[ $time ][ $id ]; 
  274.  
  275. $category_chart_data[] = array( $time, (float) wc_format_decimal( $interval_total, wc_get_price_decimals() ) ); 
  276.  
  277. $chart_data[ $category->term_id ]['category'] = $category->name; 
  278. $chart_data[ $category->term_id ]['data'] = $category_chart_data; 
  279.  
  280. $index++; 
  281. ?> 
  282. <div class="chart-container"> 
  283. <div class="chart-placeholder main"></div> 
  284. </div> 
  285. <script type="text/javascript"> 
  286. var main_chart; 
  287.  
  288. jQuery(function() { 
  289. var drawGraph = function( highlight ) { 
  290. var series = [ 
  291. <?php 
  292. $index = 0; 
  293. foreach ( $chart_data as $data ) { 
  294. $color = isset( $this->chart_colours[ $index ] ) ? $this->chart_colours[ $index ] : $this->chart_colours[0]; 
  295. $width = $this->barwidth / sizeof( $chart_data ); 
  296. $offset = ( $width * $index ); 
  297. $series = $data['data']; 
  298. foreach ( $series as $key => $series_data ) { 
  299. $series[ $key ][0] = $series_data[0] + $offset; 
  300. echo '{ 
  301. label: "' . esc_js( $data['category'] ) . '",  
  302. data: jQuery.parseJSON( "' . json_encode( $series ) . '" ),  
  303. color: "' . $color . '",  
  304. bars: { 
  305. fillColor: "' . $color . '",  
  306. fill: true,  
  307. show: true,  
  308. lineWidth: 1,  
  309. align: "center",  
  310. barWidth: ' . $width * 0.75 . ',  
  311. stack: false 
  312. },  
  313. ' . $this->get_currency_tooltip() . ',  
  314. enable_tooltip: true,  
  315. prepend_label: true 
  316. }, '; 
  317. $index++; 
  318. ?> 
  319. ]; 
  320.  
  321. if ( highlight !== 'undefined' && series[ highlight ] ) { 
  322. highlight_series = series[ highlight ]; 
  323.  
  324. highlight_series.color = '#9c5d90'; 
  325.  
  326. if ( highlight_series.bars ) { 
  327. highlight_series.bars.fillColor = '#9c5d90'; 
  328.  
  329. if ( highlight_series.lines ) { 
  330. highlight_series.lines.lineWidth = 5; 
  331.  
  332. main_chart = jQuery.plot( 
  333. jQuery('.chart-placeholder.main'),  
  334. series,  
  335. legend: { 
  336. show: false 
  337. },  
  338. grid: { 
  339. color: '#aaa',  
  340. borderColor: 'transparent',  
  341. borderWidth: 0,  
  342. hoverable: true 
  343. },  
  344. xaxes: [ { 
  345. color: '#aaa',  
  346. reserveSpace: true,  
  347. position: "bottom",  
  348. tickColor: 'transparent',  
  349. mode: "time",  
  350. timeformat: "<?php echo ( 'day' === $this->chart_groupby ) ? '%d %b' : '%b'; ?>",  
  351. monthNames: <?php echo json_encode( array_values( $wp_locale->month_abbrev ) ); ?>,  
  352. tickLength: 1,  
  353. minTickSize: [1, "<?php echo $this->chart_groupby; ?>"],  
  354. tickSize: [1, "<?php echo $this->chart_groupby; ?>"],  
  355. font: { 
  356. color: "#aaa" 
  357. } ],  
  358. yaxes: [ 
  359. min: 0,  
  360. tickDecimals: 2,  
  361. color: 'transparent',  
  362. font: { color: "#aaa" } 
  363. ],  
  364. ); 
  365.  
  366. jQuery('.chart-placeholder').resize(); 
  367.  
  368.  
  369. drawGraph(); 
  370.  
  371. jQuery('.highlight_series').hover( 
  372. function() { 
  373. drawGraph( jQuery(this).data('series') ); 
  374. },  
  375. function() { 
  376. drawGraph(); 
  377. ); 
  378. }); 
  379. </script> 
  380. <?php