Файловый менеджер - Редактировать - /home/infrafs/INFRABIKEIT/wp-content/plugins/reports.tar
Назад
class-wc-report-sales-by-category.php 0000644 00000032403 15134216707 0013642 0 ustar 00 <?php /** * Sales by category report functionality * * @package WooCommerce\Admin\Reporting */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * WC_Report_Sales_By_Category * * @package WooCommerce\Admin\Reports * @version 2.1.0 */ class WC_Report_Sales_By_Category extends WC_Admin_Report { /** * Chart colors. * * @var array */ public $chart_colours = array(); /** * Categories ids. * * @var array */ public $show_categories = array(); /** * Item sales. * * @var array */ private $item_sales = array(); /** * Item sales and times. * * @var array */ private $item_sales_and_times = array(); /** * Constructor. */ public function __construct() { if ( isset( $_GET['show_categories'] ) ) { $this->show_categories = is_array( $_GET['show_categories'] ) ? array_map( 'absint', $_GET['show_categories'] ) : array( absint( $_GET['show_categories'] ) ); } } /** * Get all product ids in a category (and its children). * * @param int $category_id Category ID. * @return array */ public function get_products_in_category( $category_id ) { $term_ids = get_term_children( $category_id, 'product_cat' ); $term_ids[] = $category_id; $product_ids = get_objects_in_term( $term_ids, 'product_cat' ); return array_unique( apply_filters( 'woocommerce_report_sales_by_category_get_products_in_category', $product_ids, $category_id ) ); } /** * Get the legend for the main chart sidebar. * * @return array */ public function get_chart_legend() { if ( empty( $this->show_categories ) ) { return array(); } $legend = array(); $index = 0; foreach ( $this->show_categories as $category ) { $category = get_term( $category, 'product_cat' ); $total = 0; $product_ids = $this->get_products_in_category( $category->term_id ); foreach ( $product_ids as $id ) { if ( isset( $this->item_sales[ $id ] ) ) { $total += $this->item_sales[ $id ]; } } $legend[] = array( /* translators: 1: total items sold 2: category name */ 'title' => sprintf( __( '%1$s sales in %2$s', 'woocommerce' ), '<strong>' . wc_price( $total ) . '</strong>', $category->name ), 'color' => isset( $this->chart_colours[ $index ] ) ? $this->chart_colours[ $index ] : $this->chart_colours[0], 'highlight_series' => $index, ); $index++; } return $legend; } /** * Output the report. */ public function output_report() { $ranges = array( 'year' => __( 'Year', 'woocommerce' ), 'last_month' => __( 'Last month', 'woocommerce' ), 'month' => __( 'This month', 'woocommerce' ), '7day' => __( 'Last 7 days', 'woocommerce' ), ); $this->chart_colours = array( '#3498db', '#34495e', '#1abc9c', '#2ecc71', '#f1c40f', '#e67e22', '#e74c3c', '#2980b9', '#8e44ad', '#2c3e50', '#16a085', '#27ae60', '#f39c12', '#d35400', '#c0392b' ); $current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; if ( ! in_array( $current_range, array( 'custom', 'year', 'last_month', 'month', '7day' ) ) ) { $current_range = '7day'; } $this->check_current_range_nonce( $current_range ); $this->calculate_current_range( $current_range ); // Get item sales data. if ( ! empty( $this->show_categories ) ) { $order_items = $this->get_order_report_data( array( 'data' => array( '_product_id' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => '', 'name' => 'product_id', ), '_line_total' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => 'SUM', 'name' => 'order_item_amount', ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), ), 'group_by' => 'ID, product_id, post_date', 'query_type' => 'get_results', 'filter_range' => true, ) ); $this->item_sales = array(); $this->item_sales_and_times = array(); if ( is_array( $order_items ) ) { foreach ( $order_items as $order_item ) { switch ( $this->chart_groupby ) { case 'day': $time = strtotime( gmdate( 'Ymd', strtotime( $order_item->post_date ) ) ) * 1000; break; case 'month': default: $time = strtotime( gmdate( 'Ym', strtotime( $order_item->post_date ) ) . '01' ) * 1000; break; } $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; $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; } } } include WC()->plugin_path() . '/includes/admin/views/html-report-by-date.php'; } /** * Get chart widgets. * * @return array */ public function get_chart_widgets() { return array( array( 'title' => __( 'Categories', 'woocommerce' ), 'callback' => array( $this, 'category_widget' ), ), ); } /** * Output category widget. */ public function category_widget() { $categories = get_terms( 'product_cat', array( 'orderby' => 'name' ) ); ?> <form method="GET"> <div> <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;"> <?php $r = array(); $r['pad_counts'] = 1; $r['hierarchical'] = 1; $r['hide_empty'] = 1; $r['value'] = 'id'; $r['selected'] = $this->show_categories; include_once WC()->plugin_path() . '/includes/walkers/class-wc-product-cat-dropdown-walker.php'; echo wc_walk_category_dropdown_tree( $categories, 0, $r ); // @codingStandardsIgnoreLine ?> </select> <?php // @codingStandardsIgnoreStart ?> <a href="#" class="select_none"><?php esc_html_e( 'None', 'woocommerce' ); ?></a> <a href="#" class="select_all"><?php esc_html_e( 'All', 'woocommerce' ); ?></a> <button type="submit" class="submit button" value="<?php esc_attr_e( 'Show', 'woocommerce' ); ?>"><?php esc_html_e( 'Show', 'woocommerce' ); ?></button> <input type="hidden" name="range" value="<?php echo ( ! empty( $_GET['range'] ) ) ? esc_attr( wp_unslash( $_GET['range'] ) ) : ''; ?>" /> <input type="hidden" name="start_date" value="<?php echo ( ! empty( $_GET['start_date'] ) ) ? esc_attr( wp_unslash( $_GET['start_date'] ) ) : ''; ?>" /> <input type="hidden" name="end_date" value="<?php echo ( ! empty( $_GET['end_date'] ) ) ? esc_attr( wp_unslash( $_GET['end_date'] ) ) : ''; ?>" /> <input type="hidden" name="page" value="<?php echo ( ! empty( $_GET['page'] ) ) ? esc_attr( wp_unslash( $_GET['page'] ) ) : ''; ?>" /> <input type="hidden" name="tab" value="<?php echo ( ! empty( $_GET['tab'] ) ) ? esc_attr( wp_unslash( $_GET['tab'] ) ) : ''; ?>" /> <input type="hidden" name="report" value="<?php echo ( ! empty( $_GET['report'] ) ) ? esc_attr( wp_unslash( $_GET['report'] ) ) : ''; ?>" /> <?php // @codingStandardsIgnoreEnd ?> </div> <script type="text/javascript"> jQuery(function(){ // Select all/None jQuery( '.chart-widget' ).on( 'click', '.select_all', function() { jQuery(this).closest( 'div' ).find( 'select option' ).attr( 'selected', 'selected' ); jQuery(this).closest( 'div' ).find('select').trigger( 'change' ); return false; }); jQuery( '.chart-widget').on( 'click', '.select_none', function() { jQuery(this).closest( 'div' ).find( 'select option' ).prop( 'selected', false ); jQuery(this).closest( 'div' ).find('select').trigger( 'change' ); return false; }); }); </script> </form> <?php } /** * Output an export link. */ public function get_export_button() { $current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; ?> <a href="#" download="report-<?php echo esc_attr( $current_range ); ?>-<?php echo esc_attr( date_i18n( 'Y-m-d', current_time( 'timestamp' ) ) ); ?>.csv" class="export_csv" data-export="chart" data-xaxes="<?php esc_attr_e( 'Date', 'woocommerce' ); ?>" data-groupby="<?php echo esc_attr( $this->chart_groupby ); ?>" > <?php esc_html_e( 'Export CSV', 'woocommerce' ); ?> </a> <?php } /** * Get the main chart. */ public function get_main_chart() { global $wp_locale; if ( empty( $this->show_categories ) ) { ?> <div class="chart-container"> <p class="chart-prompt"><?php esc_html_e( 'Choose a category to view stats', 'woocommerce' ); ?></p> </div> <?php } else { $chart_data = array(); $index = 0; foreach ( $this->show_categories as $category ) { $category = get_term( $category, 'product_cat' ); $product_ids = $this->get_products_in_category( $category->term_id ); $category_chart_data = array(); for ( $i = 0; $i <= $this->chart_interval; $i ++ ) { $interval_total = 0; switch ( $this->chart_groupby ) { case 'day': $time = strtotime( gmdate( 'Ymd', strtotime( "+{$i} DAY", $this->start_date ) ) ) * 1000; break; case 'month': default: $time = strtotime( gmdate( 'Ym', strtotime( "+{$i} MONTH", $this->start_date ) ) . '01' ) * 1000; break; } foreach ( $product_ids as $id ) { if ( isset( $this->item_sales_and_times[ $time ][ $id ] ) ) { $interval_total += $this->item_sales_and_times[ $time ][ $id ]; } } $category_chart_data[] = array( $time, (float) wc_format_decimal( $interval_total, wc_get_price_decimals() ) ); } $chart_data[ $category->term_id ]['category'] = $category->name; $chart_data[ $category->term_id ]['data'] = $category_chart_data; $index++; } ?> <div class="chart-container"> <div class="chart-placeholder main"></div> </div> <?php // @codingStandardsIgnoreStart ?> <script type="text/javascript"> var main_chart; jQuery(function(){ var drawGraph = function( highlight ) { var series = [ <?php $index = 0; foreach ( $chart_data as $data ) { $color = isset( $this->chart_colours[ $index ] ) ? $this->chart_colours[ $index ] : $this->chart_colours[0]; $width = $this->barwidth / sizeof( $chart_data ); $offset = ( $width * $index ); $series = $data['data']; foreach ( $series as $key => $series_data ) { $series[ $key ][0] = $series_data[0] + $offset; } $series = wp_json_encode( $series ); echo '{ label: "' . esc_js( $data['category'] ) . '", data: JSON.parse( decodeURIComponent( "' . rawurlencode( $series ) . '" ) ), color: "' . $color . '", bars: { fillColor: "' . $color . '", fill: true, show: true, lineWidth: 1, align: "center", barWidth: ' . $width * 0.75 . ', stack: false }, ' . $this->get_currency_tooltip() . ', enable_tooltip: true, prepend_label: true },'; $index++; } ?> ]; if ( highlight !== 'undefined' && series[ highlight ] ) { highlight_series = series[ highlight ]; highlight_series.color = '#9c5d90'; if ( highlight_series.bars ) { highlight_series.bars.fillColor = '#9c5d90'; } if ( highlight_series.lines ) { highlight_series.lines.lineWidth = 5; } } main_chart = jQuery.plot( jQuery('.chart-placeholder.main'), series, { legend: { show: false }, grid: { color: '#aaa', borderColor: 'transparent', borderWidth: 0, hoverable: true }, xaxes: [ { color: '#aaa', reserveSpace: true, position: "bottom", tickColor: 'transparent', mode: "time", timeformat: "<?php echo ( 'day' === $this->chart_groupby ) ? '%d %b' : '%b'; ?>", monthNames: JSON.parse( decodeURIComponent( '<?php echo rawurlencode( wp_json_encode( array_values( $wp_locale->month_abbrev ) ) ); ?>' ) ), tickLength: 1, minTickSize: [1, "<?php echo $this->chart_groupby; ?>"], tickSize: [1, "<?php echo $this->chart_groupby; ?>"], font: { color: "#aaa" } } ], yaxes: [ { min: 0, tickDecimals: 2, color: 'transparent', font: { color: "#aaa" } } ], } ); jQuery('.chart-placeholder').trigger( 'resize' ); } drawGraph(); jQuery('.highlight_series').on( 'mouseenter', function() { drawGraph( jQuery(this).data('series') ); } ).on( 'mouseleave', function() { drawGraph(); } ); }); </script> <?php // @codingStandardsIgnoreEnd ?> <?php } } } class-wc-report-sales-by-product.php 0000644 00000050515 15134216707 0013511 0 ustar 00 <?php /** * Sales By Product Reporting * * @package WooCommerce\Admin\Reporting */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * WC_Report_Sales_By_Product * * @package WooCommerce\Admin\Reports * @version 2.1.0 */ class WC_Report_Sales_By_Product extends WC_Admin_Report { /** * Chart colors. * * @var array */ public $chart_colours = array(); /** * Product ids. * * @var array */ public $product_ids = array(); /** * Product ids with titles. * * @var array */ public $product_ids_titles = array(); /** * Constructor. */ public function __construct() { // @codingStandardsIgnoreStart if ( isset( $_GET['product_ids'] ) && is_array( $_GET['product_ids'] ) ) { $this->product_ids = array_filter( array_map( 'absint', $_GET['product_ids'] ) ); } elseif ( isset( $_GET['product_ids'] ) ) { $this->product_ids = array_filter( array( absint( $_GET['product_ids'] ) ) ); } // @codingStandardsIgnoreEnd } /** * Get the legend for the main chart sidebar. * * @return array */ public function get_chart_legend() { if ( empty( $this->product_ids ) ) { return array(); } $legend = array(); $total_sales = $this->get_order_report_data( array( 'data' => array( '_line_total' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => 'SUM', 'name' => 'order_item_amount', ), ), 'where_meta' => array( 'relation' => 'OR', array( 'type' => 'order_item_meta', 'meta_key' => array( '_product_id', '_variation_id' ), // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key 'meta_value' => $this->product_ids, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value 'operator' => 'IN', ), ), 'query_type' => 'get_var', 'filter_range' => true, 'order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ), ) ); $total_items = absint( $this->get_order_report_data( array( 'data' => array( '_qty' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => 'SUM', 'name' => 'order_item_count', ), ), 'where_meta' => array( 'relation' => 'OR', array( 'type' => 'order_item_meta', 'meta_key' => array( '_product_id', '_variation_id' ), // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key 'meta_value' => $this->product_ids, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value 'operator' => 'IN', ), ), 'query_type' => 'get_var', 'filter_range' => true, 'order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ), ) ) ); $legend[] = array( /* translators: %s: total items sold */ 'title' => sprintf( __( '%s sales for the selected items', 'woocommerce' ), '<strong>' . wc_price( $total_sales ) . '</strong>' ), 'color' => $this->chart_colours['sales_amount'], 'highlight_series' => 1, ); $legend[] = array( /* translators: %s: total items purchased */ 'title' => sprintf( __( '%s purchases for the selected items', 'woocommerce' ), '<strong>' . ( $total_items ) . '</strong>' ), 'color' => $this->chart_colours['item_count'], 'highlight_series' => 0, ); return $legend; } /** * Output the report. */ public function output_report() { $ranges = array( 'year' => __( 'Year', 'woocommerce' ), 'last_month' => __( 'Last month', 'woocommerce' ), 'month' => __( 'This month', 'woocommerce' ), '7day' => __( 'Last 7 days', 'woocommerce' ), ); $this->chart_colours = array( 'sales_amount' => '#3498db', 'item_count' => '#d4d9dc', ); $current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; //phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( ! in_array( $current_range, array( 'custom', 'year', 'last_month', 'month', '7day' ), true ) ) { $current_range = '7day'; } $this->check_current_range_nonce( $current_range ); $this->calculate_current_range( $current_range ); include WC()->plugin_path() . '/includes/admin/views/html-report-by-date.php'; } /** * Get chart widgets. * * @return array */ public function get_chart_widgets() { $widgets = array(); if ( ! empty( $this->product_ids ) ) { $widgets[] = array( 'title' => __( 'Showing reports for:', 'woocommerce' ), 'callback' => array( $this, 'current_filters' ), ); } $widgets[] = array( 'title' => '', 'callback' => array( $this, 'products_widget' ), ); return $widgets; } /** * Output current filters. */ public function current_filters() { $this->product_ids_titles = array(); foreach ( $this->product_ids as $product_id ) { $product = wc_get_product( $product_id ); if ( $product ) { $this->product_ids_titles[] = $product->get_formatted_name(); } else { $this->product_ids_titles[] = '#' . $product_id; } } echo '<p><strong>' . wp_kses_post( implode( ', ', $this->product_ids_titles ) ) . '</strong></p>'; echo '<p><a class="button" href="' . esc_url( remove_query_arg( 'product_ids' ) ) . '">' . esc_html__( 'Reset', 'woocommerce' ) . '</a></p>'; } /** * Output products widget. */ public function products_widget() { ?> <h4 class="section_title"><span><?php esc_html_e( 'Product search', 'woocommerce' ); ?></span></h4> <div class="section"> <form method="GET"> <div> <?php // @codingStandardsIgnoreStart ?> <select class="wc-product-search" style="width:203px;" multiple="multiple" id="product_ids" name="product_ids[]" data-placeholder="<?php esc_attr_e( 'Search for a product…', 'woocommerce' ); ?>" data-action="woocommerce_json_search_products_and_variations"></select> <button type="submit" class="submit button" value="<?php esc_attr_e( 'Show', 'woocommerce' ); ?>"><?php esc_html_e( 'Show', 'woocommerce' ); ?></button> <input type="hidden" name="range" value="<?php echo ( ! empty( $_GET['range'] ) ) ? esc_attr( $_GET['range'] ) : ''; ?>" /> <input type="hidden" name="start_date" value="<?php echo ( ! empty( $_GET['start_date'] ) ) ? esc_attr( $_GET['start_date'] ) : ''; ?>" /> <input type="hidden" name="end_date" value="<?php echo ( ! empty( $_GET['end_date'] ) ) ? esc_attr( $_GET['end_date'] ) : ''; ?>" /> <input type="hidden" name="page" value="<?php echo ( ! empty( $_GET['page'] ) ) ? esc_attr( $_GET['page'] ) : ''; ?>" /> <input type="hidden" name="tab" value="<?php echo ( ! empty( $_GET['tab'] ) ) ? esc_attr( $_GET['tab'] ) : ''; ?>" /> <input type="hidden" name="report" value="<?php echo ( ! empty( $_GET['report'] ) ) ? esc_attr( $_GET['report'] ) : ''; ?>" /> <?php wp_nonce_field( 'custom_range', 'wc_reports_nonce', false ); ?> <?php // @codingStandardsIgnoreEnd ?> </div> </form> </div> <h4 class="section_title"><span><?php esc_html_e( 'Top sellers', 'woocommerce' ); ?></span></h4> <div class="section"> <table cellspacing="0"> <?php $top_sellers = $this->get_order_report_data( array( 'data' => array( '_product_id' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => '', 'name' => 'product_id', ), '_qty' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => 'SUM', 'name' => 'order_item_qty', ), ), 'order_by' => 'order_item_qty DESC', 'group_by' => 'product_id', 'limit' => 12, 'query_type' => 'get_results', 'filter_range' => true, 'order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ), ) ); if ( $top_sellers ) { // @codingStandardsIgnoreStart foreach ( $top_sellers as $product ) { echo '<tr class="' . ( in_array( $product->product_id, $this->product_ids ) ? 'active' : '' ) . '"> <td class="count">' . esc_html( $product->order_item_qty ) . '</td> <td class="name"><a href="' . esc_url( add_query_arg( 'product_ids', $product->product_id ) ) . '">' . esc_html( get_the_title( $product->product_id ) ) . '</a></td> <td class="sparkline">' . $this->sales_sparkline( $product->product_id, 7, 'count' ) . '</td> </tr>'; } // @codingStandardsIgnoreEnd } else { echo '<tr><td colspan="3">' . esc_html__( 'No products found in range', 'woocommerce' ) . '</td></tr>'; } ?> </table> </div> <h4 class="section_title"><span><?php esc_html_e( 'Top freebies', 'woocommerce' ); ?></span></h4> <div class="section"> <table cellspacing="0"> <?php $top_freebies = $this->get_order_report_data( array( 'data' => array( '_product_id' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => '', 'name' => 'product_id', ), '_qty' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => 'SUM', 'name' => 'order_item_qty', ), ), 'where_meta' => array( array( 'type' => 'order_item_meta', 'meta_key' => '_line_subtotal', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key 'meta_value' => '0', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value 'operator' => '=', ), ), 'order_by' => 'order_item_qty DESC', 'group_by' => 'product_id', 'limit' => 12, 'query_type' => 'get_results', 'filter_range' => true, ) ); if ( $top_freebies ) { // @codingStandardsIgnoreStart foreach ( $top_freebies as $product ) { echo '<tr class="' . ( in_array( $product->product_id, $this->product_ids ) ? 'active' : '' ) . '"> <td class="count">' . esc_html( $product->order_item_qty ) . '</td> <td class="name"><a href="' . esc_url( add_query_arg( 'product_ids', $product->product_id ) ) . '">' . esc_html( get_the_title( $product->product_id ) ) . '</a></td> <td class="sparkline">' . $this->sales_sparkline( $product->product_id, 7, 'count' ) . '</td> </tr>'; } // @codingStandardsIgnoreEnd } else { echo '<tr><td colspan="3">' . esc_html__( 'No products found in range', 'woocommerce' ) . '</td></tr>'; } ?> </table> </div> <h4 class="section_title"><span><?php esc_html_e( 'Top earners', 'woocommerce' ); ?></span></h4> <div class="section"> <table cellspacing="0"> <?php $top_earners = $this->get_order_report_data( array( 'data' => array( '_product_id' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => '', 'name' => 'product_id', ), '_line_total' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => 'SUM', 'name' => 'order_item_total', ), ), 'order_by' => 'order_item_total DESC', 'group_by' => 'product_id', 'limit' => 12, 'query_type' => 'get_results', 'filter_range' => true, 'order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ), ) ); if ( $top_earners ) { // @codingStandardsIgnoreStart foreach ( $top_earners as $product ) { echo '<tr class="' . ( in_array( $product->product_id, $this->product_ids ) ? 'active' : '' ) . '"> <td class="count">' . wc_price( $product->order_item_total ) . '</td> <td class="name"><a href="' . esc_url( add_query_arg( 'product_ids', $product->product_id ) ) . '">' . esc_html( get_the_title( $product->product_id ) ) . '</a></td> <td class="sparkline">' . $this->sales_sparkline( $product->product_id, 7, 'sales' ) . '</td> </tr>'; } // @codingStandardsIgnoreEnd } else { echo '<tr><td colspan="3">' . esc_html__( 'No products found in range', 'woocommerce' ) . '</td></tr>'; } ?> </table> </div> <script type="text/javascript"> jQuery( '.section_title' ).on( 'click', function() { var next_section = jQuery( this ).next( '.section' ); if ( jQuery( next_section ).is( ':visible' ) ) { return false; } jQuery( '.section:visible' ).slideUp(); jQuery( '.section_title' ).removeClass( 'open' ); jQuery( this ).addClass( 'open' ).next( '.section' ).slideDown(); return false; } ); jQuery( '.section' ).slideUp( 100, function() { <?php if ( empty( $this->product_ids ) ) : ?> jQuery( '.section_title:eq(1)' ).trigger( 'click' ); <?php endif; ?> } ); </script> <?php } /** * Output an export link. */ public function get_export_button() { $current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; //phpcs:ignore WordPress.Security.NonceVerification.Recommended ?> <a href="#" download="report-<?php echo esc_attr( $current_range ); ?>-<?php echo esc_html( date_i18n( 'Y-m-d', current_time( 'timestamp' ) ) ); ?>.csv" class="export_csv" data-export="chart" data-xaxes="<?php esc_attr_e( 'Date', 'woocommerce' ); ?>" data-groupby="<?php echo $this->chart_groupby; ?>"<?php // @codingStandardsIgnoreLine ?> > <?php esc_html_e( 'Export CSV', 'woocommerce' ); ?> </a> <?php } /** * Get the main chart. */ public function get_main_chart() { global $wp_locale; if ( empty( $this->product_ids ) ) { ?> <div class="chart-container"> <p class="chart-prompt"><?php esc_html_e( 'Choose a product to view stats', 'woocommerce' ); ?></p> </div> <?php } else { // Get orders and dates in range - we want the SUM of order totals, COUNT of order items, COUNT of orders, and the date. $order_item_counts = $this->get_order_report_data( array( 'data' => array( '_qty' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => 'SUM', 'name' => 'order_item_count', ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), '_product_id' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => '', 'name' => 'product_id', ), ), 'where_meta' => array( 'relation' => 'OR', array( 'type' => 'order_item_meta', 'meta_key' => array( '_product_id', '_variation_id' ), // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key 'meta_value' => $this->product_ids, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value 'operator' => 'IN', ), ), 'group_by' => 'product_id,' . $this->group_by_query, 'order_by' => 'post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, 'order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ), ) ); $order_item_amounts = $this->get_order_report_data( array( 'data' => array( '_line_total' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => 'SUM', 'name' => 'order_item_amount', ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), '_product_id' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => '', 'name' => 'product_id', ), ), 'where_meta' => array( 'relation' => 'OR', array( 'type' => 'order_item_meta', 'meta_key' => array( '_product_id', '_variation_id' ), // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key 'meta_value' => $this->product_ids, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value 'operator' => 'IN', ), ), 'group_by' => 'product_id, ' . $this->group_by_query, 'order_by' => 'post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, 'order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ), ) ); // Prepare data for report. $order_item_counts = $this->prepare_chart_data( $order_item_counts, 'post_date', 'order_item_count', $this->chart_interval, $this->start_date, $this->chart_groupby ); $order_item_amounts = $this->prepare_chart_data( $order_item_amounts, 'post_date', 'order_item_amount', $this->chart_interval, $this->start_date, $this->chart_groupby ); // Encode in json format. $chart_data = wp_json_encode( array( 'order_item_counts' => array_values( $order_item_counts ), 'order_item_amounts' => array_values( $order_item_amounts ), ) ); ?> <div class="chart-container"> <div class="chart-placeholder main"></div> </div> <?php // @codingStandardsIgnoreStart ?> <script type="text/javascript"> var main_chart; jQuery(function(){ var order_data = JSON.parse( decodeURIComponent( '<?php echo rawurlencode( $chart_data ); ?>' ) ); var drawGraph = function( highlight ) { var series = [ { label: "<?php echo esc_js( __( 'Number of items sold', 'woocommerce' ) ) ?>", data: order_data.order_item_counts, color: '<?php echo $this->chart_colours['item_count']; ?>', bars: { fillColor: '<?php echo $this->chart_colours['item_count']; ?>', fill: true, show: true, lineWidth: 0, barWidth: <?php echo $this->barwidth; ?> * 0.5, align: 'center' }, shadowSize: 0, hoverable: false }, { label: "<?php echo esc_js( __( 'Sales amount', 'woocommerce' ) ) ?>", data: order_data.order_item_amounts, yaxis: 2, color: '<?php echo $this->chart_colours['sales_amount']; ?>', points: { show: true, radius: 5, lineWidth: 3, fillColor: '#fff', fill: true }, lines: { show: true, lineWidth: 4, fill: false }, shadowSize: 0, <?php echo $this->get_currency_tooltip(); ?> } ]; if ( highlight !== 'undefined' && series[ highlight ] ) { highlight_series = series[ highlight ]; highlight_series.color = '#9c5d90'; if ( highlight_series.bars ) highlight_series.bars.fillColor = '#9c5d90'; if ( highlight_series.lines ) { highlight_series.lines.lineWidth = 5; } } main_chart = jQuery.plot( jQuery('.chart-placeholder.main'), series, { legend: { show: false }, grid: { color: '#aaa', borderColor: 'transparent', borderWidth: 0, hoverable: true }, xaxes: [ { color: '#aaa', position: "bottom", tickColor: 'transparent', mode: "time", timeformat: "<?php echo ( 'day' === $this->chart_groupby ) ? '%d %b' : '%b'; ?>", monthNames: JSON.parse( decodeURIComponent( '<?php echo rawurlencode( wp_json_encode( array_values( $wp_locale->month_abbrev ) ) ); ?>' ) ), tickLength: 1, minTickSize: [1, "<?php echo $this->chart_groupby; ?>"], font: { color: "#aaa" } } ], yaxes: [ { min: 0, minTickSize: 1, tickDecimals: 0, color: '#ecf0f1', font: { color: "#aaa" } }, { position: "right", min: 0, tickDecimals: 2, alignTicksWithAxis: 1, color: 'transparent', font: { color: "#aaa" } } ], } ); jQuery('.chart-placeholder').trigger( 'resize' ); } drawGraph(); jQuery('.highlight_series').on( 'mouseenter', function() { drawGraph( jQuery(this).data('series') ); } ).on( 'mouseleave', function() { drawGraph(); } ); }); </script> <?php // @codingStandardsIgnoreEnd } } } class-wc-report-stock.php 0000644 00000011007 15134216707 0011430 0 ustar 00 <?php if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } if ( ! class_exists( 'WP_List_Table' ) ) { require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php'; } /** * WC_Report_Stock. * * @author WooThemes * @category Admin * @package WooCommerce\Admin\Reports * @version 2.1.0 */ class WC_Report_Stock extends WP_List_Table { /** * Max items. * * @var int */ protected $max_items; /** * Constructor. */ public function __construct() { parent::__construct( array( 'singular' => 'stock', 'plural' => 'stock', 'ajax' => false, ) ); } /** * No items found text. */ public function no_items() { _e( 'No products found.', 'woocommerce' ); } /** * Don't need this. * * @param string $position */ public function display_tablenav( $position ) { if ( 'top' !== $position ) { parent::display_tablenav( $position ); } } /** * Output the report. */ public function output_report() { $this->prepare_items(); echo '<div id="poststuff" class="woocommerce-reports-wide">'; $this->display(); echo '</div>'; } /** * Get column value. * * @param mixed $item * @param string $column_name */ public function column_default( $item, $column_name ) { global $product; if ( ! $product || $product->get_id() !== $item->id ) { $product = wc_get_product( $item->id ); } if ( ! $product ) { return; } switch ( $column_name ) { case 'product': if ( $sku = $product->get_sku() ) { echo esc_html( $sku ) . ' - '; } echo esc_html( $product->get_name() ); // Get variation data. if ( $product->is_type( 'variation' ) ) { echo '<div class="description">' . wp_kses_post( wc_get_formatted_variation( $product, true ) ) . '</div>'; } break; case 'parent': if ( $item->parent ) { echo esc_html( get_the_title( $item->parent ) ); } else { echo '-'; } break; case 'stock_status': if ( $product->is_on_backorder() ) { $stock_html = '<mark class="onbackorder">' . __( 'On backorder', 'woocommerce' ) . '</mark>'; } elseif ( $product->is_in_stock() ) { $stock_html = '<mark class="instock">' . __( 'In stock', 'woocommerce' ) . '</mark>'; } else { $stock_html = '<mark class="outofstock">' . __( 'Out of stock', 'woocommerce' ) . '</mark>'; } echo apply_filters( 'woocommerce_admin_stock_html', $stock_html, $product ); break; case 'stock_level': echo esc_html( $product->get_stock_quantity() ); break; case 'wc_actions': ?><p> <?php $actions = array(); $action_id = $product->is_type( 'variation' ) ? $item->parent : $item->id; $actions['edit'] = array( 'url' => admin_url( 'post.php?post=' . $action_id . '&action=edit' ), 'name' => __( 'Edit', 'woocommerce' ), 'action' => 'edit', ); if ( $product->is_visible() ) { $actions['view'] = array( 'url' => get_permalink( $action_id ), 'name' => __( 'View', 'woocommerce' ), 'action' => 'view', ); } $actions = apply_filters( 'woocommerce_admin_stock_report_product_actions', $actions, $product ); foreach ( $actions as $action ) { printf( '<a class="button tips %1$s" href="%2$s" data-tip="%3$s">%4$s</a>', esc_attr( $action['action'] ), esc_url( $action['url'] ), sprintf( esc_attr__( '%s product', 'woocommerce' ), $action['name'] ), esc_html( $action['name'] ) ); } ?> </p> <?php break; } } /** * Get columns. * * @return array */ public function get_columns() { $columns = array( 'product' => __( 'Product', 'woocommerce' ), 'parent' => __( 'Parent', 'woocommerce' ), 'stock_level' => __( 'Units in stock', 'woocommerce' ), 'stock_status' => __( 'Stock status', 'woocommerce' ), 'wc_actions' => __( 'Actions', 'woocommerce' ), ); return $columns; } /** * Prepare customer list items. */ public function prepare_items() { $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() ); $current_page = absint( $this->get_pagenum() ); $per_page = apply_filters( 'woocommerce_admin_stock_report_products_per_page', 20 ); $this->get_items( $current_page, $per_page ); /** * Pagination. */ $this->set_pagination_args( array( 'total_items' => $this->max_items, 'per_page' => $per_page, 'total_pages' => ceil( $this->max_items / $per_page ), ) ); } } class-wc-report-coupon-usage.php 0000644 00000042723 15134216707 0012723 0 ustar 00 <?php /** * Coupon usage report functionality * * @package WooCommerce\Admin\Reports */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * WC_Report_Coupon_Usage * * @package WooCommerce\Admin\Reports * @version 2.1.0 */ class WC_Report_Coupon_Usage extends WC_Admin_Report { /** * Chart colors. * * @var array */ public $chart_colours = array(); /** * Coupon codes. * * @var array */ public $coupon_codes = array(); /** * Constructor. */ public function __construct() { if ( isset( $_GET['coupon_codes'] ) && is_array( $_GET['coupon_codes'] ) ) { $this->coupon_codes = array_filter( array_map( 'sanitize_text_field', wp_unslash( $_GET['coupon_codes'] ) ) ); } elseif ( isset( $_GET['coupon_codes'] ) ) { $this->coupon_codes = array_filter( array( sanitize_text_field( wp_unslash( $_GET['coupon_codes'] ) ) ) ); } } /** * Get the legend for the main chart sidebar. * * @return array */ public function get_chart_legend() { $legend = array(); $total_discount_query = array( 'data' => array( 'discount_amount' => array( 'type' => 'order_item_meta', 'order_item_type' => 'coupon', 'function' => 'SUM', 'name' => 'discount_amount', ), ), 'where' => array( array( 'key' => 'order_item_type', 'value' => 'coupon', 'operator' => '=', ), ), 'query_type' => 'get_var', 'filter_range' => true, 'order_types' => wc_get_order_types( 'order-count' ), ); $total_coupons_query = array( 'data' => array( 'order_item_id' => array( 'type' => 'order_item', 'order_item_type' => 'coupon', 'function' => 'COUNT', 'name' => 'order_coupon_count', ), ), 'where' => array( array( 'key' => 'order_item_type', 'value' => 'coupon', 'operator' => '=', ), ), 'query_type' => 'get_var', 'filter_range' => true, 'order_types' => wc_get_order_types( 'order-count' ), ); if ( ! empty( $this->coupon_codes ) ) { $coupon_code_query = array( 'type' => 'order_item', 'key' => 'order_item_name', 'value' => $this->coupon_codes, 'operator' => 'IN', ); $total_discount_query['where'][] = $coupon_code_query; $total_coupons_query['where'][] = $coupon_code_query; } $total_discount = $this->get_order_report_data( $total_discount_query ); $total_coupons = absint( $this->get_order_report_data( $total_coupons_query ) ); $legend[] = array( /* translators: %s: discount amount */ 'title' => sprintf( __( '%s discounts in total', 'woocommerce' ), '<strong>' . wc_price( $total_discount ) . '</strong>' ), 'color' => $this->chart_colours['discount_amount'], 'highlight_series' => 1, ); $legend[] = array( /* translators: %s: coupons amount */ 'title' => sprintf( __( '%s coupons used in total', 'woocommerce' ), '<strong>' . $total_coupons . '</strong>' ), 'color' => $this->chart_colours['coupon_count'], 'highlight_series' => 0, ); return $legend; } /** * Output the report. */ public function output_report() { $ranges = array( 'year' => __( 'Year', 'woocommerce' ), 'last_month' => __( 'Last month', 'woocommerce' ), 'month' => __( 'This month', 'woocommerce' ), '7day' => __( 'Last 7 days', 'woocommerce' ), ); $this->chart_colours = array( 'discount_amount' => '#3498db', 'coupon_count' => '#d4d9dc', ); $current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; if ( ! in_array( $current_range, array( 'custom', 'year', 'last_month', 'month', '7day' ) ) ) { $current_range = '7day'; } $this->check_current_range_nonce( $current_range ); $this->calculate_current_range( $current_range ); include WC()->plugin_path() . '/includes/admin/views/html-report-by-date.php'; } /** * Get chart widgets. * * @return array */ public function get_chart_widgets() { $widgets = array(); $widgets[] = array( 'title' => '', 'callback' => array( $this, 'coupons_widget' ), ); return $widgets; } /** * Output coupons widget. */ public function coupons_widget() { ?> <h4 class="section_title"><span><?php esc_html_e( 'Filter by coupon', 'woocommerce' ); ?></span></h4> <div class="section"> <form method="GET"> <div> <?php $used_coupons = $this->get_order_report_data( array( 'data' => array( 'order_item_name' => array( 'type' => 'order_item', 'order_item_type' => 'coupon', 'function' => '', 'distinct' => true, 'name' => 'order_item_name', ), ), 'where' => array( array( 'key' => 'order_item_type', 'value' => 'coupon', 'operator' => '=', ), ), 'query_type' => 'get_col', 'filter_range' => false, ) ); if ( ! empty( $used_coupons ) && is_array( $used_coupons ) ) : ?> <select id="coupon_codes" name="coupon_codes" class="wc-enhanced-select" data-placeholder="<?php esc_attr_e( 'Choose coupons…', 'woocommerce' ); ?>" style="width:100%;"> <option value=""><?php esc_html_e( 'All coupons', 'woocommerce' ); ?></option> <?php foreach ( $used_coupons as $coupon ) { echo '<option value="' . esc_attr( $coupon ) . '"' . wc_selected( $coupon, $this->coupon_codes ) . '>' . esc_html( $coupon ) . '</option>'; } ?> </select> <?php // @codingStandardsIgnoreStart ?> <button type="submit" class="submit button" value="<?php esc_attr_e( 'Show', 'woocommerce' ); ?>"><?php esc_html_e( 'Show', 'woocommerce' ); ?></button> <input type="hidden" name="range" value="<?php echo ( ! empty( $_GET['range'] ) ) ? esc_attr( wp_unslash( $_GET['range'] ) ) : ''; ?>" /> <input type="hidden" name="start_date" value="<?php echo ( ! empty( $_GET['start_date'] ) ) ? esc_attr( wp_unslash( $_GET['start_date'] ) ) : ''; ?>" /> <input type="hidden" name="end_date" value="<?php echo ( ! empty( $_GET['end_date'] ) ) ? esc_attr( wp_unslash( $_GET['end_date'] ) ) : ''; ?>" /> <input type="hidden" name="page" value="<?php echo ( ! empty( $_GET['page'] ) ) ? esc_attr( wp_unslash( $_GET['page'] ) ) : ''; ?>" /> <input type="hidden" name="tab" value="<?php echo ( ! empty( $_GET['tab'] ) ) ? esc_attr( wp_unslash( $_GET['tab'] ) ) : ''; ?>" /> <input type="hidden" name="report" value="<?php echo ( ! empty( $_GET['report'] ) ) ? esc_attr( wp_unslash( $_GET['report'] ) ) : ''; ?>" /> <?php // @codingStandardsIgnoreEnd ?> <?php else : ?> <span><?php esc_html_e( 'No used coupons found', 'woocommerce' ); ?></span> <?php endif; ?> </div> </form> </div> <h4 class="section_title"><span><?php esc_html_e( 'Most popular', 'woocommerce' ); ?></span></h4> <div class="section"> <table cellspacing="0"> <?php $most_popular = $this->get_order_report_data( array( 'data' => array( 'order_item_name' => array( 'type' => 'order_item', 'order_item_type' => 'coupon', 'function' => '', 'name' => 'coupon_code', ), 'order_item_id' => array( 'type' => 'order_item', 'order_item_type' => 'coupon', 'function' => 'COUNT', 'name' => 'coupon_count', ), ), 'where' => array( array( 'type' => 'order_item', 'key' => 'order_item_type', 'value' => 'coupon', 'operator' => '=', ), ), 'order_by' => 'coupon_count DESC', 'group_by' => 'order_item_name', 'limit' => 12, 'query_type' => 'get_results', 'filter_range' => true, ) ); if ( ! empty( $most_popular ) && is_array( $most_popular ) ) { foreach ( $most_popular as $coupon ) { echo '<tr class="' . ( in_array( $coupon->coupon_code, $this->coupon_codes ) ? 'active' : '' ) . '"> <td class="count" width="1%">' . esc_html( $coupon->coupon_count ) . '</td> <td class="name"><a href="' . esc_url( add_query_arg( 'coupon_codes', $coupon->coupon_code ) ) . '">' . esc_html( $coupon->coupon_code ) . '</a></td> </tr>'; } } else { echo '<tr><td colspan="2">' . esc_html__( 'No coupons found in range', 'woocommerce' ) . '</td></tr>'; } ?> </table> </div> <h4 class="section_title"><span><?php esc_html_e( 'Most discount', 'woocommerce' ); ?></span></h4> <div class="section"> <table cellspacing="0"> <?php $most_discount = $this->get_order_report_data( array( 'data' => array( 'order_item_name' => array( 'type' => 'order_item', 'order_item_type' => 'coupon', 'function' => '', 'name' => 'coupon_code', ), 'discount_amount' => array( 'type' => 'order_item_meta', 'order_item_type' => 'coupon', 'function' => 'SUM', 'name' => 'discount_amount', ), ), 'where' => array( array( 'type' => 'order_item', 'key' => 'order_item_type', 'value' => 'coupon', 'operator' => '=', ), ), 'order_by' => 'discount_amount DESC', 'group_by' => 'order_item_name', 'limit' => 12, 'query_type' => 'get_results', 'filter_range' => true, ) ); if ( ! empty( $most_discount ) && is_array( $most_discount ) ) { foreach ( $most_discount as $coupon ) { // @codingStandardsIgnoreStart echo '<tr class="' . ( in_array( $coupon->coupon_code, $this->coupon_codes ) ? 'active' : '' ) . '"> <td class="count" width="1%">' . wc_price( $coupon->discount_amount ) . '</td> <td class="name"><a href="' . esc_url( add_query_arg( 'coupon_codes', $coupon->coupon_code ) ) . '">' . esc_html( $coupon->coupon_code ) . '</a></td> </tr>'; // @codingStandardsIgnoreEnd } } else { echo '<tr><td colspan="3">' . esc_html__( 'No coupons found in range', 'woocommerce' ) . '</td></tr>'; } ?> </table> </div> <script type="text/javascript"> jQuery( '.section_title' ).on( 'click', function() { var next_section = jQuery( this ).next( '.section' ); if ( jQuery( next_section ).is( ':visible' ) ) { return false; } jQuery( '.section:visible' ).slideUp(); jQuery( '.section_title' ).removeClass( 'open' ); jQuery( this ).addClass( 'open' ).next( '.section' ).slideDown(); return false; } ); jQuery( '.section' ).slideUp( 100, function() { <?php if ( empty( $this->coupon_codes ) ) : ?> jQuery( '.section_title:eq(1)' ).trigger( 'click' ); <?php else : ?> jQuery( '.section_title:eq(0)' ).trigger( 'click' ); <?php endif; ?> } ); </script> <?php } /** * Output an export link. */ public function get_export_button() { $current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; ?> <a href="#" download="report-<?php echo esc_attr( $current_range ); ?>-<?php echo esc_attr( date_i18n( 'Y-m-d', current_time( 'timestamp' ) ) ); ?>.csv" class="export_csv" data-export="chart" data-xaxes="<?php esc_attr_e( 'Date', 'woocommerce' ); ?>" data-groupby="<?php echo esc_attr( $this->chart_groupby ); ?>" > <?php esc_html_e( 'Export CSV', 'woocommerce' ); ?> </a> <?php } /** * Get the main chart. */ public function get_main_chart() { global $wp_locale; // Get orders and dates in range - we want the SUM of order totals, COUNT of order items, COUNT of orders, and the date. $order_coupon_counts_query = array( 'data' => array( 'order_item_name' => array( 'type' => 'order_item', 'order_item_type' => 'coupon', 'function' => 'COUNT', 'name' => 'order_coupon_count', ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), ), 'where' => array( array( 'key' => 'order_item_type', 'value' => 'coupon', 'operator' => '=', ), ), 'group_by' => $this->group_by_query, 'order_by' => 'post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, 'order_types' => wc_get_order_types( 'order-count' ), ); $order_discount_amounts_query = array( 'data' => array( 'discount_amount' => array( 'type' => 'order_item_meta', 'order_item_type' => 'coupon', 'function' => 'SUM', 'name' => 'discount_amount', ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), ), 'where' => array( array( 'key' => 'order_item_type', 'value' => 'coupon', 'operator' => '=', ), ), 'group_by' => $this->group_by_query . ', order_item_name', 'order_by' => 'post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, 'order_types' => wc_get_order_types( 'order-count' ), ); if ( ! empty( $this->coupon_codes ) ) { $coupon_code_query = array( 'type' => 'order_item', 'key' => 'order_item_name', 'value' => $this->coupon_codes, 'operator' => 'IN', ); $order_coupon_counts_query['where'][] = $coupon_code_query; $order_discount_amounts_query['where'][] = $coupon_code_query; } $order_coupon_counts = $this->get_order_report_data( $order_coupon_counts_query ); $order_discount_amounts = $this->get_order_report_data( $order_discount_amounts_query ); // Prepare data for report. $order_coupon_counts = $this->prepare_chart_data( $order_coupon_counts, 'post_date', 'order_coupon_count', $this->chart_interval, $this->start_date, $this->chart_groupby ); $order_discount_amounts = $this->prepare_chart_data( $order_discount_amounts, 'post_date', 'discount_amount', $this->chart_interval, $this->start_date, $this->chart_groupby ); // Encode in json format. $chart_data = wp_json_encode( array( 'order_coupon_counts' => array_values( $order_coupon_counts ), 'order_discount_amounts' => array_values( $order_discount_amounts ), ) ); ?> <div class="chart-container"> <div class="chart-placeholder main"></div> </div> <script type="text/javascript"> var main_chart; jQuery(function(){ var order_data = JSON.parse( decodeURIComponent( '<?php echo rawurlencode( $chart_data ); ?>' ) ); var drawGraph = function( highlight ) { var series = [ { label: "<?php echo esc_js( __( 'Number of coupons used', 'woocommerce' ) ); ?>", data: order_data.order_coupon_counts, color: '<?php echo esc_js( $this->chart_colours['coupon_count'] ); ?>', bars: { fillColor: '<?php echo esc_js( $this->chart_colours['coupon_count'] ); ?>', fill: true, show: true, lineWidth: 0, barWidth: <?php echo esc_js( $this->barwidth ); ?> * 0.5, align: 'center' }, shadowSize: 0, hoverable: false }, { label: "<?php echo esc_js( __( 'Discount amount', 'woocommerce' ) ); ?>", data: order_data.order_discount_amounts, yaxis: 2, color: '<?php echo esc_js( $this->chart_colours['discount_amount'] ); ?>', points: { show: true, radius: 5, lineWidth: 3, fillColor: '#fff', fill: true }, lines: { show: true, lineWidth: 4, fill: false }, shadowSize: 0, <?php echo $this->get_currency_tooltip(); ?><?php // @codingStandardsIgnoreLine ?> } ]; if ( highlight !== 'undefined' && series[ highlight ] ) { highlight_series = series[ highlight ]; highlight_series.color = '#9c5d90'; if ( highlight_series.bars ) highlight_series.bars.fillColor = '#9c5d90'; if ( highlight_series.lines ) { highlight_series.lines.lineWidth = 5; } } main_chart = jQuery.plot( jQuery('.chart-placeholder.main'), series, { legend: { show: false }, grid: { color: '#aaa', borderColor: 'transparent', borderWidth: 0, hoverable: true }, xaxes: [ { color: '#aaa', position: "bottom", tickColor: 'transparent', mode: "time", timeformat: "<?php echo ( 'day' === $this->chart_groupby ) ? '%d %b' : '%b'; ?>", monthNames: JSON.parse( decodeURIComponent( '<?php echo rawurlencode( wp_json_encode( array_values( $wp_locale->month_abbrev ) ) ); ?>' ) ), tickLength: 1, minTickSize: [1, "<?php echo esc_js( $this->chart_groupby ); ?>"], font: { color: "#aaa" } } ], yaxes: [ { min: 0, minTickSize: 1, tickDecimals: 0, color: '#ecf0f1', font: { color: "#aaa" } }, { position: "right", min: 0, tickDecimals: 2, alignTicksWithAxis: 1, color: 'transparent', font: { color: "#aaa" } } ], } ); jQuery('.chart-placeholder').trigger( 'resize' ); } drawGraph(); jQuery('.highlight_series').on( 'mouseenter', function() { drawGraph( jQuery(this).data('series') ); } ).on( 'mouseleave', function() { drawGraph(); } ); }); </script> <?php } } class-wc-report-taxes-by-code.php 0000644 00000020111 15134216707 0012745 0 ustar 00 <?php /** * Taxes by tax code report. * * @package WooCommerce\Admin\Reports */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * WC_Report_Taxes_By_Code * * @package WooCommerce\Admin\Reports * @version 2.1.0 */ class WC_Report_Taxes_By_Code extends WC_Admin_Report { /** * Get the legend for the main chart sidebar. * * @return array */ public function get_chart_legend() { return array(); } /** * Output an export link. */ public function get_export_button() { $current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : 'last_month'; ?> <a href="#" download="report-<?php echo esc_attr( $current_range ); ?>-<?php echo esc_attr( date_i18n( 'Y-m-d', current_time( 'timestamp' ) ) ); ?>.csv" class="export_csv" data-export="table" > <?php esc_html_e( 'Export CSV', 'woocommerce' ); ?> </a> <?php } /** * Output the report. */ public function output_report() { $ranges = array( 'year' => __( 'Year', 'woocommerce' ), 'last_month' => __( 'Last month', 'woocommerce' ), 'month' => __( 'This month', 'woocommerce' ), ); $current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : 'last_month'; if ( ! in_array( $current_range, array( 'custom', 'year', 'last_month', 'month', '7day' ) ) ) { $current_range = 'last_month'; } $this->check_current_range_nonce( $current_range ); $this->calculate_current_range( $current_range ); $hide_sidebar = true; include WC()->plugin_path() . '/includes/admin/views/html-report-by-date.php'; } /** * Get the main chart. */ public function get_main_chart() { global $wpdb; $query_data = array( 'order_item_name' => array( 'type' => 'order_item', 'function' => '', 'name' => 'tax_rate', ), 'tax_amount' => array( 'type' => 'order_item_meta', 'order_item_type' => 'tax', 'function' => '', 'name' => 'tax_amount', ), 'shipping_tax_amount' => array( 'type' => 'order_item_meta', 'order_item_type' => 'tax', 'function' => '', 'name' => 'shipping_tax_amount', ), 'rate_id' => array( 'type' => 'order_item_meta', 'order_item_type' => 'tax', 'function' => '', 'name' => 'rate_id', ), 'ID' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_id', ), ); $query_where = array( array( 'key' => 'order_item_type', 'value' => 'tax', 'operator' => '=', ), array( 'key' => 'order_item_name', 'value' => '', 'operator' => '!=', ), ); // We exclude on-hold orders as they are still pending payment. $tax_rows_orders = $this->get_order_report_data( array( 'data' => $query_data, 'where' => $query_where, 'order_by' => 'posts.post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, 'order_types' => wc_get_order_types( 'sales-reports' ), 'order_status' => array( 'completed', 'processing', 'refunded' ), ) ); $tax_rows_partial_refunds = $this->get_order_report_data( array( 'data' => $query_data, 'where' => $query_where, 'order_by' => 'posts.post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, 'order_types' => array( 'shop_order_refund' ), 'parent_order_status' => array( 'completed', 'processing' ), // Partial refunds inside refunded orders should be ignored. ) ); $tax_rows_full_refunds = $this->get_order_report_data( array( 'data' => $query_data, 'where' => $query_where, 'order_by' => 'posts.post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, 'order_types' => array( 'shop_order_refund' ), 'parent_order_status' => array( 'refunded' ), ) ); // Merge. $tax_rows = array(); foreach ( $tax_rows_orders + $tax_rows_partial_refunds as $tax_row ) { $key = $tax_row->rate_id; $tax_rows[ $key ] = isset( $tax_rows[ $key ] ) ? $tax_rows[ $key ] : (object) array( 'tax_amount' => 0, 'shipping_tax_amount' => 0, 'total_orders' => 0, ); $tax_rows[ $key ]->total_orders += 1; $tax_rows[ $key ]->tax_rate = $tax_row->tax_rate; $tax_rows[ $key ]->tax_amount += wc_round_tax_total( $tax_row->tax_amount ); $tax_rows[ $key ]->shipping_tax_amount += wc_round_tax_total( $tax_row->shipping_tax_amount ); } foreach ( $tax_rows_full_refunds as $tax_row ) { $key = $tax_row->rate_id; $tax_rows[ $key ] = isset( $tax_rows[ $key ] ) ? $tax_rows[ $key ] : (object) array( 'tax_amount' => 0, 'shipping_tax_amount' => 0, 'total_orders' => 0, ); $tax_rows[ $key ]->tax_rate = $tax_row->tax_rate; $tax_rows[ $key ]->tax_amount += wc_round_tax_total( $tax_row->tax_amount ); $tax_rows[ $key ]->shipping_tax_amount += wc_round_tax_total( $tax_row->shipping_tax_amount ); } ?> <table class="widefat"> <thead> <tr> <th><?php esc_html_e( 'Tax', 'woocommerce' ); ?></th> <th><?php esc_html_e( 'Rate', 'woocommerce' ); ?></th> <th class="total_row"><?php esc_html_e( 'Number of orders', 'woocommerce' ); ?></th> <th class="total_row"><?php esc_html_e( 'Tax amount', 'woocommerce' ); ?> <?php echo wc_help_tip( __( 'This is the sum of the "Tax rows" tax amount within your orders.', 'woocommerce' ) ); ?></th> <th class="total_row"><?php esc_html_e( 'Shipping tax amount', 'woocommerce' ); ?> <?php echo wc_help_tip( __( 'This is the sum of the "Tax rows" shipping tax amount within your orders.', 'woocommerce' ) ); ?></th> <th class="total_row"><?php esc_html_e( 'Total tax', 'woocommerce' ); ?> <?php echo wc_help_tip( __( 'This is the total tax for the rate (shipping tax + product tax).', 'woocommerce' ) ); ?></th> </tr> </thead> <?php if ( ! empty( $tax_rows ) ) : ?> <tbody> <?php foreach ( $tax_rows as $rate_id => $tax_row ) { $rate = $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %d;", $rate_id ) ); ?> <tr> <th scope="row"><?php echo wp_kses_post( apply_filters( 'woocommerce_reports_taxes_tax_rate', $tax_row->tax_rate, $rate_id, $tax_row ) ); ?></th> <td><?php echo wp_kses_post( apply_filters( 'woocommerce_reports_taxes_rate', $rate, $rate_id, $tax_row ) ); ?>%</td> <td class="total_row"><?php echo esc_html( $tax_row->total_orders ); ?></td> <td class="total_row"><?php echo wc_price( $tax_row->tax_amount ); // phpcs:ignore ?></td> <td class="total_row"><?php echo wc_price( $tax_row->shipping_tax_amount ); // phpcs:ignore ?></td> <td class="total_row"><?php echo wc_price( $tax_row->tax_amount + $tax_row->shipping_tax_amount ); // phpcs:ignore ?></td> </tr> <?php } ?> </tbody> <tfoot> <tr> <th scope="row" colspan="3"><?php esc_html_e( 'Total', 'woocommerce' ); ?></th> <th class="total_row"><?php echo wc_price( wc_round_tax_total( array_sum( wp_list_pluck( (array) $tax_rows, 'tax_amount' ) ) ) ); // phpcs:ignore ?></th> <th class="total_row"><?php echo wc_price( wc_round_tax_total( array_sum( wp_list_pluck( (array) $tax_rows, 'shipping_tax_amount' ) ) ) ); // phpcs:ignore ?></th> <th class="total_row"><strong><?php echo wc_price( wc_round_tax_total( array_sum( wp_list_pluck( (array) $tax_rows, 'tax_amount' ) ) + array_sum( wp_list_pluck( (array) $tax_rows, 'shipping_tax_amount' ) ) ) ); // phpcs:ignore ?></strong></th> </tr> </tfoot> <?php else : ?> <tbody> <tr> <td><?php esc_html_e( 'No taxes found in this period', 'woocommerce' ); ?></td> </tr> </tbody> <?php endif; ?> </table> <?php } } class-wc-report-out-of-stock.php 0000644 00000003173 15134216707 0012644 0 ustar 00 <?php /** * WC_Report_Out_Of_Stock. * * @package WooCommerce\Admin\Reports */ defined( 'ABSPATH' ) || exit; if ( ! class_exists( 'WC_Report_Stock' ) ) { require_once dirname( __FILE__ ) . '/class-wc-report-stock.php'; } /** * WC_Report_Out_Of_Stock class. */ class WC_Report_Out_Of_Stock extends WC_Report_Stock { /** * No items found text. */ public function no_items() { esc_html_e( 'No out of stock products found.', 'woocommerce' ); } /** * Get Products matching stock criteria. * * @param int $current_page Current page number. * @param int $per_page How many results to show per page. */ public function get_items( $current_page, $per_page ) { global $wpdb; $this->max_items = 0; $this->items = array(); $stock = absint( max( get_option( 'woocommerce_notify_no_stock_amount' ), 0 ) ); $query_from = apply_filters( 'woocommerce_report_out_of_stock_query_from', $wpdb->prepare( " FROM {$wpdb->posts} as posts INNER JOIN {$wpdb->wc_product_meta_lookup} AS lookup ON posts.ID = lookup.product_id WHERE 1=1 AND posts.post_type IN ( 'product', 'product_variation' ) AND posts.post_status = 'publish' AND lookup.stock_quantity <= %d ", $stock ) ); $this->items = $wpdb->get_results( $wpdb->prepare( "SELECT SQL_CALC_FOUND_ROWS posts.ID as id, posts.post_parent as parent {$query_from} ORDER BY posts.post_title DESC LIMIT %d, %d;", ( $current_page - 1 ) * $per_page, $per_page ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $this->max_items = $wpdb->get_var( 'SELECT FOUND_ROWS();' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } } class-wc-report-downloads.php 0000644 00000024720 15134216707 0012305 0 ustar 00 <?php /** * Download report. * * @author WooThemes * @category Admin * @package WooCommerce\Admin\Reports * @version 3.3.0 */ if ( ! defined( 'ABSPATH' ) ) { exit; } if ( ! class_exists( 'WP_List_Table' ) ) { require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php'; } /** * WC_Report_Downloads. */ class WC_Report_Downloads extends WP_List_Table { /** * Max items. * * @var int */ protected $max_items; /** * Constructor. */ public function __construct() { parent::__construct( array( 'singular' => 'download', 'plural' => 'downloads', 'ajax' => false, ) ); } /** * Don't need this. * * @param string $position Top or bottom. */ public function display_tablenav( $position ) { if ( 'top' !== $position ) { parent::display_tablenav( $position ); } } /** * Output the report. */ public function output_report() { $this->prepare_items(); // Subtitle for permission if set. if ( ! empty( $_GET['permission_id'] ) ) { // WPCS: input var ok. $permission_id = absint( $_GET['permission_id'] ); // WPCS: input var ok. // Load the permission, order, etc. so we can render more information. $permission = null; $product = null; try { $permission = new WC_Customer_Download( $permission_id ); $product = wc_get_product( $permission->product_id ); } catch ( Exception $e ) { wp_die( sprintf( esc_html__( 'Permission #%d not found.', 'woocommerce' ), esc_html( $permission_id ) ) ); } } echo '<h1>' . esc_html__( 'Customer downloads', 'woocommerce' ); $filters = $this->get_filter_vars(); $filter_list = array(); $filter_names = array( 'product_id' => __( 'Product', 'woocommerce' ), 'download_id' => __( 'File ID', 'woocommerce' ), 'permission_id' => __( 'Permission ID', 'woocommerce' ), 'order_id' => __( 'Order', 'woocommerce' ), 'user_id' => __( 'User', 'woocommerce' ), 'user_ip_address' => __( 'IP address', 'woocommerce' ), ); foreach ( $filters as $key => $value ) { if ( is_null( $value ) ) { continue; } switch ( $key ) { case 'order_id': $order = wc_get_order( $value ); if ( $order ) { $display_value = _x( '#', 'hash before order number', 'woocommerce' ) . $order->get_order_number(); } else { break 2; } break; case 'product_id': $product = wc_get_product( $value ); if ( $product ) { $display_value = $product->get_formatted_name(); } else { break 2; } break; default: $display_value = $value; break; } $filter_list[] = $filter_names[ $key ] . ' ' . $display_value . ' <a href="' . esc_url( remove_query_arg( $key ) ) . '" class="woocommerce-reports-remove-filter">×</a>'; } echo '</h1>'; echo '<div id="active-filters" class="woocommerce-reports-wide"><h2>'; echo esc_html__( 'Active filters', 'woocommerce' ) . ': '; echo $filter_list ? wp_kses_post( implode( ', ', $filter_list ) ) : ''; echo '</h2></div>'; echo '<div id="poststuff" class="woocommerce-reports-wide">'; $this->display(); echo '</div>'; } /** * Get column value. * * @param mixed $item Item being displayed. * @param string $column_name Column name. */ public function column_default( $item, $column_name ) { $permission = null; $product = null; try { $permission = new WC_Customer_Download( $item->permission_id ); $product = wc_get_product( $permission->product_id ); } catch ( Exception $e ) { // Ok to continue rendering other information even if permission and/or product is not found. return; } switch ( $column_name ) { case 'timestamp': echo esc_html( $item->timestamp ); break; case 'product': if ( ! empty( $product ) ) { edit_post_link( esc_html( $product->get_formatted_name() ), '', '', $product->get_id(), 'view-link' ); echo '<div class="row-actions">'; echo '<a href="' . esc_url( add_query_arg( 'product_id', $product->get_id() ) ) . '">' . esc_html__( 'Filter by product', 'woocommerce' ) . '</a>'; echo '</div>'; } break; case 'file': if ( ! empty( $permission ) && ! empty( $product ) ) { // File information. $file = $product->get_file( $permission->get_download_id() ); if ( false === $file ) { echo esc_html__( 'File does not exist', 'woocommerce' ); } else { echo esc_html( $file->get_name() . ' - ' . basename( $file->get_file() ) ); echo '<div class="row-actions">'; echo '<a href="' . esc_url( add_query_arg( 'download_id', $permission->get_download_id() ) ) . '">' . esc_html__( 'Filter by file', 'woocommerce' ) . '</a>'; echo '</div>'; } } break; case 'order': if ( ! empty( $permission ) && ( $order = wc_get_order( $permission->order_id ) ) ) { edit_post_link( esc_html( _x( '#', 'hash before order number', 'woocommerce' ) . $order->get_order_number() ), '', '', $permission->order_id, 'view-link' ); echo '<div class="row-actions">'; echo '<a href="' . esc_url( add_query_arg( 'order_id', $order->get_id() ) ) . '">' . esc_html__( 'Filter by order', 'woocommerce' ) . '</a>'; echo '</div>'; } break; case 'user': if ( $item->user_id > 0 ) { $user = get_user_by( 'id', $item->user_id ); if ( ! empty( $user ) ) { echo '<a href="' . esc_url( get_edit_user_link( $item->user_id ) ) . '">' . esc_html( $user->display_name ) . '</a>'; echo '<div class="row-actions">'; echo '<a href="' . esc_url( add_query_arg( 'user_id', $item->user_id ) ) . '">' . esc_html__( 'Filter by user', 'woocommerce' ) . '</a>'; echo '</div>'; } } else { esc_html_e( 'Guest', 'woocommerce' ); } break; case 'user_ip_address': echo esc_html( $item->user_ip_address ); echo '<div class="row-actions">'; echo '<a href="' . esc_url( add_query_arg( 'user_ip_address', $item->user_ip_address ) ) . '">' . esc_html__( 'Filter by IP address', 'woocommerce' ) . '</a>'; echo '</div>'; break; } } /** * Get columns. * * @return array */ public function get_columns() { $columns = array( 'timestamp' => __( 'Timestamp', 'woocommerce' ), 'product' => __( 'Product', 'woocommerce' ), 'file' => __( 'File', 'woocommerce' ), 'order' => __( 'Order', 'woocommerce' ), 'user' => __( 'User', 'woocommerce' ), 'user_ip_address' => __( 'IP address', 'woocommerce' ), ); return $columns; } /** * Prepare download list items. */ public function prepare_items() { $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() ); $current_page = absint( $this->get_pagenum() ); // Allow filtering per_page value, but ensure it's at least 1. $per_page = max( 1, apply_filters( 'woocommerce_admin_downloads_report_downloads_per_page', 20 ) ); $this->get_items( $current_page, $per_page ); /** * Pagination. */ $this->set_pagination_args( array( 'total_items' => $this->max_items, 'per_page' => $per_page, 'total_pages' => ceil( $this->max_items / $per_page ), ) ); } /** * No items found text. */ public function no_items() { esc_html_e( 'No customer downloads found.', 'woocommerce' ); } /** * Get filters from querystring. * * @return object */ protected function get_filter_vars() { $product_id = ! empty( $_GET['product_id'] ) ? absint( wp_unslash( $_GET['product_id'] ) ) : null; // WPCS: input var ok. $download_id = ! empty( $_GET['download_id'] ) ? wc_clean( wp_unslash( $_GET['download_id'] ) ) : null; // WPCS: input var ok. $permission_id = ! empty( $_GET['permission_id'] ) ? absint( wp_unslash( $_GET['permission_id'] ) ) : null; // WPCS: input var ok. $order_id = ! empty( $_GET['order_id'] ) ? absint( wp_unslash( $_GET['order_id'] ) ) : null; // WPCS: input var ok. $user_id = ! empty( $_GET['user_id'] ) ? absint( wp_unslash( $_GET['user_id'] ) ) : null; // WPCS: input var ok. $user_ip_address = ! empty( $_GET['user_ip_address'] ) ? wc_clean( wp_unslash( $_GET['user_ip_address'] ) ) : null; // WPCS: input var ok. return (object) array( 'product_id' => $product_id, 'download_id' => $download_id, 'permission_id' => $permission_id, 'order_id' => $order_id, 'user_id' => $user_id, 'user_ip_address' => $user_ip_address, ); } /** * Get downloads matching criteria. * * @param int $current_page Current viewed page. * @param int $per_page How many results to show per page. */ public function get_items( $current_page, $per_page ) { global $wpdb; $this->max_items = 0; $this->items = array(); $filters = $this->get_filter_vars(); // Get downloads from database. $table = $wpdb->prefix . WC_Customer_Download_Log_Data_Store::get_table_name(); $query_from = " FROM {$table} as downloads "; if ( ! is_null( $filters->product_id ) || ! is_null( $filters->download_id ) || ! is_null( $filters->order_id ) ) { $query_from .= " LEFT JOIN {$wpdb->prefix}woocommerce_downloadable_product_permissions as permissions on downloads.permission_id = permissions.permission_id "; } $query_from .= ' WHERE 1=1 '; if ( ! is_null( $filters->product_id ) ) { $query_from .= $wpdb->prepare( ' AND product_id = %d ', $filters->product_id ); } if ( ! is_null( $filters->download_id ) ) { $query_from .= $wpdb->prepare( ' AND download_id = %s ', $filters->download_id ); } if ( ! is_null( $filters->order_id ) ) { $query_from .= $wpdb->prepare( ' AND order_id = %d ', $filters->order_id ); } if ( ! is_null( $filters->permission_id ) ) { $query_from .= $wpdb->prepare( ' AND downloads.permission_id = %d ', $filters->permission_id ); } if ( ! is_null( $filters->user_id ) ) { $query_from .= $wpdb->prepare( ' AND downloads.user_id = %d ', $filters->user_id ); } if ( ! is_null( $filters->user_ip_address ) ) { $query_from .= $wpdb->prepare( ' AND user_ip_address = %s ', $filters->user_ip_address ); } $query_from = apply_filters( 'woocommerce_report_downloads_query_from', $query_from ); $query_order = $wpdb->prepare( 'ORDER BY timestamp DESC LIMIT %d, %d;', ( $current_page - 1 ) * $per_page, $per_page ); $this->items = $wpdb->get_results( "SELECT * {$query_from} {$query_order}" ); // WPCS: cache ok, db call ok, unprepared SQL ok. $this->max_items = $wpdb->get_var( "SELECT COUNT( DISTINCT download_log_id ) {$query_from};" ); // WPCS: cache ok, db call ok, unprepared SQL ok. } } class-wc-report-sales-by-date.php 0000644 00000076512 15134216707 0012753 0 ustar 00 <?php /** * WC_Report_Sales_By_Date * * @package WooCommerce\Admin\Reports * @version 2.1.0 */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * WC_Report_Sales_By_Date */ class WC_Report_Sales_By_Date extends WC_Admin_Report { /** * Chart colors. * * @var array */ public $chart_colours = array(); /** * The report data. * * @var stdClass */ private $report_data; /** * Get report data. * * @return stdClass */ public function get_report_data() { if ( empty( $this->report_data ) ) { $this->query_report_data(); } return $this->report_data; } /** * Get all data needed for this report and store in the class. */ private function query_report_data() { $this->report_data = new stdClass(); $this->report_data->order_counts = (array) $this->get_order_report_data( array( 'data' => array( 'ID' => array( 'type' => 'post_data', 'function' => 'COUNT', 'name' => 'count', 'distinct' => true, ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), ), 'group_by' => $this->group_by_query, 'order_by' => 'post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, 'order_types' => wc_get_order_types( 'order-count' ), 'order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ), ) ); $this->report_data->coupons = (array) $this->get_order_report_data( array( 'data' => array( 'order_item_name' => array( 'type' => 'order_item', 'function' => '', 'name' => 'order_item_name', ), 'discount_amount' => array( 'type' => 'order_item_meta', 'order_item_type' => 'coupon', 'function' => 'SUM', 'name' => 'discount_amount', ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), ), 'where' => array( array( 'key' => 'order_items.order_item_type', 'value' => 'coupon', 'operator' => '=', ), ), 'group_by' => $this->group_by_query . ', order_item_name', 'order_by' => 'post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, 'order_types' => wc_get_order_types( 'order-count' ), 'order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ), ) ); // All items from orders - even those refunded. $this->report_data->order_items = (array) $this->get_order_report_data( array( 'data' => array( '_qty' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => 'SUM', 'name' => 'order_item_count', ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), ), 'where' => array( array( 'key' => 'order_items.order_item_type', 'value' => 'line_item', 'operator' => '=', ), ), 'group_by' => $this->group_by_query, 'order_by' => 'post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, 'order_types' => wc_get_order_types( 'order-count' ), 'order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ), ) ); /** * Get total of fully refunded items. */ $this->report_data->refunded_order_items = absint( $this->get_order_report_data( array( 'data' => array( '_qty' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => 'SUM', 'name' => 'order_item_count', ), ), 'where' => array( array( 'key' => 'order_items.order_item_type', 'value' => 'line_item', 'operator' => '=', ), ), 'query_type' => 'get_var', 'filter_range' => true, 'order_types' => wc_get_order_types( 'order-count' ), 'order_status' => array( 'refunded' ), ) ) ); /** * Order totals by date. Charts should show GROSS amounts to avoid going -ve. */ $this->report_data->orders = (array) $this->get_order_report_data( array( 'data' => array( '_order_total' => array( 'type' => 'meta', 'function' => 'SUM', 'name' => 'total_sales', ), '_order_shipping' => array( 'type' => 'meta', 'function' => 'SUM', 'name' => 'total_shipping', ), '_order_tax' => array( 'type' => 'meta', 'function' => 'SUM', 'name' => 'total_tax', ), '_order_shipping_tax' => array( 'type' => 'meta', 'function' => 'SUM', 'name' => 'total_shipping_tax', ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), ), 'group_by' => $this->group_by_query, 'order_by' => 'post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, 'order_types' => wc_get_order_types( 'sales-reports' ), 'order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ), ) ); /** * If an order is 100% refunded we should look at the parent's totals, but the refunds dates. * We also need to ensure each parent order's values are only counted/summed once. */ $this->report_data->full_refunds = (array) $this->get_order_report_data( array( 'data' => array( '_order_total' => array( 'type' => 'parent_meta', 'function' => '', 'name' => 'total_refund', ), '_order_shipping' => array( 'type' => 'parent_meta', 'function' => '', 'name' => 'total_shipping', ), '_order_tax' => array( 'type' => 'parent_meta', 'function' => '', 'name' => 'total_tax', ), '_order_shipping_tax' => array( 'type' => 'parent_meta', 'function' => '', 'name' => 'total_shipping_tax', ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), ), 'group_by' => 'posts.post_parent', 'query_type' => 'get_results', 'filter_range' => true, 'order_status' => false, 'parent_order_status' => array( 'refunded' ), ) ); foreach ( $this->report_data->full_refunds as $key => $order ) { $total_refund = is_numeric( $order->total_refund ) ? $order->total_refund : 0; $total_shipping = is_numeric( $order->total_shipping ) ? $order->total_shipping : 0; $total_tax = is_numeric( $order->total_tax ) ? $order->total_tax : 0; $total_shipping_tax = is_numeric( $order->total_shipping_tax ) ? $order->total_shipping_tax : 0; $this->report_data->full_refunds[ $key ]->net_refund = $total_refund - ( $total_shipping + $total_tax + $total_shipping_tax ); } /** * Partial refunds. This includes line items, shipping and taxes. Not grouped by date. */ $this->report_data->partial_refunds = (array) $this->get_order_report_data( array( 'data' => array( 'ID' => array( 'type' => 'post_data', 'function' => '', 'name' => 'refund_id', ), '_refund_amount' => array( 'type' => 'meta', 'function' => '', 'name' => 'total_refund', ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), 'order_item_type' => array( 'type' => 'order_item', 'function' => '', 'name' => 'item_type', 'join_type' => 'LEFT', ), '_order_total' => array( 'type' => 'meta', 'function' => '', 'name' => 'total_sales', ), '_order_shipping' => array( 'type' => 'meta', 'function' => '', 'name' => 'total_shipping', 'join_type' => 'LEFT', ), '_order_tax' => array( 'type' => 'meta', 'function' => '', 'name' => 'total_tax', 'join_type' => 'LEFT', ), '_order_shipping_tax' => array( 'type' => 'meta', 'function' => '', 'name' => 'total_shipping_tax', 'join_type' => 'LEFT', ), '_qty' => array( 'type' => 'order_item_meta', 'function' => 'SUM', 'name' => 'order_item_count', 'join_type' => 'LEFT', ), ), 'group_by' => 'refund_id', 'order_by' => 'post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, 'order_status' => false, 'parent_order_status' => array( 'completed', 'processing', 'on-hold' ), ) ); foreach ( $this->report_data->partial_refunds as $key => $order ) { $this->report_data->partial_refunds[ $key ]->net_refund = $order->total_refund - ( $order->total_shipping + $order->total_tax + $order->total_shipping_tax ); } /** * Refund lines - all partial refunds on all order types so we can plot full AND partial refunds on the chart. */ $this->report_data->refund_lines = (array) $this->get_order_report_data( array( 'data' => array( 'ID' => array( 'type' => 'post_data', 'function' => '', 'name' => 'refund_id', ), '_refund_amount' => array( 'type' => 'meta', 'function' => '', 'name' => 'total_refund', ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), 'order_item_type' => array( 'type' => 'order_item', 'function' => '', 'name' => 'item_type', 'join_type' => 'LEFT', ), '_order_total' => array( 'type' => 'meta', 'function' => '', 'name' => 'total_sales', ), '_order_shipping' => array( 'type' => 'meta', 'function' => '', 'name' => 'total_shipping', 'join_type' => 'LEFT', ), '_order_tax' => array( 'type' => 'meta', 'function' => '', 'name' => 'total_tax', 'join_type' => 'LEFT', ), '_order_shipping_tax' => array( 'type' => 'meta', 'function' => '', 'name' => 'total_shipping_tax', 'join_type' => 'LEFT', ), '_qty' => array( 'type' => 'order_item_meta', 'function' => 'SUM', 'name' => 'order_item_count', 'join_type' => 'LEFT', ), ), 'group_by' => 'refund_id', 'order_by' => 'post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, 'order_status' => false, 'parent_order_status' => array( 'completed', 'processing', 'on-hold', 'refunded' ), ) ); /** * Total up refunds. Note: when an order is fully refunded, a refund line will be added. */ $this->report_data->total_tax_refunded = 0; $this->report_data->total_shipping_refunded = 0; $this->report_data->total_shipping_tax_refunded = 0; $this->report_data->total_refunds = 0; $this->report_data->refunded_orders = array_merge( $this->report_data->partial_refunds, $this->report_data->full_refunds ); foreach ( $this->report_data->refunded_orders as $key => $value ) { $this->report_data->total_tax_refunded += floatval( $value->total_tax < 0 ? $value->total_tax * -1 : $value->total_tax ); $this->report_data->total_refunds += floatval( $value->total_refund ); $this->report_data->total_shipping_tax_refunded += floatval( $value->total_shipping_tax < 0 ? $value->total_shipping_tax * -1 : $value->total_shipping_tax ); $this->report_data->total_shipping_refunded += floatval( $value->total_shipping < 0 ? $value->total_shipping * -1 : $value->total_shipping ); // Only applies to parial. if ( isset( $value->order_item_count ) ) { $this->report_data->refunded_order_items += floatval( $value->order_item_count < 0 ? $value->order_item_count * -1 : $value->order_item_count ); } } // Totals from all orders - including those refunded. Subtract refunded amounts. $this->report_data->total_tax = wc_format_decimal( array_sum( wp_list_pluck( $this->report_data->orders, 'total_tax' ) ) - $this->report_data->total_tax_refunded, 2 ); $this->report_data->total_shipping = wc_format_decimal( array_sum( wp_list_pluck( $this->report_data->orders, 'total_shipping' ) ) - $this->report_data->total_shipping_refunded, 2 ); $this->report_data->total_shipping_tax = wc_format_decimal( array_sum( wp_list_pluck( $this->report_data->orders, 'total_shipping_tax' ) ) - $this->report_data->total_shipping_tax_refunded, 2 ); // Total the refunds and sales amounts. Sales subract refunds. Note - total_sales also includes shipping costs. $this->report_data->total_sales = wc_format_decimal( array_sum( wp_list_pluck( $this->report_data->orders, 'total_sales' ) ) - $this->report_data->total_refunds, 2 ); $this->report_data->net_sales = wc_format_decimal( $this->report_data->total_sales - $this->report_data->total_shipping - max( 0, $this->report_data->total_tax ) - max( 0, $this->report_data->total_shipping_tax ), 2 ); // Calculate average based on net. $this->report_data->average_sales = wc_format_decimal( $this->report_data->net_sales / ( $this->chart_interval + 1 ), 2 ); $this->report_data->average_total_sales = wc_format_decimal( $this->report_data->total_sales / ( $this->chart_interval + 1 ), 2 ); // Total orders and discounts also includes those which have been refunded at some point. $this->report_data->total_coupons = number_format( array_sum( wp_list_pluck( $this->report_data->coupons, 'discount_amount' ) ), 2, '.', '' ); $this->report_data->total_refunded_orders = absint( count( $this->report_data->full_refunds ) ); // Total orders in this period, even if refunded. $this->report_data->total_orders = absint( array_sum( wp_list_pluck( $this->report_data->order_counts, 'count' ) ) ); // Item items ordered in this period, even if refunded. $this->report_data->total_items = absint( array_sum( wp_list_pluck( $this->report_data->order_items, 'order_item_count' ) ) ); // 3rd party filtering of report data $this->report_data = apply_filters( 'woocommerce_admin_report_data', $this->report_data ); } /** * Get the legend for the main chart sidebar. * * @return array */ public function get_chart_legend() { $legend = array(); $data = $this->get_report_data(); switch ( $this->chart_groupby ) { case 'day': $average_total_sales_title = sprintf( /* translators: %s: average total sales */ __( '%s average gross daily sales', 'woocommerce' ), '<strong>' . wc_price( $data->average_total_sales ) . '</strong>' ); $average_sales_title = sprintf( /* translators: %s: average sales */ __( '%s average net daily sales', 'woocommerce' ), '<strong>' . wc_price( $data->average_sales ) . '</strong>' ); break; case 'month': default: $average_total_sales_title = sprintf( /* translators: %s: average total sales */ __( '%s average gross monthly sales', 'woocommerce' ), '<strong>' . wc_price( $data->average_total_sales ) . '</strong>' ); $average_sales_title = sprintf( /* translators: %s: average sales */ __( '%s average net monthly sales', 'woocommerce' ), '<strong>' . wc_price( $data->average_sales ) . '</strong>' ); break; } $legend[] = array( 'title' => sprintf( /* translators: %s: total sales */ __( '%s gross sales in this period', 'woocommerce' ), '<strong>' . wc_price( $data->total_sales ) . '</strong>' ), 'placeholder' => __( 'This is the sum of the order totals after any refunds and including shipping and taxes.', 'woocommerce' ), 'color' => $this->chart_colours['sales_amount'], 'highlight_series' => 6, ); if ( $data->average_total_sales > 0 ) { $legend[] = array( 'title' => $average_total_sales_title, 'color' => $this->chart_colours['average'], 'highlight_series' => 2, ); } $legend[] = array( 'title' => sprintf( /* translators: %s: net sales */ __( '%s net sales in this period', 'woocommerce' ), '<strong>' . wc_price( $data->net_sales ) . '</strong>' ), 'placeholder' => __( 'This is the sum of the order totals after any refunds and excluding shipping and taxes.', 'woocommerce' ), 'color' => $this->chart_colours['net_sales_amount'], 'highlight_series' => 7, ); if ( $data->average_sales > 0 ) { $legend[] = array( 'title' => $average_sales_title, 'color' => $this->chart_colours['net_average'], 'highlight_series' => 3, ); } $legend[] = array( 'title' => sprintf( /* translators: %s: total orders */ __( '%s orders placed', 'woocommerce' ), '<strong>' . $data->total_orders . '</strong>' ), 'color' => $this->chart_colours['order_count'], 'highlight_series' => 1, ); $legend[] = array( 'title' => sprintf( /* translators: %s: total items */ __( '%s items purchased', 'woocommerce' ), '<strong>' . $data->total_items . '</strong>' ), 'color' => $this->chart_colours['item_count'], 'highlight_series' => 0, ); $legend[] = array( 'title' => sprintf( /* translators: 1: total refunds 2: total refunded orders 3: refunded items */ _n( '%1$s refunded %2$d order (%3$d item)', '%1$s refunded %2$d orders (%3$d items)', $this->report_data->total_refunded_orders, 'woocommerce' ), '<strong>' . wc_price( $data->total_refunds ) . '</strong>', $this->report_data->total_refunded_orders, $this->report_data->refunded_order_items ), 'color' => $this->chart_colours['refund_amount'], 'highlight_series' => 8, ); $legend[] = array( 'title' => sprintf( /* translators: %s: total shipping */ __( '%s charged for shipping', 'woocommerce' ), '<strong>' . wc_price( $data->total_shipping ) . '</strong>' ), 'color' => $this->chart_colours['shipping_amount'], 'highlight_series' => 5, ); $legend[] = array( 'title' => sprintf( /* translators: %s: total coupons */ __( '%s worth of coupons used', 'woocommerce' ), '<strong>' . wc_price( $data->total_coupons ) . '</strong>' ), 'color' => $this->chart_colours['coupon_amount'], 'highlight_series' => 4, ); return $legend; } /** * Output the report. */ public function output_report() { $ranges = array( 'year' => __( 'Year', 'woocommerce' ), 'last_month' => __( 'Last month', 'woocommerce' ), 'month' => __( 'This month', 'woocommerce' ), '7day' => __( 'Last 7 days', 'woocommerce' ), ); $this->chart_colours = array( 'sales_amount' => '#b1d4ea', 'net_sales_amount' => '#3498db', 'average' => '#b1d4ea', 'net_average' => '#3498db', 'order_count' => '#dbe1e3', 'item_count' => '#ecf0f1', 'shipping_amount' => '#5cc488', 'coupon_amount' => '#f1c40f', 'refund_amount' => '#e74c3c', ); $current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( ! in_array( $current_range, array( 'custom', 'year', 'last_month', 'month', '7day' ), true ) ) { $current_range = '7day'; } $this->check_current_range_nonce( $current_range ); $this->calculate_current_range( $current_range ); include WC()->plugin_path() . '/includes/admin/views/html-report-by-date.php'; } /** * Output an export link. */ public function get_export_button() { $current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?> <a href="#" download="report-<?php echo esc_attr( $current_range ); ?>-<?php echo esc_attr( date_i18n( 'Y-m-d', current_time( 'timestamp' ) ) ); ?>.csv" class="export_csv" data-export="chart" data-xaxes="<?php esc_attr_e( 'Date', 'woocommerce' ); ?>" data-exclude_series="2" data-groupby="<?php echo esc_attr( $this->chart_groupby ); ?>" > <?php esc_html_e( 'Export CSV', 'woocommerce' ); ?> </a> <?php } /** * Round our totals correctly. * * @param array|string $amount Chart total. * * @return array|string */ private function round_chart_totals( $amount ) { if ( is_array( $amount ) ) { return array( $amount[0], wc_format_decimal( $amount[1], wc_get_price_decimals() ) ); } else { return wc_format_decimal( $amount, wc_get_price_decimals() ); } } /** * Get the main chart. */ public function get_main_chart() { global $wp_locale; // Prepare data for report. $data = array( 'order_counts' => $this->prepare_chart_data( $this->report_data->order_counts, 'post_date', 'count', $this->chart_interval, $this->start_date, $this->chart_groupby ), 'order_item_counts' => $this->prepare_chart_data( $this->report_data->order_items, 'post_date', 'order_item_count', $this->chart_interval, $this->start_date, $this->chart_groupby ), 'order_amounts' => $this->prepare_chart_data( $this->report_data->orders, 'post_date', 'total_sales', $this->chart_interval, $this->start_date, $this->chart_groupby ), 'coupon_amounts' => $this->prepare_chart_data( $this->report_data->coupons, 'post_date', 'discount_amount', $this->chart_interval, $this->start_date, $this->chart_groupby ), 'shipping_amounts' => $this->prepare_chart_data( $this->report_data->orders, 'post_date', 'total_shipping', $this->chart_interval, $this->start_date, $this->chart_groupby ), 'refund_amounts' => $this->prepare_chart_data( $this->report_data->refund_lines, 'post_date', 'total_refund', $this->chart_interval, $this->start_date, $this->chart_groupby ), 'net_refund_amounts' => $this->prepare_chart_data( $this->report_data->refunded_orders, 'post_date', 'net_refund', $this->chart_interval, $this->start_date, $this->chart_groupby ), 'shipping_tax_amounts' => $this->prepare_chart_data( $this->report_data->orders, 'post_date', 'total_shipping_tax', $this->chart_interval, $this->start_date, $this->chart_groupby ), 'tax_amounts' => $this->prepare_chart_data( $this->report_data->orders, 'post_date', 'total_tax', $this->chart_interval, $this->start_date, $this->chart_groupby ), 'net_order_amounts' => array(), 'gross_order_amounts' => array(), ); foreach ( $data['order_amounts'] as $order_amount_key => $order_amount_value ) { $data['gross_order_amounts'][ $order_amount_key ] = $order_amount_value; $data['gross_order_amounts'][ $order_amount_key ][1] -= $data['refund_amounts'][ $order_amount_key ][1]; $data['net_order_amounts'][ $order_amount_key ] = $order_amount_value; // Subtract the sum of the values from net order amounts. $data['net_order_amounts'][ $order_amount_key ][1] -= $data['net_refund_amounts'][ $order_amount_key ][1] + $data['shipping_amounts'][ $order_amount_key ][1] + $data['shipping_tax_amounts'][ $order_amount_key ][1] + $data['tax_amounts'][ $order_amount_key ][1]; } // 3rd party filtering of report data. $data = apply_filters( 'woocommerce_admin_report_chart_data', $data ); // Encode in json format. $chart_data = wp_json_encode( array( 'order_counts' => array_values( $data['order_counts'] ), 'order_item_counts' => array_values( $data['order_item_counts'] ), 'order_amounts' => array_map( array( $this, 'round_chart_totals' ), array_values( $data['order_amounts'] ) ), 'gross_order_amounts' => array_map( array( $this, 'round_chart_totals' ), array_values( $data['gross_order_amounts'] ) ), 'net_order_amounts' => array_map( array( $this, 'round_chart_totals' ), array_values( $data['net_order_amounts'] ) ), 'shipping_amounts' => array_map( array( $this, 'round_chart_totals' ), array_values( $data['shipping_amounts'] ) ), 'coupon_amounts' => array_map( array( $this, 'round_chart_totals' ), array_values( $data['coupon_amounts'] ) ), 'refund_amounts' => array_map( array( $this, 'round_chart_totals' ), array_values( $data['refund_amounts'] ) ), ) ); ?> <div class="chart-container"> <div class="chart-placeholder main"></div> </div> <script type="text/javascript"> var main_chart; jQuery(function(){ var order_data = JSON.parse( decodeURIComponent( '<?php echo rawurlencode( $chart_data ); ?>' ) ); var drawGraph = function( highlight ) { var series = [ { label: "<?php echo esc_js( __( 'Number of items sold', 'woocommerce' ) ); ?>", data: order_data.order_item_counts, color: '<?php echo esc_js( $this->chart_colours['item_count'] ); ?>', bars: { fillColor: '<?php echo esc_js( $this->chart_colours['item_count'] ); ?>', fill: true, show: true, lineWidth: 0, barWidth: <?php echo esc_js( $this->barwidth ); ?> * 0.5, align: 'center' }, shadowSize: 0, hoverable: false }, { label: "<?php echo esc_js( __( 'Number of orders', 'woocommerce' ) ); ?>", data: order_data.order_counts, color: '<?php echo esc_js( $this->chart_colours['order_count'] ); ?>', bars: { fillColor: '<?php echo esc_js( $this->chart_colours['order_count'] ); ?>', fill: true, show: true, lineWidth: 0, barWidth: <?php echo esc_js( $this->barwidth ); ?> * 0.5, align: 'center' }, shadowSize: 0, hoverable: false }, { label: "<?php echo esc_js( __( 'Average gross sales amount', 'woocommerce' ) ); ?>", data: [ [ <?php echo esc_js( min( array_keys( $data['order_amounts'] ) ) ); ?>, <?php echo esc_js( $this->report_data->average_total_sales ); ?> ], [ <?php echo esc_js( max( array_keys( $data['order_amounts'] ) ) ); ?>, <?php echo esc_js( $this->report_data->average_total_sales ); ?> ] ], yaxis: 2, color: '<?php echo esc_js( $this->chart_colours['average'] ); ?>', points: { show: false }, lines: { show: true, lineWidth: 2, fill: false }, shadowSize: 0, hoverable: false }, { label: "<?php echo esc_js( __( 'Average net sales amount', 'woocommerce' ) ); ?>", data: [ [ <?php echo esc_js( min( array_keys( $data['order_amounts'] ) ) ); ?>, <?php echo esc_js( $this->report_data->average_sales ); ?> ], [ <?php echo esc_js( max( array_keys( $data['order_amounts'] ) ) ); ?>, <?php echo esc_js( $this->report_data->average_sales ); ?> ] ], yaxis: 2, color: '<?php echo esc_js( $this->chart_colours['net_average'] ); ?>', points: { show: false }, lines: { show: true, lineWidth: 2, fill: false }, shadowSize: 0, hoverable: false }, { label: "<?php echo esc_js( __( 'Coupon amount', 'woocommerce' ) ); ?>", data: order_data.coupon_amounts, yaxis: 2, color: '<?php echo esc_js( $this->chart_colours['coupon_amount'] ); ?>', points: { show: true, radius: 5, lineWidth: 2, fillColor: '#fff', fill: true }, lines: { show: true, lineWidth: 2, fill: false }, shadowSize: 0, <?php echo $this->get_currency_tooltip(); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?> }, { label: "<?php echo esc_js( __( 'Shipping amount', 'woocommerce' ) ); ?>", data: order_data.shipping_amounts, yaxis: 2, color: '<?php echo esc_js( $this->chart_colours['shipping_amount'] ); ?>', points: { show: true, radius: 5, lineWidth: 2, fillColor: '#fff', fill: true }, lines: { show: true, lineWidth: 2, fill: false }, shadowSize: 0, prepend_tooltip: "<?php echo get_woocommerce_currency_symbol(); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>" }, { label: "<?php echo esc_js( __( 'Gross sales amount', 'woocommerce' ) ); ?>", data: order_data.gross_order_amounts, yaxis: 2, color: '<?php echo esc_js( $this->chart_colours['sales_amount'] ); ?>', points: { show: true, radius: 5, lineWidth: 2, fillColor: '#fff', fill: true }, lines: { show: true, lineWidth: 2, fill: false }, shadowSize: 0, <?php echo $this->get_currency_tooltip(); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?> }, { label: "<?php echo esc_js( __( 'Net sales amount', 'woocommerce' ) ); ?>", data: order_data.net_order_amounts, yaxis: 2, color: '<?php echo esc_js( $this->chart_colours['net_sales_amount'] ); ?>', points: { show: true, radius: 6, lineWidth: 4, fillColor: '#fff', fill: true }, lines: { show: true, lineWidth: 5, fill: false }, shadowSize: 0, <?php echo $this->get_currency_tooltip(); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?> }, { label: "<?php echo esc_js( __( 'Refund amount', 'woocommerce' ) ); ?>", data: order_data.refund_amounts, yaxis: 2, color: '<?php echo esc_js( $this->chart_colours['refund_amount'] ); ?>', points: { show: true, radius: 5, lineWidth: 2, fillColor: '#fff', fill: true }, lines: { show: true, lineWidth: 2, fill: false }, shadowSize: 0, prepend_tooltip: "<?php echo get_woocommerce_currency_symbol(); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>" }, ]; if ( highlight !== 'undefined' && series[ highlight ] ) { highlight_series = series[ highlight ]; highlight_series.color = '#9c5d90'; if ( highlight_series.bars ) { highlight_series.bars.fillColor = '#9c5d90'; } if ( highlight_series.lines ) { highlight_series.lines.lineWidth = 5; } } main_chart = jQuery.plot( jQuery('.chart-placeholder.main'), series, { legend: { show: false }, grid: { color: '#aaa', borderColor: 'transparent', borderWidth: 0, hoverable: true }, xaxes: [ { color: '#aaa', position: "bottom", tickColor: 'transparent', mode: "time", timeformat: "<?php echo ( 'day' === $this->chart_groupby ) ? '%d %b' : '%b'; ?>", monthNames: JSON.parse( decodeURIComponent( '<?php echo rawurlencode( wp_json_encode( array_values( $wp_locale->month_abbrev ) ) ); ?>' ) ), tickLength: 1, minTickSize: [1, "<?php echo esc_js( $this->chart_groupby ); ?>"], font: { color: "#aaa" } } ], yaxes: [ { min: 0, minTickSize: 1, tickDecimals: 0, color: '#d4d9dc', font: { color: "#aaa" } }, { position: "right", min: 0, tickDecimals: 2, alignTicksWithAxis: 1, color: 'transparent', font: { color: "#aaa" } } ], } ); jQuery('.chart-placeholder').trigger( 'resize' ); } drawGraph(); jQuery('.highlight_series').on( 'mouseenter', function() { drawGraph( jQuery(this).data('series') ); } ).on( 'mouseleave', function() { drawGraph(); } ); }); </script> <?php } } class-wc-report-customers.php 0000644 00000027071 15134216707 0012341 0 ustar 00 <?php /** * Class WC_Report_Customers file. * * @package WooCommerce\Reports */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * WC_Report_Customers * * @package WooCommerce\Admin\Reports * @version 2.1.0 */ class WC_Report_Customers extends WC_Admin_Report { /** * Chart colors. * * @var array */ public $chart_colours = array(); /** * Customers. * * @var array */ public $customers = array(); /** * Get the legend for the main chart sidebar. * * @return array */ public function get_chart_legend() { $legend = array(); $legend[] = array( /* translators: %s: signups amount */ 'title' => sprintf( __( '%s signups in this period', 'woocommerce' ), '<strong>' . count( $this->customers ) . '</strong>' ), 'color' => $this->chart_colours['signups'], 'highlight_series' => 2, ); return $legend; } /** * Get chart widgets. * * @return array */ public function get_chart_widgets() { $widgets = array(); $widgets[] = array( 'title' => '', 'callback' => array( $this, 'customers_vs_guests' ), ); return $widgets; } /** * Output customers vs guests chart. */ public function customers_vs_guests() { $customer_order_totals = $this->get_order_report_data( array( 'data' => array( 'ID' => array( 'type' => 'post_data', 'function' => 'COUNT', 'name' => 'total_orders', ), ), 'where_meta' => array( array( 'meta_key' => '_customer_user', 'meta_value' => '0', 'operator' => '>', ), ), 'filter_range' => true, ) ); $guest_order_totals = $this->get_order_report_data( array( 'data' => array( 'ID' => array( 'type' => 'post_data', 'function' => 'COUNT', 'name' => 'total_orders', ), ), 'where_meta' => array( array( 'meta_key' => '_customer_user', 'meta_value' => '0', 'operator' => '=', ), ), 'filter_range' => true, ) ); ?> <div class="chart-container"> <div class="chart-placeholder customers_vs_guests pie-chart" style="height:200px"></div> <ul class="pie-chart-legend"> <li style="border-color: <?php echo esc_attr( $this->chart_colours['customers'] ); ?>"><?php esc_html_e( 'Customer sales', 'woocommerce' ); ?></li> <li style="border-color: <?php echo esc_attr( $this->chart_colours['guests'] ); ?>"><?php esc_html_e( 'Guest sales', 'woocommerce' ); ?></li> </ul> </div> <script type="text/javascript"> jQuery(function(){ jQuery.plot( jQuery('.chart-placeholder.customers_vs_guests'), [ { label: '<?php esc_html_e( 'Customer orders', 'woocommerce' ); ?>', data: "<?php echo esc_html( $customer_order_totals->total_orders ); ?>", color: '<?php echo esc_html( $this->chart_colours['customers'] ); ?>' }, { label: '<?php esc_html_e( 'Guest orders', 'woocommerce' ); ?>', data: "<?php echo esc_html( $guest_order_totals->total_orders ); ?>", color: '<?php echo esc_html( $this->chart_colours['guests'] ); ?>' } ], { grid: { hoverable: true }, series: { pie: { show: true, radius: 1, innerRadius: 0.6, label: { show: false } }, enable_tooltip: true, append_tooltip: "<?php echo esc_html( ' ' . __( 'orders', 'woocommerce' ) ); ?>", }, legend: { show: false } } ); jQuery('.chart-placeholder.customers_vs_guests').trigger( 'resize' ); }); </script> <?php } /** * Output the report. */ public function output_report() { $ranges = array( 'year' => __( 'Year', 'woocommerce' ), 'last_month' => __( 'Last month', 'woocommerce' ), 'month' => __( 'This month', 'woocommerce' ), '7day' => __( 'Last 7 days', 'woocommerce' ), ); $this->chart_colours = array( 'signups' => '#3498db', 'customers' => '#1abc9c', 'guests' => '#8fdece', ); $current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; if ( ! in_array( $current_range, array( 'custom', 'year', 'last_month', 'month', '7day' ), true ) ) { $current_range = '7day'; } $this->check_current_range_nonce( $current_range ); $this->calculate_current_range( $current_range ); $admin_users = new WP_User_Query( array( 'role' => 'administrator', 'fields' => 'ID', ) ); $manager_users = new WP_User_Query( array( 'role' => 'shop_manager', 'fields' => 'ID', ) ); $users_query = new WP_User_Query( apply_filters( 'woocommerce_admin_report_customers_user_query_args', array( 'fields' => array( 'user_registered' ), 'exclude' => array_merge( $admin_users->get_results(), $manager_users->get_results() ), ) ) ); $this->customers = $users_query->get_results(); foreach ( $this->customers as $key => $customer ) { if ( strtotime( $customer->user_registered ) < $this->start_date || strtotime( $customer->user_registered ) > $this->end_date ) { unset( $this->customers[ $key ] ); } } include WC()->plugin_path() . '/includes/admin/views/html-report-by-date.php'; } /** * Output an export link. */ public function get_export_button() { $current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '7day'; ?> <a href="#" download="report-<?php echo esc_attr( $current_range ); ?>-<?php echo esc_attr( date_i18n( 'Y-m-d', current_time( 'timestamp' ) ) ); ?>.csv" class="export_csv" data-export="chart" data-xaxes="<?php esc_attr_e( 'Date', 'woocommerce' ); ?>" data-groupby="<?php echo esc_attr( $this->chart_groupby ); ?>" > <?php esc_html_e( 'Export CSV', 'woocommerce' ); ?> </a> <?php } /** * Output the main chart. */ public function get_main_chart() { global $wp_locale; $customer_orders = $this->get_order_report_data( array( 'data' => array( 'ID' => array( 'type' => 'post_data', 'function' => 'COUNT', 'name' => 'total_orders', ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), ), 'where_meta' => array( array( 'meta_key' => '_customer_user', 'meta_value' => '0', 'operator' => '>', ), ), 'group_by' => $this->group_by_query, 'order_by' => 'post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, ) ); $guest_orders = $this->get_order_report_data( array( 'data' => array( 'ID' => array( 'type' => 'post_data', 'function' => 'COUNT', 'name' => 'total_orders', ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), ), 'where_meta' => array( array( 'meta_key' => '_customer_user', 'meta_value' => '0', 'operator' => '=', ), ), 'group_by' => $this->group_by_query, 'order_by' => 'post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, ) ); $signups = $this->prepare_chart_data( $this->customers, 'user_registered', '', $this->chart_interval, $this->start_date, $this->chart_groupby ); $customer_orders = $this->prepare_chart_data( $customer_orders, 'post_date', 'total_orders', $this->chart_interval, $this->start_date, $this->chart_groupby ); $guest_orders = $this->prepare_chart_data( $guest_orders, 'post_date', 'total_orders', $this->chart_interval, $this->start_date, $this->chart_groupby ); $chart_data = wp_json_encode( array( 'signups' => array_values( $signups ), 'customer_orders' => array_values( $customer_orders ), 'guest_orders' => array_values( $guest_orders ), ) ); ?> <div class="chart-container"> <div class="chart-placeholder main"></div> </div> <script type="text/javascript"> var main_chart; jQuery(function(){ var chart_data = JSON.parse( decodeURIComponent( '<?php echo rawurlencode( $chart_data ); ?>' ) ); var drawGraph = function( highlight ) { var series = [ { label: "<?php echo esc_js( __( 'Customer orders', 'woocommerce' ) ); ?>", data: chart_data.customer_orders, color: '<?php echo esc_html( $this->chart_colours['customers'] ); ?>', bars: { fillColor: '<?php echo esc_html( $this->chart_colours['customers'] ); ?>', fill: true, show: true, lineWidth: 0, barWidth: <?php echo esc_html( $this->barwidth ); ?> * 0.5, align: 'center' }, shadowSize: 0, enable_tooltip: true, append_tooltip: "<?php echo esc_html( ' ' . __( 'customer orders', 'woocommerce' ) ); ?>", stack: true, }, { label: "<?php echo esc_js( __( 'Guest orders', 'woocommerce' ) ); ?>", data: chart_data.guest_orders, color: '<?php echo esc_html( $this->chart_colours['guests'] ); ?>', bars: { fillColor: '<?php echo esc_html( $this->chart_colours['guests'] ); ?>', fill: true, show: true, lineWidth: 0, barWidth: <?php echo esc_html( $this->barwidth ); ?> * 0.5, align: 'center' }, shadowSize: 0, enable_tooltip: true, append_tooltip: "<?php echo esc_html( ' ' . __( 'guest orders', 'woocommerce' ) ); ?>", stack: true, }, { label: "<?php echo esc_js( __( 'Signups', 'woocommerce' ) ); ?>", data: chart_data.signups, color: '<?php echo esc_html( $this->chart_colours['signups'] ); ?>', points: { show: true, radius: 5, lineWidth: 3, fillColor: '#fff', fill: true }, lines: { show: true, lineWidth: 4, fill: false }, shadowSize: 0, enable_tooltip: true, append_tooltip: "<?php echo esc_html( ' ' . __( 'new users', 'woocommerce' ) ); ?>", stack: false }, ]; if ( highlight !== 'undefined' && series[ highlight ] ) { highlight_series = series[ highlight ]; highlight_series.color = '#9c5d90'; if ( highlight_series.bars ) highlight_series.bars.fillColor = '#9c5d90'; if ( highlight_series.lines ) { highlight_series.lines.lineWidth = 5; } } main_chart = jQuery.plot( jQuery('.chart-placeholder.main'), series, { legend: { show: false }, grid: { color: '#aaa', borderColor: 'transparent', borderWidth: 0, hoverable: true }, xaxes: [ { color: '#aaa', position: "bottom", tickColor: 'transparent', mode: "time", timeformat: "<?php echo ( 'day' === $this->chart_groupby ) ? '%d %b' : '%b'; ?>", monthNames: JSON.parse( decodeURIComponent( '<?php echo rawurlencode( wp_json_encode( array_values( $wp_locale->month_abbrev ) ) ); ?>' ) ), tickLength: 1, minTickSize: [1, "<?php echo esc_html( $this->chart_groupby ); ?>"], tickSize: [1, "<?php echo esc_html( $this->chart_groupby ); ?>"], font: { color: "#aaa" } } ], yaxes: [ { min: 0, minTickSize: 1, tickDecimals: 0, color: '#ecf0f1', font: { color: "#aaa" } } ], } ); jQuery('.chart-placeholder').trigger( 'resize' ); } drawGraph(); jQuery('.highlight_series').on( 'mouseenter', function() { drawGraph( jQuery(this).data('series') ); } ).on( 'mouseleave', function() { drawGraph(); } ); }); </script> <?php } } class-wc-admin-report.php 0000644 00000053622 15134216707 0011406 0 ustar 00 <?php if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } /** * Admin Report. * * Extended by reports to show charts and stats in admin. * * @author WooThemes * @category Admin * @package WooCommerce\Admin\Reports * @version 2.1.0 */ class WC_Admin_Report { /** * @var array List of transients name that have been updated and need persisting. */ protected static $transients_to_update = array(); /** * @var array The list of transients. */ protected static $cached_results = array(); /** * The chart interval. * * @var int */ public $chart_interval; /** * Group by SQL query. * * @var string */ public $group_by_query; /** * The bar width. * * @var int */ public $barwidth; /** * Group chart item by day or month. * * @var string */ public $chart_groupby; /** * The start date of the report. * * @var int timestamp */ public $start_date; /** * The end date of the report. * * @var int timestamp */ public $end_date; /** * Get report totals such as order totals and discount amounts. * * Data example: * * '_order_total' => array( * 'type' => 'meta', * 'function' => 'SUM', * 'name' => 'total_sales' * ) * * @param array $args * @return mixed depending on query_type */ public function get_order_report_data( $args = array() ) { global $wpdb; $default_args = array( 'data' => array(), 'where' => array(), 'where_meta' => array(), 'query_type' => 'get_row', 'group_by' => '', 'order_by' => '', 'limit' => '', 'filter_range' => false, 'nocache' => false, 'debug' => false, 'order_types' => wc_get_order_types( 'reports' ), 'order_status' => array( 'completed', 'processing', 'on-hold' ), 'parent_order_status' => false, ); $args = apply_filters( 'woocommerce_reports_get_order_report_data_args', $args ); $args = wp_parse_args( $args, $default_args ); extract( $args ); if ( empty( $data ) ) { return ''; } $order_status = apply_filters( 'woocommerce_reports_order_statuses', $order_status ); $query = array(); $select = array(); foreach ( $data as $raw_key => $value ) { $key = sanitize_key( $raw_key ); $distinct = ''; if ( isset( $value['distinct'] ) ) { $distinct = 'DISTINCT'; } switch ( $value['type'] ) { case 'meta': $get_key = "meta_{$key}.meta_value"; break; case 'parent_meta': $get_key = "parent_meta_{$key}.meta_value"; break; case 'post_data': $get_key = "posts.{$key}"; break; case 'order_item_meta': $get_key = "order_item_meta_{$key}.meta_value"; break; case 'order_item': $get_key = "order_items.{$key}"; break; } if ( empty( $get_key ) ) { // Skip to the next foreach iteration else the query will be invalid. continue; } if ( $value['function'] ) { $get = "{$value['function']}({$distinct} {$get_key})"; } else { $get = "{$distinct} {$get_key}"; } $select[] = "{$get} as {$value['name']}"; } $query['select'] = 'SELECT ' . implode( ',', $select ); $query['from'] = "FROM {$wpdb->posts} AS posts"; // Joins $joins = array(); foreach ( ( $data + $where ) as $raw_key => $value ) { $join_type = isset( $value['join_type'] ) ? $value['join_type'] : 'INNER'; $type = isset( $value['type'] ) ? $value['type'] : false; $key = sanitize_key( $raw_key ); switch ( $type ) { case 'meta': $joins[ "meta_{$key}" ] = "{$join_type} JOIN {$wpdb->postmeta} AS meta_{$key} ON ( posts.ID = meta_{$key}.post_id AND meta_{$key}.meta_key = '{$raw_key}' )"; break; case 'parent_meta': $joins[ "parent_meta_{$key}" ] = "{$join_type} JOIN {$wpdb->postmeta} AS parent_meta_{$key} ON (posts.post_parent = parent_meta_{$key}.post_id) AND (parent_meta_{$key}.meta_key = '{$raw_key}')"; break; case 'order_item_meta': $joins['order_items'] = "{$join_type} JOIN {$wpdb->prefix}woocommerce_order_items AS order_items ON (posts.ID = order_items.order_id)"; if ( ! empty( $value['order_item_type'] ) ) { $joins['order_items'] .= " AND (order_items.order_item_type = '{$value['order_item_type']}')"; } $joins[ "order_item_meta_{$key}" ] = "{$join_type} JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS order_item_meta_{$key} ON " . "(order_items.order_item_id = order_item_meta_{$key}.order_item_id) " . " AND (order_item_meta_{$key}.meta_key = '{$raw_key}')"; break; case 'order_item': $joins['order_items'] = "{$join_type} JOIN {$wpdb->prefix}woocommerce_order_items AS order_items ON posts.ID = order_items.order_id"; break; } } if ( ! empty( $where_meta ) ) { foreach ( $where_meta as $value ) { if ( ! is_array( $value ) ) { continue; } $join_type = isset( $value['join_type'] ) ? $value['join_type'] : 'INNER'; $type = isset( $value['type'] ) ? $value['type'] : false; $key = sanitize_key( is_array( $value['meta_key'] ) ? $value['meta_key'][0] . '_array' : $value['meta_key'] ); if ( 'order_item_meta' === $type ) { $joins['order_items'] = "{$join_type} JOIN {$wpdb->prefix}woocommerce_order_items AS order_items ON posts.ID = order_items.order_id"; $joins[ "order_item_meta_{$key}" ] = "{$join_type} JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS order_item_meta_{$key} ON order_items.order_item_id = order_item_meta_{$key}.order_item_id"; } else { // If we have a where clause for meta, join the postmeta table $joins[ "meta_{$key}" ] = "{$join_type} JOIN {$wpdb->postmeta} AS meta_{$key} ON posts.ID = meta_{$key}.post_id"; } } } if ( ! empty( $parent_order_status ) ) { $joins['parent'] = "LEFT JOIN {$wpdb->posts} AS parent ON posts.post_parent = parent.ID"; } $query['join'] = implode( ' ', $joins ); $query['where'] = " WHERE posts.post_type IN ( '" . implode( "','", $order_types ) . "' ) "; if ( ! empty( $order_status ) ) { $query['where'] .= " AND posts.post_status IN ( 'wc-" . implode( "','wc-", $order_status ) . "') "; } if ( ! empty( $parent_order_status ) ) { if ( ! empty( $order_status ) ) { $query['where'] .= " AND ( parent.post_status IN ( 'wc-" . implode( "','wc-", $parent_order_status ) . "') OR parent.ID IS NULL ) "; } else { $query['where'] .= " AND parent.post_status IN ( 'wc-" . implode( "','wc-", $parent_order_status ) . "') "; } } if ( $filter_range ) { $query['where'] .= " AND posts.post_date >= '" . date( 'Y-m-d H:i:s', $this->start_date ) . "' AND posts.post_date < '" . date( 'Y-m-d H:i:s', strtotime( '+1 DAY', $this->end_date ) ) . "' "; } if ( ! empty( $where_meta ) ) { $relation = isset( $where_meta['relation'] ) ? $where_meta['relation'] : 'AND'; $query['where'] .= ' AND ('; foreach ( $where_meta as $index => $value ) { if ( ! is_array( $value ) ) { continue; } $key = sanitize_key( is_array( $value['meta_key'] ) ? $value['meta_key'][0] . '_array' : $value['meta_key'] ); if ( strtolower( $value['operator'] ) == 'in' || strtolower( $value['operator'] ) == 'not in' ) { if ( is_array( $value['meta_value'] ) ) { $value['meta_value'] = implode( "','", $value['meta_value'] ); } if ( ! empty( $value['meta_value'] ) ) { $where_value = "{$value['operator']} ('{$value['meta_value']}')"; } } else { $where_value = "{$value['operator']} '{$value['meta_value']}'"; } if ( ! empty( $where_value ) ) { if ( $index > 0 ) { $query['where'] .= ' ' . $relation; } if ( isset( $value['type'] ) && 'order_item_meta' === $value['type'] ) { if ( is_array( $value['meta_key'] ) ) { $query['where'] .= " ( order_item_meta_{$key}.meta_key IN ('" . implode( "','", $value['meta_key'] ) . "')"; } else { $query['where'] .= " ( order_item_meta_{$key}.meta_key = '{$value['meta_key']}'"; } $query['where'] .= " AND order_item_meta_{$key}.meta_value {$where_value} )"; } else { if ( is_array( $value['meta_key'] ) ) { $query['where'] .= " ( meta_{$key}.meta_key IN ('" . implode( "','", $value['meta_key'] ) . "')"; } else { $query['where'] .= " ( meta_{$key}.meta_key = '{$value['meta_key']}'"; } $query['where'] .= " AND meta_{$key}.meta_value {$where_value} )"; } } } $query['where'] .= ')'; } if ( ! empty( $where ) ) { foreach ( $where as $value ) { if ( strtolower( $value['operator'] ) == 'in' || strtolower( $value['operator'] ) == 'not in' ) { if ( is_array( $value['value'] ) ) { $value['value'] = implode( "','", $value['value'] ); } if ( ! empty( $value['value'] ) ) { $where_value = "{$value['operator']} ('{$value['value']}')"; } } else { $where_value = "{$value['operator']} '{$value['value']}'"; } if ( ! empty( $where_value ) ) { $query['where'] .= " AND {$value['key']} {$where_value}"; } } } if ( $group_by ) { $query['group_by'] = "GROUP BY {$group_by}"; } if ( $order_by ) { $query['order_by'] = "ORDER BY {$order_by}"; } if ( $limit ) { $query['limit'] = "LIMIT {$limit}"; } $query = apply_filters( 'woocommerce_reports_get_order_report_query', $query ); $query = implode( ' ', $query ); if ( $debug ) { echo '<pre>'; wc_print_r( $query ); echo '</pre>'; } if ( $debug || $nocache ) { self::enable_big_selects(); $result = apply_filters( 'woocommerce_reports_get_order_report_data', $wpdb->$query_type( $query ), $data ); } else { $query_hash = md5( $query_type . $query ); $result = $this->get_cached_query( $query_hash ); if ( $result === null ) { self::enable_big_selects(); $result = apply_filters( 'woocommerce_reports_get_order_report_data', $wpdb->$query_type( $query ), $data ); } $this->set_cached_query( $query_hash, $result ); } return $result; } /** * Init the static hooks of the class. */ protected static function add_update_transients_hook() { if ( ! has_action( 'shutdown', array( 'WC_Admin_Report', 'maybe_update_transients' ) ) ) { add_action( 'shutdown', array( 'WC_Admin_Report', 'maybe_update_transients' ) ); } } /** * Enables big mysql selects for reports, just once for this session. */ protected static function enable_big_selects() { static $big_selects = false; global $wpdb; if ( ! $big_selects ) { $wpdb->query( 'SET SESSION SQL_BIG_SELECTS=1' ); $big_selects = true; } } /** * Get the cached query result or null if it's not in the cache. * * @param string $query_hash The query hash. * * @return mixed */ protected function get_cached_query( $query_hash ) { $class = strtolower( get_class( $this ) ); if ( ! isset( self::$cached_results[ $class ] ) ) { self::$cached_results[ $class ] = get_transient( strtolower( get_class( $this ) ) ); } if ( isset( self::$cached_results[ $class ][ $query_hash ] ) ) { return self::$cached_results[ $class ][ $query_hash ]; } return null; } /** * Set the cached query result. * * @param string $query_hash The query hash. * @param mixed $data The data to cache. */ protected function set_cached_query( $query_hash, $data ) { $class = strtolower( get_class( $this ) ); if ( ! isset( self::$cached_results[ $class ] ) ) { self::$cached_results[ $class ] = get_transient( strtolower( get_class( $this ) ) ); } self::add_update_transients_hook(); self::$transients_to_update[ $class ] = $class; self::$cached_results[ $class ][ $query_hash ] = $data; } /** * Function to update the modified transients at the end of the request. */ public static function maybe_update_transients() { foreach ( self::$transients_to_update as $key => $transient_name ) { set_transient( $transient_name, self::$cached_results[ $transient_name ], DAY_IN_SECONDS ); } // Transients have been updated reset the list. self::$transients_to_update = array(); } /** * Put data with post_date's into an array of times. * * @param array $data array of your data * @param string $date_key key for the 'date' field. e.g. 'post_date' * @param string $data_key key for the data you are charting * @param int $interval * @param string $start_date * @param string $group_by * @return array */ public function prepare_chart_data( $data, $date_key, $data_key, $interval, $start_date, $group_by ) { $prepared_data = array(); // Ensure all days (or months) have values in this range. if ( 'day' === $group_by ) { for ( $i = 0; $i <= $interval; $i ++ ) { $time = strtotime( date( 'Ymd', strtotime( "+{$i} DAY", $start_date ) ) ) . '000'; if ( ! isset( $prepared_data[ $time ] ) ) { $prepared_data[ $time ] = array( esc_js( $time ), 0 ); } } } else { $current_yearnum = date( 'Y', $start_date ); $current_monthnum = date( 'm', $start_date ); for ( $i = 0; $i <= $interval; $i ++ ) { $time = strtotime( $current_yearnum . str_pad( $current_monthnum, 2, '0', STR_PAD_LEFT ) . '01' ) . '000'; if ( ! isset( $prepared_data[ $time ] ) ) { $prepared_data[ $time ] = array( esc_js( $time ), 0 ); } $current_monthnum ++; if ( $current_monthnum > 12 ) { $current_monthnum = 1; $current_yearnum ++; } } } foreach ( $data as $d ) { switch ( $group_by ) { case 'day': $time = strtotime( date( 'Ymd', strtotime( $d->$date_key ) ) ) . '000'; break; case 'month': default: $time = strtotime( date( 'Ym', strtotime( $d->$date_key ) ) . '01' ) . '000'; break; } if ( ! isset( $prepared_data[ $time ] ) ) { continue; } if ( $data_key ) { $prepared_data[ $time ][1] += $d->$data_key; } else { $prepared_data[ $time ][1] ++; } } return $prepared_data; } /** * Prepares a sparkline to show sales in the last X days. * * @param int $id ID of the product to show. Blank to get all orders. * @param int $days Days of stats to get. * @param string $type Type of sparkline to get. Ignored if ID is not set. * @return string */ public function sales_sparkline( $id = '', $days = 7, $type = 'sales' ) { if ( $id ) { $meta_key = ( 'sales' === $type ) ? '_line_total' : '_qty'; $data = $this->get_order_report_data( array( 'data' => array( '_product_id' => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => '', 'name' => 'product_id', ), $meta_key => array( 'type' => 'order_item_meta', 'order_item_type' => 'line_item', 'function' => 'SUM', 'name' => 'sparkline_value', ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), ), 'where' => array( array( 'key' => 'post_date', 'value' => date( 'Y-m-d', strtotime( 'midnight -' . ( $days - 1 ) . ' days', current_time( 'timestamp' ) ) ), 'operator' => '>', ), array( 'key' => 'order_item_meta__product_id.meta_value', 'value' => $id, 'operator' => '=', ), ), 'group_by' => 'YEAR(posts.post_date), MONTH(posts.post_date), DAY(posts.post_date)', 'query_type' => 'get_results', 'filter_range' => false, ) ); } else { $data = $this->get_order_report_data( array( 'data' => array( '_order_total' => array( 'type' => 'meta', 'function' => 'SUM', 'name' => 'sparkline_value', ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), ), 'where' => array( array( 'key' => 'post_date', 'value' => date( 'Y-m-d', strtotime( 'midnight -' . ( $days - 1 ) . ' days', current_time( 'timestamp' ) ) ), 'operator' => '>', ), ), 'group_by' => 'YEAR(posts.post_date), MONTH(posts.post_date), DAY(posts.post_date)', 'query_type' => 'get_results', 'filter_range' => false, ) ); } $total = 0; foreach ( $data as $d ) { $total += $d->sparkline_value; } if ( 'sales' === $type ) { /* translators: 1: total income 2: days */ $tooltip = sprintf( __( 'Sold %1$s worth in the last %2$d days', 'woocommerce' ), strip_tags( wc_price( $total ) ), $days ); } else { /* translators: 1: total items sold 2: days */ $tooltip = sprintf( _n( 'Sold %1$d item in the last %2$d days', 'Sold %1$d items in the last %2$d days', $total, 'woocommerce' ), $total, $days ); } $sparkline_data = array_values( $this->prepare_chart_data( $data, 'post_date', 'sparkline_value', $days - 1, strtotime( 'midnight -' . ( $days - 1 ) . ' days', current_time( 'timestamp' ) ), 'day' ) ); return '<span class="wc_sparkline ' . ( ( 'sales' === $type ) ? 'lines' : 'bars' ) . ' tips" data-color="#777" data-tip="' . esc_attr( $tooltip ) . '" data-barwidth="' . 60 * 60 * 16 * 1000 . '" data-sparkline="' . wc_esc_json( wp_json_encode( $sparkline_data ) ) . '"></span>'; } /** * Get the current range and calculate the start and end dates. * * @param string $current_range */ public function calculate_current_range( $current_range ) { switch ( $current_range ) { case 'custom': $this->start_date = max( strtotime( '-20 years' ), strtotime( sanitize_text_field( $_GET['start_date'] ) ) ); if ( empty( $_GET['end_date'] ) ) { $this->end_date = strtotime( 'midnight', current_time( 'timestamp' ) ); } else { $this->end_date = strtotime( 'midnight', strtotime( sanitize_text_field( $_GET['end_date'] ) ) ); } $interval = 0; $min_date = $this->start_date; while ( ( $min_date = strtotime( '+1 MONTH', $min_date ) ) <= $this->end_date ) { $interval ++; } // 3 months max for day view if ( $interval > 3 ) { $this->chart_groupby = 'month'; } else { $this->chart_groupby = 'day'; } break; case 'year': $this->start_date = strtotime( date( 'Y-01-01', current_time( 'timestamp' ) ) ); $this->end_date = strtotime( 'midnight', current_time( 'timestamp' ) ); $this->chart_groupby = 'month'; break; case 'last_month': $first_day_current_month = strtotime( date( 'Y-m-01', current_time( 'timestamp' ) ) ); $this->start_date = strtotime( date( 'Y-m-01', strtotime( '-1 DAY', $first_day_current_month ) ) ); $this->end_date = strtotime( date( 'Y-m-t', strtotime( '-1 DAY', $first_day_current_month ) ) ); $this->chart_groupby = 'day'; break; case 'month': $this->start_date = strtotime( date( 'Y-m-01', current_time( 'timestamp' ) ) ); $this->end_date = strtotime( 'midnight', current_time( 'timestamp' ) ); $this->chart_groupby = 'day'; break; case '7day': $this->start_date = strtotime( '-6 days', strtotime( 'midnight', current_time( 'timestamp' ) ) ); $this->end_date = strtotime( 'midnight', current_time( 'timestamp' ) ); $this->chart_groupby = 'day'; break; } // Group by switch ( $this->chart_groupby ) { case 'day': $this->group_by_query = 'YEAR(posts.post_date), MONTH(posts.post_date), DAY(posts.post_date)'; $this->chart_interval = absint( ceil( max( 0, ( $this->end_date - $this->start_date ) / ( 60 * 60 * 24 ) ) ) ); $this->barwidth = 60 * 60 * 24 * 1000; break; case 'month': $this->group_by_query = 'YEAR(posts.post_date), MONTH(posts.post_date)'; $this->chart_interval = 0; $min_date = strtotime( date( 'Y-m-01', $this->start_date ) ); while ( ( $min_date = strtotime( '+1 MONTH', $min_date ) ) <= $this->end_date ) { $this->chart_interval ++; } $this->barwidth = 60 * 60 * 24 * 7 * 4 * 1000; break; } } /** * Return currency tooltip JS based on WooCommerce currency position settings. * * @return string */ public function get_currency_tooltip() { switch ( get_option( 'woocommerce_currency_pos' ) ) { case 'right': $currency_tooltip = 'append_tooltip: "' . get_woocommerce_currency_symbol() . '"'; break; case 'right_space': $currency_tooltip = 'append_tooltip: " ' . get_woocommerce_currency_symbol() . '"'; break; case 'left': $currency_tooltip = 'prepend_tooltip: "' . get_woocommerce_currency_symbol() . '"'; break; case 'left_space': default: $currency_tooltip = 'prepend_tooltip: "' . get_woocommerce_currency_symbol() . ' "'; break; } return $currency_tooltip; } /** * Get the main chart. */ public function get_main_chart() {} /** * Get the legend for the main chart sidebar. * * @return array */ public function get_chart_legend() { return array(); } /** * Get chart widgets. * * @return array */ public function get_chart_widgets() { return array(); } /** * Get an export link if needed. */ public function get_export_button() {} /** * Output the report. */ public function output_report() {} /** * Check nonce for current range. * * @since 3.0.4 * @param string $current_range Current range. */ public function check_current_range_nonce( $current_range ) { if ( 'custom' !== $current_range ) { return; } if ( ! isset( $_GET['wc_reports_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['wc_reports_nonce'] ), 'custom_range' ) ) { // WPCS: input var ok, CSRF ok. wp_die( /* translators: %1$s: open link, %2$s: close link */ sprintf( esc_html__( 'This report link has expired. %1$sClick here to view the filtered report%2$s.', 'woocommerce' ), '<a href="' . esc_url( wp_nonce_url( esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ), 'custom_range', 'wc_reports_nonce' ) ) . '">', '</a>' ), // @codingStandardsIgnoreLine. esc_attr__( 'Confirm navigation', 'woocommerce' ) ); exit; } } } class-wc-report-most-stocked.php 0000644 00000002773 15134216707 0012733 0 ustar 00 <?php /** * WC_Report_Most_Stocked. * * @package WooCommerce\Admin\Reports */ defined( 'ABSPATH' ) || exit; if ( ! class_exists( 'WC_Report_Stock' ) ) { require_once dirname( __FILE__ ) . '/class-wc-report-stock.php'; } /** * WC_Report_Most_Stocked. */ class WC_Report_Most_Stocked extends WC_Report_Stock { /** * Get Products matching stock criteria. * * @param int $current_page Current page number. * @param int $per_page How many results to show per page. */ public function get_items( $current_page, $per_page ) { global $wpdb; $this->max_items = 0; $this->items = array(); $stock = absint( max( get_option( 'woocommerce_notify_low_stock_amount' ), 0 ) ); $query_from = apply_filters( 'woocommerce_report_most_stocked_query_from', $wpdb->prepare( " FROM {$wpdb->posts} as posts INNER JOIN {$wpdb->wc_product_meta_lookup} AS lookup ON posts.ID = lookup.product_id WHERE 1=1 AND posts.post_type IN ( 'product', 'product_variation' ) AND posts.post_status = 'publish' AND lookup.stock_quantity > %d ", $stock ) ); $this->items = $wpdb->get_results( $wpdb->prepare( "SELECT SQL_CALC_FOUND_ROWS posts.ID as id, posts.post_parent as parent {$query_from} ORDER BY lookup.stock_quantity DESC, id ASC LIMIT %d, %d;", ( $current_page - 1 ) * $per_page, $per_page ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $this->max_items = $wpdb->get_var( 'SELECT FOUND_ROWS();' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } } class-wc-report-low-in-stock.php 0000644 00000003376 15134216707 0012645 0 ustar 00 <?php /** * WC_Report_Low_In_Stock. * * @package WooCommerce\Admin\Reports */ defined( 'ABSPATH' ) || exit; if ( ! class_exists( 'WC_Report_Stock' ) ) { require_once dirname( __FILE__ ) . '/class-wc-report-stock.php'; } /** * Low stock report class. */ class WC_Report_Low_In_Stock extends WC_Report_Stock { /** * No items found text. */ public function no_items() { esc_html_e( 'No low in stock products found.', 'woocommerce' ); } /** * Get Products matching stock criteria. * * @param int $current_page Current page number. * @param int $per_page How many results to show per page. */ public function get_items( $current_page, $per_page ) { global $wpdb; $this->max_items = 0; $this->items = array(); $stock = absint( max( get_option( 'woocommerce_notify_low_stock_amount' ), 1 ) ); $nostock = absint( max( get_option( 'woocommerce_notify_no_stock_amount' ), 0 ) ); $query_from = apply_filters( 'woocommerce_report_low_in_stock_query_from', $wpdb->prepare( " FROM {$wpdb->posts} as posts INNER JOIN {$wpdb->wc_product_meta_lookup} AS lookup ON posts.ID = lookup.product_id WHERE 1=1 AND posts.post_type IN ( 'product', 'product_variation' ) AND posts.post_status = 'publish' AND lookup.stock_quantity <= %d AND lookup.stock_quantity > %d ", $stock, $nostock ) ); $this->items = $wpdb->get_results( $wpdb->prepare( "SELECT SQL_CALC_FOUND_ROWS posts.ID as id, posts.post_parent as parent {$query_from} ORDER BY posts.post_title DESC LIMIT %d, %d;", ( $current_page - 1 ) * $per_page, $per_page ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $this->max_items = $wpdb->get_var( 'SELECT FOUND_ROWS();' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared } } class-wc-report-taxes-by-date.php 0000644 00000022316 15134216707 0012761 0 ustar 00 <?php if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } /** * WC_Report_Taxes_By_Date * * @author WooThemes * @category Admin * @package WooCommerce\Admin\Reports * @version 2.1.0 */ class WC_Report_Taxes_By_Date extends WC_Admin_Report { /** * Get the legend for the main chart sidebar. * * @return array */ public function get_chart_legend() { return array(); } /** * Output an export link. */ public function get_export_button() { $current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( $_GET['range'] ) : 'last_month'; ?> <a href="#" download="report-<?php echo esc_attr( $current_range ); ?>-<?php echo date_i18n( 'Y-m-d', current_time( 'timestamp' ) ); ?>.csv" class="export_csv" data-export="table" > <?php _e( 'Export CSV', 'woocommerce' ); ?> </a> <?php } /** * Output the report. */ public function output_report() { $ranges = array( 'year' => __( 'Year', 'woocommerce' ), 'last_month' => __( 'Last month', 'woocommerce' ), 'month' => __( 'This month', 'woocommerce' ), ); $current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( $_GET['range'] ) : 'last_month'; if ( ! in_array( $current_range, array( 'custom', 'year', 'last_month', 'month', '7day' ) ) ) { $current_range = 'last_month'; } $this->check_current_range_nonce( $current_range ); $this->calculate_current_range( $current_range ); $hide_sidebar = true; include WC()->plugin_path() . '/includes/admin/views/html-report-by-date.php'; } /** * Get the main chart. */ public function get_main_chart() { $query_data = array( '_order_tax' => array( 'type' => 'meta', 'function' => 'SUM', 'name' => 'tax_amount', ), '_order_shipping_tax' => array( 'type' => 'meta', 'function' => 'SUM', 'name' => 'shipping_tax_amount', ), '_order_total' => array( 'type' => 'meta', 'function' => 'SUM', 'name' => 'total_sales', ), '_order_shipping' => array( 'type' => 'meta', 'function' => 'SUM', 'name' => 'total_shipping', ), 'ID' => array( 'type' => 'post_data', 'function' => 'COUNT', 'name' => 'total_orders', 'distinct' => true, ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), ); // We exlude on-hold orders are they are still pending payment. $tax_rows_orders = $this->get_order_report_data( array( 'data' => $query_data, 'group_by' => $this->group_by_query, 'order_by' => 'post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, 'order_types' => wc_get_order_types( 'sales-reports' ), 'order_status' => array( 'completed', 'processing', 'refunded' ), ) ); $tax_rows_full_refunds = $this->get_order_report_data( array( 'data' => array( 'ID' => array( 'type' => 'post_data', 'distinct' => true, 'function' => '', 'name' => 'ID', ), 'post_parent' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_parent', ), 'post_date' => array( 'type' => 'post_data', 'function' => '', 'name' => 'post_date', ), ), 'query_type' => 'get_results', 'filter_range' => true, 'order_types' => array( 'shop_order_refund' ), 'parent_order_status' => array( 'refunded' ), ) ); $tax_rows_partial_refunds = $this->get_order_report_data( array( 'data' => $query_data, 'group_by' => $this->group_by_query, 'order_by' => 'post_date ASC', 'query_type' => 'get_results', 'filter_range' => true, 'order_types' => array( 'shop_order_refund' ), 'parent_order_status' => array( 'completed', 'processing' ), // Partial refunds inside refunded orders should be ignored. ) ); $tax_rows = array(); foreach ( $tax_rows_orders + $tax_rows_partial_refunds as $tax_row ) { $key = date( ( 'month' === $this->chart_groupby ) ? 'Ym' : 'Ymd', strtotime( $tax_row->post_date ) ); $tax_rows[ $key ] = isset( $tax_rows[ $key ] ) ? $tax_rows[ $key ] : (object) array( 'tax_amount' => 0, 'shipping_tax_amount' => 0, 'total_sales' => 0, 'total_shipping' => 0, 'total_orders' => 0, ); } foreach ( $tax_rows_orders as $tax_row ) { $key = date( ( 'month' === $this->chart_groupby ) ? 'Ym' : 'Ymd', strtotime( $tax_row->post_date ) ); $tax_rows[ $key ]->total_orders += $tax_row->total_orders; $tax_rows[ $key ]->tax_amount += $tax_row->tax_amount; $tax_rows[ $key ]->shipping_tax_amount += $tax_row->shipping_tax_amount; $tax_rows[ $key ]->total_sales += $tax_row->total_sales; $tax_rows[ $key ]->total_shipping += $tax_row->total_shipping; } foreach ( $tax_rows_partial_refunds as $tax_row ) { $key = date( ( 'month' === $this->chart_groupby ) ? 'Ym' : 'Ymd', strtotime( $tax_row->post_date ) ); $tax_rows[ $key ]->tax_amount += $tax_row->tax_amount; $tax_rows[ $key ]->shipping_tax_amount += $tax_row->shipping_tax_amount; $tax_rows[ $key ]->total_sales += $tax_row->total_sales; $tax_rows[ $key ]->total_shipping += $tax_row->total_shipping; } foreach ( $tax_rows_full_refunds as $tax_row ) { $key = date( ( 'month' === $this->chart_groupby ) ? 'Ym' : 'Ymd', strtotime( $tax_row->post_date ) ); $tax_rows[ $key ] = isset( $tax_rows[ $key ] ) ? $tax_rows[ $key ] : (object) array( 'tax_amount' => 0, 'shipping_tax_amount' => 0, 'total_sales' => 0, 'total_shipping' => 0, 'total_orders' => 0, ); $parent_order = wc_get_order( $tax_row->post_parent ); if ( $parent_order ) { $tax_rows[ $key ]->tax_amount += $parent_order->get_cart_tax() * -1; $tax_rows[ $key ]->shipping_tax_amount += $parent_order->get_shipping_tax() * -1; $tax_rows[ $key ]->total_sales += $parent_order->get_total() * -1; $tax_rows[ $key ]->total_shipping += $parent_order->get_shipping_total() * -1; } } ?> <table class="widefat"> <thead> <tr> <th><?php _e( 'Period', 'woocommerce' ); ?></th> <th class="total_row"><?php _e( 'Number of orders', 'woocommerce' ); ?></th> <th class="total_row"><?php _e( 'Total sales', 'woocommerce' ); ?> <?php echo wc_help_tip( __( "This is the sum of the 'Order total' field within your orders.", 'woocommerce' ) ); ?></th> <th class="total_row"><?php _e( 'Total shipping', 'woocommerce' ); ?> <?php echo wc_help_tip( __( "This is the sum of the 'Shipping total' field within your orders.", 'woocommerce' ) ); ?></th> <th class="total_row"><?php _e( 'Total tax', 'woocommerce' ); ?> <?php echo wc_help_tip( __( 'This is the total tax for the rate (shipping tax + product tax).', 'woocommerce' ) ); ?></th> <th class="total_row"><?php _e( 'Net profit', 'woocommerce' ); ?> <?php echo wc_help_tip( __( 'Total sales minus shipping and tax.', 'woocommerce' ) ); ?></th> </tr> </thead> <?php if ( ! empty( $tax_rows ) ) : ?> <tbody> <?php foreach ( $tax_rows as $date => $tax_row ) { $gross = $tax_row->total_sales - $tax_row->total_shipping; $total_tax = $tax_row->tax_amount + $tax_row->shipping_tax_amount; ?> <tr> <th scope="row"> <?php echo ( 'month' === $this->chart_groupby ) ? date_i18n( 'F', strtotime( $date . '01' ) ) : date_i18n( get_option( 'date_format' ), strtotime( $date ) ); ?> </th> <td class="total_row"><?php echo $tax_row->total_orders; ?></td> <td class="total_row"><?php echo wc_price( $gross ); ?></td> <td class="total_row"><?php echo wc_price( $tax_row->total_shipping ); ?></td> <td class="total_row"><?php echo wc_price( $total_tax ); ?></td> <td class="total_row"><?php echo wc_price( $gross - $total_tax ); ?></td> </tr> <?php } ?> </tbody> <tfoot> <?php $gross = array_sum( wp_list_pluck( (array) $tax_rows, 'total_sales' ) ) - array_sum( wp_list_pluck( (array) $tax_rows, 'total_shipping' ) ); $total_tax = array_sum( wp_list_pluck( (array) $tax_rows, 'tax_amount' ) ) + array_sum( wp_list_pluck( (array) $tax_rows, 'shipping_tax_amount' ) ); ?> <tr> <th scope="row"><?php _e( 'Totals', 'woocommerce' ); ?></th> <th class="total_row"><?php echo array_sum( wp_list_pluck( (array) $tax_rows, 'total_orders' ) ); ?></th> <th class="total_row"><?php echo wc_price( $gross ); ?></th> <th class="total_row"><?php echo wc_price( array_sum( wp_list_pluck( (array) $tax_rows, 'total_shipping' ) ) ); ?></th> <th class="total_row"><?php echo wc_price( $total_tax ); ?></th> <th class="total_row"><?php echo wc_price( $gross - $total_tax ); ?></th> </tr> </tfoot> <?php else : ?> <tbody> <tr> <td><?php _e( 'No taxes found in this period', 'woocommerce' ); ?></td> </tr> </tbody> <?php endif; ?> </table> <?php } } class-wc-report-customer-list.php 0000644 00000021062 15134216707 0013121 0 ustar 00 <?php /** * Class WC_Report_Customer_List file. * * @package WooCommerce\Reports */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } if ( ! class_exists( 'WP_List_Table' ) ) { require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php'; } /** * WC_Report_Customer_List. * * @package WooCommerce\Admin\Reports * @version 2.1.0 */ class WC_Report_Customer_List extends WP_List_Table { /** * Constructor. */ public function __construct() { parent::__construct( array( 'singular' => 'customer', 'plural' => 'customers', 'ajax' => false, ) ); } /** * No items found text. */ public function no_items() { esc_html_e( 'No customers found.', 'woocommerce' ); } /** * Output the report. */ public function output_report() { $this->prepare_items(); echo '<div id="poststuff" class="woocommerce-reports-wide">'; if ( ! empty( $_GET['link_orders'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'link_orders' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput $linked = wc_update_new_customer_past_orders( absint( $_GET['link_orders'] ) ); /* translators: single or plural number of orders */ echo '<div class="updated"><p>' . sprintf( esc_html( _n( '%s previous order linked', '%s previous orders linked', $linked, 'woocommerce' ), $linked ) ) . '</p></div>'; } if ( ! empty( $_GET['refresh'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'refresh' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput $user_id = absint( $_GET['refresh'] ); $user = get_user_by( 'id', $user_id ); delete_user_meta( $user_id, '_money_spent' ); delete_user_meta( $user_id, '_order_count' ); delete_user_meta( $user_id, '_last_order' ); /* translators: User display name */ echo '<div class="updated"><p>' . sprintf( esc_html__( 'Refreshed stats for %s', 'woocommerce' ), esc_html( $user->display_name ) ) . '</p></div>'; } echo '<form method="post" id="woocommerce_customers">'; $this->search_box( __( 'Search customers', 'woocommerce' ), 'customer_search' ); $this->display(); echo '</form>'; echo '</div>'; } /** * Get column value. * * @param WP_User $user WP User object. * @param string $column_name Column name. * @return string */ public function column_default( $user, $column_name ) { switch ( $column_name ) { case 'customer_name': if ( $user->last_name && $user->first_name ) { return $user->last_name . ', ' . $user->first_name; } else { return '-'; } case 'username': return $user->user_login; case 'location': $state_code = get_user_meta( $user->ID, 'billing_state', true ); $country_code = get_user_meta( $user->ID, 'billing_country', true ); $state = isset( WC()->countries->states[ $country_code ][ $state_code ] ) ? WC()->countries->states[ $country_code ][ $state_code ] : $state_code; $country = isset( WC()->countries->countries[ $country_code ] ) ? WC()->countries->countries[ $country_code ] : $country_code; $value = ''; if ( $state ) { $value .= $state . ', '; } $value .= $country; if ( $value ) { return $value; } else { return '-'; } case 'email': return '<a href="mailto:' . $user->user_email . '">' . $user->user_email . '</a>'; case 'spent': return wc_price( wc_get_customer_total_spent( $user->ID ) ); case 'orders': return wc_get_customer_order_count( $user->ID ); case 'last_order': $orders = wc_get_orders( array( 'limit' => 1, 'status' => array_map( 'wc_get_order_status_name', wc_get_is_paid_statuses() ), 'customer' => $user->ID, ) ); if ( ! empty( $orders ) ) { $order = $orders[0]; return '<a href="' . admin_url( 'post.php?post=' . $order->get_id() . '&action=edit' ) . '">' . _x( '#', 'hash before order number', 'woocommerce' ) . $order->get_order_number() . '</a> – ' . wc_format_datetime( $order->get_date_created() ); } else { return '-'; } break; case 'wc_actions': ob_start(); ?><p> <?php do_action( 'woocommerce_admin_user_actions_start', $user ); $actions = array(); $actions['refresh'] = array( 'url' => wp_nonce_url( add_query_arg( 'refresh', $user->ID ), 'refresh' ), 'name' => __( 'Refresh stats', 'woocommerce' ), 'action' => 'refresh', ); $actions['edit'] = array( 'url' => admin_url( 'user-edit.php?user_id=' . $user->ID ), 'name' => __( 'Edit', 'woocommerce' ), 'action' => 'edit', ); $actions['view'] = array( 'url' => admin_url( 'edit.php?post_type=shop_order&_customer_user=' . $user->ID ), 'name' => __( 'View orders', 'woocommerce' ), 'action' => 'view', ); $orders = wc_get_orders( array( 'limit' => 1, 'status' => array_map( 'wc_get_order_status_name', wc_get_is_paid_statuses() ), 'customer' => array( array( 0, $user->user_email ) ), ) ); if ( $orders ) { $actions['link'] = array( 'url' => wp_nonce_url( add_query_arg( 'link_orders', $user->ID ), 'link_orders' ), 'name' => __( 'Link previous orders', 'woocommerce' ), 'action' => 'link', ); } $actions = apply_filters( 'woocommerce_admin_user_actions', $actions, $user ); foreach ( $actions as $action ) { printf( '<a class="button tips %s" href="%s" data-tip="%s">%s</a>', esc_attr( $action['action'] ), esc_url( $action['url'] ), esc_attr( $action['name'] ), esc_attr( $action['name'] ) ); } do_action( 'woocommerce_admin_user_actions_end', $user ); ?> </p> <?php $user_actions = ob_get_contents(); ob_end_clean(); return $user_actions; } return ''; } /** * Get columns. * * @return array */ public function get_columns() { $columns = array( 'customer_name' => __( 'Name (Last, First)', 'woocommerce' ), 'username' => __( 'Username', 'woocommerce' ), 'email' => __( 'Email', 'woocommerce' ), 'location' => __( 'Location', 'woocommerce' ), 'orders' => __( 'Orders', 'woocommerce' ), 'spent' => __( 'Money spent', 'woocommerce' ), 'last_order' => __( 'Last order', 'woocommerce' ), 'wc_actions' => __( 'Actions', 'woocommerce' ), ); return $columns; } /** * Order users by name. * * @param WP_User_Query $query Query that gets passed through. * @return WP_User_Query */ public function order_by_last_name( $query ) { global $wpdb; $s = ! empty( $_REQUEST['s'] ) ? wp_unslash( $_REQUEST['s'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $query->query_from .= " LEFT JOIN {$wpdb->usermeta} as meta2 ON ({$wpdb->users}.ID = meta2.user_id) "; $query->query_where .= " AND meta2.meta_key = 'last_name' "; $query->query_orderby = ' ORDER BY meta2.meta_value, user_login ASC '; if ( $s ) { $query->query_from .= " LEFT JOIN {$wpdb->usermeta} as meta3 ON ({$wpdb->users}.ID = meta3.user_id)"; $query->query_where .= " AND ( user_login LIKE '%" . esc_sql( str_replace( '*', '', $s ) ) . "%' OR user_nicename LIKE '%" . esc_sql( str_replace( '*', '', $s ) ) . "%' OR meta3.meta_value LIKE '%" . esc_sql( str_replace( '*', '', $s ) ) . "%' ) "; $query->query_orderby = ' GROUP BY ID ' . $query->query_orderby; } return $query; } /** * Prepare customer list items. */ public function prepare_items() { $current_page = absint( $this->get_pagenum() ); $per_page = 20; /** * Init column headers. */ $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() ); add_action( 'pre_user_query', array( $this, 'order_by_last_name' ) ); /** * Get users. */ $admin_users = new WP_User_Query( array( 'role' => 'administrator', 'fields' => 'ID', ) ); $manager_users = new WP_User_Query( array( 'role' => 'shop_manager', 'fields' => 'ID', ) ); $query = new WP_User_Query( apply_filters( 'woocommerce_admin_report_customer_list_user_query_args', array( 'exclude' => array_merge( $admin_users->get_results(), $manager_users->get_results() ), 'number' => $per_page, 'offset' => ( $current_page - 1 ) * $per_page, ) ) ); $this->items = $query->get_results(); remove_action( 'pre_user_query', array( $this, 'order_by_last_name' ) ); /** * Pagination. */ $this->set_pagination_args( array( 'total_items' => $query->total_users, 'per_page' => $per_page, 'total_pages' => ceil( $query->total_users / $per_page ), ) ); } }
| ver. 1.4 |
Github
|
.
| PHP 8.2.29 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка