2013-06-26 14:11:33 +00:00
< ? php
2014-09-20 19:58:32 +00:00
if ( ! defined ( 'ABSPATH' ) ) {
exit ; // Exit if accessed directly
}
2014-02-14 13:02:37 +00:00
2013-06-26 14:11:33 +00:00
/**
2015-11-03 12:28:01 +00:00
* Admin Report .
2013-06-26 14:11:33 +00:00
*
* Extended by reports to show charts and stats in admin .
*
2014-08-31 07:19:13 +00:00
* @ author WooThemes
* @ category Admin
2020-08-05 16:36:24 +00:00
* @ package WooCommerce\Admin\Reports
2013-06-26 14:11:33 +00:00
* @ version 2.1 . 0
*/
class WC_Admin_Report {
2019-03-13 10:33:03 +00:00
/**
2019-03-14 15:44:26 +00:00
* @ var array List of transients name that have been updated and need persisting .
2019-03-13 10:33:03 +00:00
*/
2019-03-14 15:44:26 +00:00
protected static $transients_to_update = array ();
2019-06-27 13:48:31 +00:00
2019-03-14 15:44:26 +00:00
/**
* @ var array The list of transients .
*/
protected static $cached_results = array ();
2019-03-13 10:33:03 +00:00
2016-01-05 08:48:39 +00:00
/**
* The chart interval .
*
* @ var int
*/
2014-02-12 12:26:32 +00:00
public $chart_interval ;
2016-01-05 08:48:39 +00:00
/**
* Group by SQL query .
*
* @ var string
*/
2014-02-12 12:26:32 +00:00
public $group_by_query ;
2016-01-05 08:48:39 +00:00
/**
* The bar width .
*
* @ var int
*/
2014-02-12 12:26:32 +00:00
public $barwidth ;
2016-01-05 08:48:39 +00:00
/**
* Group chart item by day or month .
*
* @ var string
*/
2014-02-12 12:26:32 +00:00
public $chart_groupby ;
2016-01-05 08:48:39 +00:00
/**
* The start date of the report .
*
2016-06-06 18:15:40 +00:00
* @ var int timestamp
2016-01-05 08:48:39 +00:00
*/
2013-06-26 14:11:33 +00:00
public $start_date ;
2016-01-05 08:48:39 +00:00
/**
* The end date of the report .
*
2016-06-06 18:15:40 +00:00
* @ var int timestamp
2016-01-05 08:48:39 +00:00
*/
2013-06-26 14:11:33 +00:00
public $end_date ;
/**
* Get report totals such as order totals and discount amounts .
*
2015-11-03 13:31:20 +00:00
* Data example :
2013-06-26 14:11:33 +00:00
*
* '_order_total' => array (
2014-08-31 07:19:13 +00:00
* 'type' => 'meta' ,
* 'function' => 'SUM' ,
* 'name' => 'total_sales'
2013-06-26 14:11:33 +00:00
* )
*
* @ param array $args
2015-04-01 13:33:56 +00:00
* @ return mixed depending on query_type
2013-06-26 14:11:33 +00:00
*/
public function get_order_report_data ( $args = array () ) {
global $wpdb ;
2014-10-07 09:48:44 +00:00
$default_args = array (
2014-10-14 15:39:57 +00:00
'data' => array (),
'where' => array (),
'where_meta' => array (),
'query_type' => 'get_row' ,
'group_by' => '' ,
'order_by' => '' ,
'limit' => '' ,
'filter_range' => false ,
2014-10-14 16:01:15 +00:00
'nocache' => false ,
2014-10-14 15:39:57 +00:00
'debug' => false ,
'order_types' => wc_get_order_types ( 'reports' ),
'order_status' => array ( 'completed' , 'processing' , 'on-hold' ),
'parent_order_status' => false ,
2013-06-26 14:11:33 +00:00
);
2018-03-05 18:59:17 +00:00
$args = apply_filters ( 'woocommerce_reports_get_order_report_data_args' , $args );
$args = wp_parse_args ( $args , $default_args );
2013-06-26 14:11:33 +00:00
extract ( $args );
2014-05-28 14:19:16 +00:00
if ( empty ( $data ) ) {
2014-10-07 09:32:38 +00:00
return '' ;
2014-05-28 14:19:16 +00:00
}
2013-06-26 14:11:33 +00:00
2014-10-14 15:39:57 +00:00
$order_status = apply_filters ( 'woocommerce_reports_order_statuses' , $order_status );
2014-10-07 09:31:07 +00:00
$query = array ();
2013-06-26 14:11:33 +00:00
$select = array ();
2017-07-12 09:53:39 +00:00
foreach ( $data as $raw_key => $value ) {
$key = sanitize_key ( $raw_key );
2013-06-26 14:11:33 +00:00
$distinct = '' ;
2014-10-07 09:48:44 +00:00
if ( isset ( $value [ 'distinct' ] ) ) {
2013-06-26 14:11:33 +00:00
$distinct = 'DISTINCT' ;
2014-10-07 09:48:44 +00:00
}
2013-06-26 14:11:33 +00:00
2015-07-01 11:11:21 +00:00
switch ( $value [ 'type' ] ) {
2018-03-05 18:59:17 +00:00
case 'meta' :
2015-07-01 11:11:21 +00:00
$get_key = " meta_ { $key } .meta_value " ;
break ;
2018-03-05 18:59:17 +00:00
case 'parent_meta' :
2015-07-01 11:11:21 +00:00
$get_key = " parent_meta_ { $key } .meta_value " ;
break ;
2018-03-05 18:59:17 +00:00
case 'post_data' :
2015-07-01 11:11:21 +00:00
$get_key = " posts. { $key } " ;
break ;
2018-03-05 18:59:17 +00:00
case 'order_item_meta' :
2015-07-01 11:11:21 +00:00
$get_key = " order_item_meta_ { $key } .meta_value " ;
break ;
2018-03-05 18:59:17 +00:00
case 'order_item' :
2015-07-01 11:11:21 +00:00
$get_key = " order_items. { $key } " ;
break ;
2019-03-13 16:54:13 +00:00
}
2019-03-13 17:00:13 +00:00
2019-03-13 16:54:13 +00:00
if ( empty ( $get_key ) ) {
// Skip to the next foreach iteration else the query will be invalid.
continue ;
2014-08-31 07:19:13 +00:00
}
2013-06-28 16:33:37 +00:00
2014-08-31 07:19:13 +00:00
if ( $value [ 'function' ] ) {
2013-06-28 16:33:37 +00:00
$get = " { $value [ 'function' ] } ( { $distinct } { $get_key } ) " ;
2014-08-31 07:19:13 +00:00
} else {
2013-06-28 16:33:37 +00:00
$get = " { $distinct } { $get_key } " ;
2014-08-31 07:19:13 +00:00
}
2013-06-28 16:33:37 +00:00
$select [] = " { $get } as { $value [ 'name' ] } " ;
2013-06-26 14:11:33 +00:00
}
2018-03-05 18:59:17 +00:00
$query [ 'select' ] = 'SELECT ' . implode ( ',' , $select );
2013-06-26 14:11:33 +00:00
$query [ 'from' ] = " FROM { $wpdb -> posts } AS posts " ;
// Joins
2014-08-31 07:19:13 +00:00
$joins = array ();
2013-06-26 14:11:33 +00:00
2017-07-12 09:53:39 +00:00
foreach ( ( $data + $where ) as $raw_key => $value ) {
2015-07-01 11:11:21 +00:00
$join_type = isset ( $value [ 'join_type' ] ) ? $value [ 'join_type' ] : 'INNER' ;
$type = isset ( $value [ 'type' ] ) ? $value [ 'type' ] : false ;
2017-07-12 09:53:39 +00:00
$key = sanitize_key ( $raw_key );
2015-07-01 11:11:21 +00:00
switch ( $type ) {
2018-03-05 18:59:17 +00:00
case 'meta' :
2017-07-12 09:53:39 +00:00
$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 } ' ) " ;
2015-07-01 11:11:21 +00:00
break ;
2018-03-05 18:59:17 +00:00
case 'parent_meta' :
2017-07-12 09:53:39 +00:00
$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 } ') " ;
2015-07-01 11:11:21 +00:00
break ;
2018-03-05 18:59:17 +00:00
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) " ;
2015-07-01 11:11:21 +00:00
if ( ! empty ( $value [ 'order_item_type' ] ) ) {
2018-03-05 18:59:17 +00:00
$joins [ 'order_items' ] .= " AND (order_items.order_item_type = ' { $value [ 'order_item_type' ] } ') " ;
2015-07-01 11:11:21 +00:00
}
2018-03-05 18:59:17 +00:00
$joins [ " order_item_meta_ { $key } " ] = " { $join_type } JOIN { $wpdb -> prefix } woocommerce_order_itemmeta AS order_item_meta_ { $key } ON " .
2015-07-01 11:11:21 +00:00
" (order_items.order_item_id = order_item_meta_ { $key } .order_item_id) " .
2017-07-12 09:53:39 +00:00
" AND (order_item_meta_ { $key } .meta_key = ' { $raw_key } ') " ;
2015-07-01 11:11:21 +00:00
break ;
2018-03-05 18:59:17 +00:00
case 'order_item' :
$joins [ 'order_items' ] = " { $join_type } JOIN { $wpdb -> prefix } woocommerce_order_items AS order_items ON posts.ID = order_items.order_id " ;
2015-07-01 11:11:21 +00:00
break ;
2013-06-26 14:11:33 +00:00
}
}
if ( ! empty ( $where_meta ) ) {
foreach ( $where_meta as $value ) {
2014-08-31 07:19:13 +00:00
if ( ! is_array ( $value ) ) {
2013-07-18 13:04:18 +00:00
continue ;
2014-08-31 07:19:13 +00:00
}
2015-07-01 11:11:21 +00:00
$join_type = isset ( $value [ 'join_type' ] ) ? $value [ 'join_type' ] : 'INNER' ;
$type = isset ( $value [ 'type' ] ) ? $value [ 'type' ] : false ;
2017-07-12 09:53:39 +00:00
$key = sanitize_key ( is_array ( $value [ 'meta_key' ] ) ? $value [ 'meta_key' ][ 0 ] . '_array' : $value [ 'meta_key' ] );
2013-07-25 14:00:23 +00:00
2015-07-01 11:11:21 +00:00
if ( 'order_item_meta' === $type ) {
2013-06-26 14:11:33 +00:00
2018-03-05 18:59:17 +00:00
$joins [ 'order_items' ] = " { $join_type } JOIN { $wpdb -> prefix } woocommerce_order_items AS order_items ON posts.ID = order_items.order_id " ;
2016-08-27 03:11:30 +00:00
$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 " ;
2013-06-26 14:11:33 +00:00
} else {
// If we have a where clause for meta, join the postmeta table
2016-08-27 03:11:30 +00:00
$joins [ " meta_ { $key } " ] = " { $join_type } JOIN { $wpdb -> postmeta } AS meta_ { $key } ON posts.ID = meta_ { $key } .post_id " ;
2013-06-26 14:11:33 +00:00
}
}
}
2014-10-14 15:39:57 +00:00
if ( ! empty ( $parent_order_status ) ) {
2018-03-05 18:59:17 +00:00
$joins [ 'parent' ] = " LEFT JOIN { $wpdb -> posts } AS parent ON posts.post_parent = parent.ID " ;
2014-10-14 15:39:57 +00:00
}
2013-06-26 14:11:33 +00:00
$query [ 'join' ] = implode ( ' ' , $joins );
2018-03-05 18:59:17 +00:00
$query [ 'where' ] = "
2014-07-24 14:55:06 +00:00
WHERE posts . post_type IN ( '" . implode( "' , '", $order_types ) . "' )
2013-06-26 14:11:33 +00:00
" ;
2014-10-14 15:39:57 +00:00
if ( ! empty ( $order_status ) ) {
$query [ 'where' ] .= "
AND posts . post_status IN ( 'wc-" . implode( "' , 'wc-", $order_status ) . "' )
" ;
}
if ( ! empty ( $parent_order_status ) ) {
2015-04-24 14:58:13 +00:00
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 ) . " ') " ;
}
2014-10-14 15:39:57 +00:00
}
2013-06-26 14:11:33 +00:00
if ( $filter_range ) {
$query [ 'where' ] .= "
2017-01-10 15:50:03 +00:00
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 ) ) . "'
2013-06-26 14:11:33 +00:00
" ;
}
if ( ! empty ( $where_meta ) ) {
2014-08-31 07:19:13 +00:00
2013-07-18 13:04:18 +00:00
$relation = isset ( $where_meta [ 'relation' ] ) ? $where_meta [ 'relation' ] : 'AND' ;
2018-03-05 18:59:17 +00:00
$query [ 'where' ] .= ' AND (' ;
2013-07-18 13:04:18 +00:00
foreach ( $where_meta as $index => $value ) {
2014-08-31 07:19:13 +00:00
if ( ! is_array ( $value ) ) {
2013-07-18 13:04:18 +00:00
continue ;
2014-08-31 07:19:13 +00:00
}
2013-07-18 13:04:18 +00:00
2017-07-12 09:53:39 +00:00
$key = sanitize_key ( is_array ( $value [ 'meta_key' ] ) ? $value [ 'meta_key' ][ 0 ] . '_array' : $value [ 'meta_key' ] );
2013-07-25 14:00:23 +00:00
2016-07-05 23:15:39 +00:00
if ( strtolower ( $value [ 'operator' ] ) == 'in' || strtolower ( $value [ 'operator' ] ) == 'not in' ) {
2014-08-31 07:19:13 +00:00
if ( is_array ( $value [ 'meta_value' ] ) ) {
2013-06-26 14:11:33 +00:00
$value [ 'meta_value' ] = implode ( " ',' " , $value [ 'meta_value' ] );
2014-08-31 07:19:13 +00:00
}
if ( ! empty ( $value [ 'meta_value' ] ) ) {
2016-07-05 23:15:39 +00:00
$where_value = " { $value [ 'operator' ] } (' { $value [ 'meta_value' ] } ') " ;
2014-08-31 07:19:13 +00:00
}
2013-06-26 14:11:33 +00:00
} else {
$where_value = " { $value [ 'operator' ] } ' { $value [ 'meta_value' ] } ' " ;
}
2013-07-08 15:36:09 +00:00
if ( ! empty ( $where_value ) ) {
2014-08-31 07:19:13 +00:00
if ( $index > 0 ) {
2013-07-18 13:04:18 +00:00
$query [ 'where' ] .= ' ' . $relation ;
2014-08-31 07:19:13 +00:00
}
2013-07-18 13:04:18 +00:00
2016-09-09 00:14:28 +00:00
if ( isset ( $value [ 'type' ] ) && 'order_item_meta' === $value [ 'type' ] ) {
2014-08-31 07:19:13 +00:00
if ( is_array ( $value [ 'meta_key' ] ) ) {
2013-07-25 14:00:23 +00:00
$query [ 'where' ] .= " ( order_item_meta_ { $key } .meta_key IN (' " . implode ( " ',' " , $value [ 'meta_key' ] ) . " ') " ;
2014-08-31 07:19:13 +00:00
} else {
2013-07-25 14:00:23 +00:00
$query [ 'where' ] .= " ( order_item_meta_ { $key } .meta_key = ' { $value [ 'meta_key' ] } ' " ;
2014-08-31 07:19:13 +00:00
}
2013-07-25 14:00:23 +00:00
$query [ 'where' ] .= " AND order_item_meta_ { $key } .meta_value { $where_value } ) " ;
2013-07-08 15:36:09 +00:00
} else {
2014-08-31 07:19:13 +00:00
if ( is_array ( $value [ 'meta_key' ] ) ) {
2013-07-25 14:00:23 +00:00
$query [ 'where' ] .= " ( meta_ { $key } .meta_key IN (' " . implode ( " ',' " , $value [ 'meta_key' ] ) . " ') " ;
2014-08-31 07:19:13 +00:00
} else {
2013-07-25 14:00:23 +00:00
$query [ 'where' ] .= " ( meta_ { $key } .meta_key = ' { $value [ 'meta_key' ] } ' " ;
2014-08-31 07:19:13 +00:00
}
2013-07-25 14:00:23 +00:00
$query [ 'where' ] .= " AND meta_ { $key } .meta_value { $where_value } ) " ;
2013-07-08 15:36:09 +00:00
}
2013-06-26 14:11:33 +00:00
}
}
2013-07-18 13:04:18 +00:00
2018-03-05 18:59:17 +00:00
$query [ 'where' ] .= ')' ;
2013-06-26 14:11:33 +00:00
}
if ( ! empty ( $where ) ) {
2014-08-31 07:19:13 +00:00
2013-06-26 14:11:33 +00:00
foreach ( $where as $value ) {
2014-08-31 07:19:13 +00:00
2016-07-05 23:15:39 +00:00
if ( strtolower ( $value [ 'operator' ] ) == 'in' || strtolower ( $value [ 'operator' ] ) == 'not in' ) {
2014-08-31 07:19:13 +00:00
if ( is_array ( $value [ 'value' ] ) ) {
2013-06-26 14:11:33 +00:00
$value [ 'value' ] = implode ( " ',' " , $value [ 'value' ] );
2014-08-31 07:19:13 +00:00
}
if ( ! empty ( $value [ 'value' ] ) ) {
2016-07-05 23:15:39 +00:00
$where_value = " { $value [ 'operator' ] } (' { $value [ 'value' ] } ') " ;
2014-08-31 07:19:13 +00:00
}
2013-06-26 14:11:33 +00:00
} else {
$where_value = " { $value [ 'operator' ] } ' { $value [ 'value' ] } ' " ;
}
2017-03-07 20:24:24 +00:00
if ( ! empty ( $where_value ) ) {
2013-07-08 15:36:09 +00:00
$query [ 'where' ] .= " AND { $value [ 'key' ] } { $where_value } " ;
2017-03-07 20:24:24 +00:00
}
2013-06-26 14:11:33 +00:00
}
}
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 } " ;
}
2019-06-27 13:48:31 +00:00
$query = apply_filters ( 'woocommerce_reports_get_order_report_query' , $query );
$query = implode ( ' ' , $query );
2019-03-13 16:59:34 +00:00
2014-03-20 11:10:25 +00:00
if ( $debug ) {
2014-10-07 09:30:17 +00:00
echo '<pre>' ;
2016-12-16 21:51:20 +00:00
wc_print_r ( $query );
2014-10-07 09:30:17 +00:00
echo '</pre>' ;
2014-03-20 11:10:25 +00:00
}
2019-03-13 16:59:34 +00:00
2019-03-14 22:16:55 +00:00
if ( $debug || $nocache ) {
2019-03-13 16:52:28 +00:00
self :: enable_big_selects ();
2013-07-08 15:36:09 +00:00
2019-03-13 16:52:28 +00:00
$result = apply_filters ( 'woocommerce_reports_get_order_report_data' , $wpdb -> $query_type ( $query ), $data );
2019-03-14 22:16:55 +00:00
} else {
$query_hash = md5 ( $query_type . $query );
2019-06-27 13:48:31 +00:00
$result = $this -> get_cached_query ( $query_hash );
2019-03-14 22:16:55 +00:00
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 );
2019-03-13 16:52:28 +00:00
}
return $result ;
}
2019-03-13 16:59:34 +00:00
2019-03-14 15:44:26 +00:00
/**
* Init the static hooks of the class .
*/
protected static function add_update_transients_hook () {
2019-03-14 22:55:02 +00:00
if ( ! has_action ( 'shutdown' , array ( 'WC_Admin_Report' , 'maybe_update_transients' ) ) ) {
2019-03-14 22:05:54 +00:00
add_action ( 'shutdown' , array ( 'WC_Admin_Report' , 'maybe_update_transients' ) );
2019-03-14 15:44:26 +00:00
}
}
2019-06-27 13:48:31 +00:00
2019-03-13 16:52:28 +00:00
/**
2019-03-14 22:05:54 +00:00
* Enables big mysql selects for reports , just once for this session .
2019-03-13 16:52:28 +00:00
*/
protected static function enable_big_selects () {
static $big_selects = false ;
2019-02-20 12:00:47 +00:00
2019-03-13 16:52:28 +00:00
global $wpdb ;
if ( ! $big_selects ) {
$wpdb -> query ( 'SET SESSION SQL_BIG_SELECTS=1' );
$big_selects = true ;
}
}
/**
2019-03-14 22:05:54 +00:00
* Get the cached query result or null if it ' s not in the cache .
2019-03-13 18:06:47 +00:00
*
2019-03-14 22:18:47 +00:00
* @ param string $query_hash The query hash .
2019-03-13 16:52:28 +00:00
*
* @ return mixed
*/
2019-03-13 21:21:09 +00:00
protected function get_cached_query ( $query_hash ) {
2019-03-13 16:52:28 +00:00
$class = strtolower ( get_class ( $this ) );
2019-06-27 13:48:31 +00:00
2019-03-13 16:52:28 +00:00
if ( ! isset ( self :: $cached_results [ $class ] ) ) {
self :: $cached_results [ $class ] = get_transient ( strtolower ( get_class ( $this ) ) );
}
2019-06-27 13:48:31 +00:00
2019-03-13 21:21:09 +00:00
if ( isset ( self :: $cached_results [ $class ][ $query_hash ] ) ) {
2019-03-13 16:52:28 +00:00
return self :: $cached_results [ $class ][ $query_hash ];
}
2014-03-20 11:10:25 +00:00
2019-03-13 16:52:28 +00:00
return null ;
2013-06-26 14:11:33 +00:00
}
2019-03-13 21:28:09 +00:00
/**
2019-03-14 22:18:47 +00:00
* Set the cached query result .
2019-03-13 21:28:09 +00:00
*
2019-03-14 22:18:47 +00:00
* @ param string $query_hash The query hash .
* @ param mixed $data The data to cache .
2019-03-13 21:28:09 +00:00
*/
2019-03-13 21:21:09 +00:00
protected function set_cached_query ( $query_hash , $data ) {
$class = strtolower ( get_class ( $this ) );
2019-06-27 13:48:31 +00:00
2019-03-13 21:21:09 +00:00
if ( ! isset ( self :: $cached_results [ $class ] ) ) {
self :: $cached_results [ $class ] = get_transient ( strtolower ( get_class ( $this ) ) );
}
2019-06-27 13:48:31 +00:00
2019-03-13 21:21:09 +00:00
self :: add_update_transients_hook ();
2019-06-27 13:48:31 +00:00
2019-03-13 21:21:09 +00:00
self :: $transients_to_update [ $class ] = $class ;
self :: $cached_results [ $class ][ $query_hash ] = $data ;
}
2013-06-26 14:11:33 +00:00
2019-03-13 10:51:24 +00:00
/**
2019-03-13 12:47:00 +00:00
* Function to update the modified transients at the end of the request .
2019-03-13 10:51:24 +00:00
*/
2019-03-13 16:52:28 +00:00
public static function maybe_update_transients () {
2019-03-13 12:47:00 +00:00
foreach ( self :: $transients_to_update as $key => $transient_name ) {
2019-03-13 10:33:03 +00:00
set_transient ( $transient_name , self :: $cached_results [ $transient_name ], DAY_IN_SECONDS );
}
2019-03-13 16:52:28 +00:00
// Transients have been updated reset the list.
2019-03-13 12:47:00 +00:00
self :: $transients_to_update = array ();
2019-03-13 10:33:03 +00:00
}
2013-06-26 14:11:33 +00:00
/**
2015-11-03 12:28:01 +00:00
* Put data with post_date ' s into an array of times .
2013-06-26 14:11:33 +00:00
*
2018-03-05 18:59:17 +00:00
* @ param array $data array of your data
2013-06-26 14:11:33 +00:00
* @ param string $date_key key for the 'date' field . e . g . 'post_date'
* @ param string $data_key key for the data you are charting
2018-03-05 18:59:17 +00:00
* @ param int $interval
2013-06-26 14:11:33 +00:00
* @ param string $start_date
* @ param string $group_by
2016-01-05 08:48:39 +00:00
* @ return array
2013-06-26 14:11:33 +00:00
*/
public function prepare_chart_data ( $data , $date_key , $data_key , $interval , $start_date , $group_by ) {
$prepared_data = array ();
2014-07-23 17:17:01 +00:00
2016-12-16 12:35:33 +00:00
// 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 );
}
2013-06-26 14:11:33 +00:00
}
2016-12-16 12:35:33 +00:00
} else {
$current_yearnum = date ( 'Y' , $start_date );
$current_monthnum = date ( 'm' , $start_date );
2014-07-23 17:17:01 +00:00
2016-12-16 12:35:33 +00:00
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 ++ ;
}
2014-08-31 07:19:13 +00:00
}
2013-06-26 14:11:33 +00:00
}
foreach ( $data as $d ) {
switch ( $group_by ) {
2018-03-05 18:59:17 +00:00
case 'day' :
2014-02-28 14:51:37 +00:00
$time = strtotime ( date ( 'Ymd' , strtotime ( $d -> $date_key ) ) ) . '000' ;
2018-03-05 18:59:17 +00:00
break ;
case 'month' :
default :
2014-02-28 14:51:37 +00:00
$time = strtotime ( date ( 'Ym' , strtotime ( $d -> $date_key ) ) . '01' ) . '000' ;
2018-03-05 18:59:17 +00:00
break ;
2013-06-26 14:11:33 +00:00
}
2014-08-31 07:19:13 +00:00
if ( ! isset ( $prepared_data [ $time ] ) ) {
2013-06-26 14:11:33 +00:00
continue ;
2014-08-31 07:19:13 +00:00
}
2013-06-26 14:11:33 +00:00
2014-08-31 07:19:13 +00:00
if ( $data_key ) {
2013-07-09 14:31:22 +00:00
$prepared_data [ $time ][ 1 ] += $d -> $data_key ;
2014-08-31 07:19:13 +00:00
} else {
2013-07-09 14:31:22 +00:00
$prepared_data [ $time ][ 1 ] ++ ;
2014-08-31 07:19:13 +00:00
}
2013-06-26 14:11:33 +00:00
}
return $prepared_data ;
}
/**
2015-11-03 12:28:01 +00:00
* Prepares a sparkline to show sales in the last X days .
2013-06-26 14:11:33 +00:00
*
2018-03-05 18:59:17 +00:00
* @ param int $id ID of the product to show . Blank to get all orders .
* @ param int $days Days of stats to get .
2013-07-25 14:00:23 +00:00
* @ param string $type Type of sparkline to get . Ignored if ID is not set .
* @ return string
2013-06-26 14:11:33 +00:00
*/
2013-07-25 14:00:23 +00:00
public function sales_sparkline ( $id = '' , $days = 7 , $type = 'sales' ) {
if ( $id ) {
2016-09-09 00:14:28 +00:00
$meta_key = ( 'sales' === $type ) ? '_line_total' : '_qty' ;
2013-07-25 14:00:23 +00:00
2018-03-05 18:59:17 +00:00
$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' ,
),
2013-07-25 14:00:23 +00:00
),
2018-03-05 18:59:17 +00:00
'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' => '=' ,
),
2013-07-25 14:00:23 +00:00
),
2018-03-05 18:59:17 +00:00
'group_by' => 'YEAR(posts.post_date), MONTH(posts.post_date), DAY(posts.post_date)' ,
'query_type' => 'get_results' ,
'filter_range' => false ,
)
);
2013-07-25 14:00:23 +00:00
} else {
2014-08-31 07:19:13 +00:00
2018-03-05 18:59:17 +00:00
$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' ,
),
2013-07-25 14:00:23 +00:00
),
2018-03-05 18:59:17 +00:00
'where' => array (
array (
'key' => 'post_date' ,
'value' => date ( 'Y-m-d' , strtotime ( 'midnight -' . ( $days - 1 ) . ' days' , current_time ( 'timestamp' ) ) ),
'operator' => '>' ,
),
2016-08-27 02:08:49 +00:00
),
2018-03-05 18:59:17 +00:00
'group_by' => 'YEAR(posts.post_date), MONTH(posts.post_date), DAY(posts.post_date)' ,
'query_type' => 'get_results' ,
'filter_range' => false ,
)
);
2013-07-25 14:00:23 +00:00
}
2013-06-26 14:11:33 +00:00
$total = 0 ;
2014-08-31 07:19:13 +00:00
foreach ( $data as $d ) {
2013-07-25 14:00:23 +00:00
$total += $d -> sparkline_value ;
2014-08-31 07:19:13 +00:00
}
2013-06-26 14:11:33 +00:00
2016-09-09 00:14:28 +00:00
if ( 'sales' === $type ) {
2016-10-29 20:03:28 +00:00
/* translators: 1: total income 2: days */
2016-09-01 20:50:14 +00:00
$tooltip = sprintf ( __ ( 'Sold %1$s worth in the last %2$d days' , 'woocommerce' ), strip_tags ( wc_price ( $total ) ), $days );
2013-06-26 14:11:33 +00:00
} else {
2016-10-29 20:03:28 +00:00
/* translators: 1: total items sold 2: days */
2019-06-27 14:00:07 +00:00
$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 );
2013-06-26 14:11:33 +00:00
}
2013-07-25 14:00:23 +00:00
$sparkline_data = array_values ( $this -> prepare_chart_data ( $data , 'post_date' , 'sparkline_value' , $days - 1 , strtotime ( 'midnight -' . ( $days - 1 ) . ' days' , current_time ( 'timestamp' ) ), 'day' ) );
2013-06-26 14:11:33 +00:00
2019-02-20 12:00:47 +00:00
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>' ;
2013-06-26 14:11:33 +00:00
}
2013-07-30 10:12:42 +00:00
/**
2015-11-03 12:28:01 +00:00
* Get the current range and calculate the start and end dates .
2013-07-30 10:12:42 +00:00
*
* @ param string $current_range
*/
public function calculate_current_range ( $current_range ) {
2014-08-31 07:19:13 +00:00
2013-07-30 10:12:42 +00:00
switch ( $current_range ) {
2014-08-31 07:19:13 +00:00
2018-03-05 18:59:17 +00:00
case 'custom' :
2017-04-03 09:46:37 +00:00
$this -> start_date = max ( strtotime ( '-20 years' ), strtotime ( sanitize_text_field ( $_GET [ 'start_date' ] ) ) );
2013-07-30 10:12:42 +00:00
2017-03-27 11:11:08 +00:00
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' ] ) ) );
2014-08-31 07:19:13 +00:00
}
2013-07-30 10:12:42 +00:00
$interval = 0 ;
$min_date = $this -> start_date ;
2014-08-31 07:19:13 +00:00
2018-03-05 18:59:17 +00:00
while ( ( $min_date = strtotime ( '+1 MONTH' , $min_date ) ) <= $this -> end_date ) {
2014-08-31 07:19:13 +00:00
$interval ++ ;
2013-07-30 10:12:42 +00:00
}
// 3 months max for day view
2014-08-31 07:19:13 +00:00
if ( $interval > 3 ) {
$this -> chart_groupby = 'month' ;
} else {
$this -> chart_groupby = 'day' ;
}
2018-03-05 18:59:17 +00:00
break ;
2014-08-31 07:19:13 +00:00
2018-03-05 18:59:17 +00:00
case 'year' :
2016-09-02 01:51:31 +00:00
$this -> start_date = strtotime ( date ( 'Y-01-01' , current_time ( 'timestamp' ) ) );
2013-07-30 10:12:42 +00:00
$this -> end_date = strtotime ( 'midnight' , current_time ( 'timestamp' ) );
$this -> chart_groupby = 'month' ;
2018-03-05 18:59:17 +00:00
break ;
2014-08-31 07:19:13 +00:00
2018-03-05 18:59:17 +00:00
case 'last_month' :
2015-03-31 12:12:59 +00:00
$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' ;
2018-03-05 18:59:17 +00:00
break ;
2014-08-31 07:19:13 +00:00
2018-03-05 18:59:17 +00:00
case 'month' :
2016-09-02 01:51:31 +00:00
$this -> start_date = strtotime ( date ( 'Y-m-01' , current_time ( 'timestamp' ) ) );
2014-08-31 07:19:13 +00:00
$this -> end_date = strtotime ( 'midnight' , current_time ( 'timestamp' ) );
$this -> chart_groupby = 'day' ;
2018-03-05 18:59:17 +00:00
break ;
2014-08-31 07:19:13 +00:00
2018-03-05 18:59:17 +00:00
case '7day' :
2017-06-30 10:34:07 +00:00
$this -> start_date = strtotime ( '-6 days' , strtotime ( 'midnight' , current_time ( 'timestamp' ) ) );
2014-08-31 07:19:13 +00:00
$this -> end_date = strtotime ( 'midnight' , current_time ( 'timestamp' ) );
$this -> chart_groupby = 'day' ;
2018-03-05 18:59:17 +00:00
break ;
2013-07-30 10:12:42 +00:00
}
// Group by
switch ( $this -> chart_groupby ) {
2014-08-31 07:19:13 +00:00
2018-03-05 18:59:17 +00:00
case 'day' :
2014-10-14 15:39:57 +00:00
$this -> group_by_query = 'YEAR(posts.post_date), MONTH(posts.post_date), DAY(posts.post_date)' ;
2016-06-07 13:02:02 +00:00
$this -> chart_interval = absint ( ceil ( max ( 0 , ( $this -> end_date - $this -> start_date ) / ( 60 * 60 * 24 ) ) ) );
2014-08-31 07:19:13 +00:00
$this -> barwidth = 60 * 60 * 24 * 1000 ;
2018-03-05 18:59:17 +00:00
break ;
2014-08-31 07:19:13 +00:00
2018-03-05 18:59:17 +00:00
case 'month' :
2014-10-14 15:39:57 +00:00
$this -> group_by_query = 'YEAR(posts.post_date), MONTH(posts.post_date)' ;
2013-07-30 10:12:42 +00:00
$this -> chart_interval = 0 ;
2016-12-16 12:35:33 +00:00
$min_date = strtotime ( date ( 'Y-m-01' , $this -> start_date ) );
2014-08-31 07:19:13 +00:00
2018-03-05 18:59:17 +00:00
while ( ( $min_date = strtotime ( '+1 MONTH' , $min_date ) ) <= $this -> end_date ) {
2013-07-30 10:12:42 +00:00
$this -> chart_interval ++ ;
}
2014-08-31 07:19:13 +00:00
$this -> barwidth = 60 * 60 * 24 * 7 * 4 * 1000 ;
2018-03-05 18:59:17 +00:00
break ;
2013-07-30 10:12:42 +00:00
}
}
2014-09-19 07:23:58 +00:00
/**
* Return currency tooltip JS based on WooCommerce currency position settings .
*
* @ return string
*/
public function get_currency_tooltip () {
2016-08-27 04:23:02 +00:00
switch ( get_option ( 'woocommerce_currency_pos' ) ) {
2014-09-19 07:23:58 +00:00
case 'right' :
2016-09-02 03:40:52 +00:00
$currency_tooltip = 'append_tooltip: "' . get_woocommerce_currency_symbol () . '"' ;
break ;
2014-09-19 07:23:58 +00:00
case 'right_space' :
2016-09-02 03:40:52 +00:00
$currency_tooltip = 'append_tooltip: " ' . get_woocommerce_currency_symbol () . '"' ;
break ;
2014-10-16 06:56:28 +00:00
case 'left' :
2016-09-02 03:40:52 +00:00
$currency_tooltip = 'prepend_tooltip: "' . get_woocommerce_currency_symbol () . '"' ;
break ;
2014-10-16 06:56:28 +00:00
case 'left_space' :
default :
2016-09-02 03:40:52 +00:00
$currency_tooltip = 'prepend_tooltip: "' . get_woocommerce_currency_symbol () . ' "' ;
break ;
2014-09-19 07:23:58 +00:00
}
return $currency_tooltip ;
}
2013-06-26 14:11:33 +00:00
/**
2015-11-03 12:28:01 +00:00
* Get the main chart .
2013-06-26 14:11:33 +00:00
*/
public function get_main_chart () {}
/**
2015-11-03 12:28:01 +00:00
* Get the legend for the main chart sidebar .
2014-08-31 07:19:13 +00:00
*
2013-06-26 14:11:33 +00:00
* @ return array
*/
public function get_chart_legend () {
return array ();
}
/**
2016-01-05 08:48:39 +00:00
* Get chart widgets .
2014-08-31 07:19:13 +00:00
*
2013-06-26 14:11:33 +00:00
* @ return array
*/
public function get_chart_widgets () {
return array ();
}
2013-07-18 11:56:12 +00:00
/**
2015-11-03 12:28:01 +00:00
* Get an export link if needed .
2013-07-18 11:56:12 +00:00
*/
public function get_export_button () {}
2013-06-26 14:11:33 +00:00
/**
2015-11-03 12:28:01 +00:00
* Output the report .
2013-06-26 14:11:33 +00:00
*/
public function output_report () {}
2017-04-18 23:33:25 +00:00
/**
* 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 ;
}
2017-11-22 11:30:22 +00:00
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' )
);
2017-04-18 23:33:25 +00:00
exit ;
}
}
2013-11-21 13:28:09 +00:00
}