2022-11-27 15:03:07 +00:00
< ? php
/**
* Reports functions .
*
* @ package EDD
* @ subpackage Admin / Reports
* @ copyright Copyright ( c ) 2018 , Easy Digital Downloads , LLC
* @ license http :// opensource . org / licenses / gpl - 2.0 . php GNU Public License
* @ since 1.0
* @ since 3.0 Full refactor of Reports .
*/
use EDD\Reports ;
// Exit if accessed directly
defined ( 'ABSPATH' ) || exit ;
/**
* Load a report early in the admin - area .
*
* This action - function loads the Report early , so that a redirect can occur in
* the event that the report is not valid , registered , or the user cannot view
* it .
*
* Note that pre - 3.0 reports are shimmed via EDD\Reports :: legacy_reports ()
*
* @ since 3.0
*/
function edd_admin_load_report () {
// Redirect URL (on error)
$redirect_url = edd_get_admin_url ( array (
'page' => 'edd-reports'
) );
// Redirect if user cannot view reports
if ( ! current_user_can ( 'view_shop_reports' ) ) {
edd_redirect ( $redirect_url );
}
// Start the Reports API.
new Reports\Init ();
add_filter ( 'edd_admin_is_single_view' , '__return_false' );
// Get the section and report
$section = Reports\get_current_report ();
$report = Reports\get_report ( $section );
// Redirect if report is invalid
if ( empty ( $report ) || is_wp_error ( $report ) ) {
edd_redirect ( $redirect_url );
}
// Stash the report in the EDD global for future reference
EDD () -> report = $report ;
}
add_action ( 'load-download_page_edd-reports' , 'edd_admin_load_report' );
/**
* Contains backwards compat code to shim tabs & views to EDD_Sections ()
*
* @ since 3.0
*/
function edd_reports_sections () {
// Instantiate the Sections class and sections array
$sections = new EDD\Admin\Reports_Sections ();
$c_sections = array ();
// Setup sections variables
$sections -> use_js = false ;
$sections -> current_section = Reports\get_current_report ();
$sections -> item = null ;
// Find persisted filters to append to the base URL.
$persisted_filters = Reports\get_persisted_filters ();
$persisted_filter_args = array ();
foreach ( $persisted_filters as $filter ) {
if ( isset ( $_GET [ $filter ] ) ) {
$persisted_filter_args [ $filter ] = sanitize_text_field ( $_GET [ $filter ] );
}
}
// Build the section base URL.
$sections -> base_url = edd_get_admin_url (
array_merge (
array (
'page' => 'edd-reports' ,
),
$persisted_filter_args
)
);
// Get all registered tabs & views
$tabs = Reports\get_reports ();
// Loop through tabs & setup sections
if ( ! empty ( $tabs ) ) {
foreach ( $tabs as $id => $tab ) {
// Add to sections array
$c_sections [] = array (
'id' => $id ,
'label' => $tab [ 'label' ],
'icon' => $tab [ 'icon' ],
'callback' => array ( 'edd_output_report_callback' , array ( $id ) )
);
}
}
// Set the customer sections
$sections -> set_sections ( $c_sections );
// Display the sections
$sections -> display ();
}
/**
* Output a report via a callback
*
* @ since 3.0
*
* @ param string $report_id
*/
function edd_output_report_callback ( $report_id = '' ) {
// Maybe use the already loaded report
$report = EDD () -> report
? EDD () -> report
: EDD\Reports\get_report ( $report_id );
/**
* Fires at the top of the content area of a Reports tab .
*
* @ since 1.0
* @ since 3.0 Added the `$report` parameter .
*
* @ param \EDD\Reports\Data\Report | \WP_Error $report The current report object ,
* or WP_Error if invalid .
*/
do_action ( 'edd_reports_page_top' , $report );
if ( ! is_wp_error ( $report ) ) {
printf ( '<h2 class="edd-reports__heading">%s</h2>' , esc_html ( $report -> label ) );
$report -> display ();
} else {
Reports\default_display_report ( $report );
}
/**
* Fires at the bottom of the content area of a Reports tab .
*
* @ since 1.0
* @ since 3.0 Added the `$report` parameter .
*
* @ param \EDD\Reports\Data\Report | \WP_Error $report The current report object ,
* or WP_Error if invalid .
*/
do_action ( 'edd_reports_page_bottom' , $report );
}
/**
* Reports Page
*
* Renders the reports page contents .
*
* @ since 1.0
* @ return void
*/
function edd_reports_page () {
// Enqueue scripts.
wp_enqueue_script ( 'edd-admin-reports' );
?>
< div class = " wrap " >
< h1 >< ? php esc_html_e ( 'Reports' , 'easy-digital-downloads' ); ?> </h1>
< ? php Reports\display_filters ( EDD () -> report ); ?>
< div id = " edd-item-wrapper " class = " full-width edd-clearfix " >
< ? php edd_reports_sections (); ?>
</ div >
</ div ><!-- . wrap -->
< ? php
}
/**
* Register overview report and endpoints .
*
* @ since 3.0
*
* @ param \EDD\Reports\Data\Report_Registry $reports Report registry .
*/
function edd_register_overview_report ( $reports ) {
try {
// Variables to hold date filter values.
$options = Reports\get_dates_filter_options ();
$dates = Reports\get_filter_value ( 'dates' );
$exclude_taxes = Reports\get_taxes_excluded_filter ();
$currency = Reports\get_filter_value ( 'currencies' );
$hbh = Reports\get_dates_filter_hour_by_hour ();
$label = $options [ $dates [ 'range' ] ] . ( $hbh ? ' (' . edd_get_timezone_abbr () . ')' : '' );
$reports -> add_report ( 'overview' , array (
'label' => __ ( 'Overview' , 'easy-digital-downloads' ),
'icon' => 'dashboard' ,
'priority' => 5 ,
'endpoints' => array (
'tiles' => array (
'overview_sales' ,
'overview_earnings' ,
'overview_average_order_value' ,
'overview_new_customers' ,
'overview_refunded_amount' ,
),
'charts' => array (
'overview_sales_earnings_chart' ,
),
),
'filters' => array (
'dates' ,
'taxes' ,
'currencies' ,
)
) );
$reports -> register_endpoint ( 'overview_sales' , array (
'label' => __ ( 'Sales' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $currency ) {
$stats = new EDD\Stats (
array (
'range' => $dates [ 'range' ],
'relative' => true ,
'currency' => $currency ,
'revenue_type' => 'net' ,
)
);
return $stats -> get_order_count ();
},
'display_args' => array (
'comparison_label' => $label . ' — ' . __ ( 'Net' , 'easy-digital-downloads' ),
),
),
),
) );
$reports -> register_endpoint ( 'overview_earnings' , array (
'label' => __ ( 'Earnings' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $exclude_taxes , $currency ) {
$stats = new EDD\Stats (
array (
'range' => $dates [ 'range' ],
'function' => 'SUM' ,
'exclude_taxes' => $exclude_taxes ,
'currency' => $currency ,
'relative' => true ,
'output' => 'formatted' ,
'revenue_type' => 'net' ,
)
);
return $stats -> get_order_earnings ();
},
'display_args' => array (
'comparison_label' => $label . ' — ' . __ ( 'Net' , 'easy-digital-downloads' ),
),
),
),
) );
$reports -> register_endpoint ( 'overview_average_order_value' , array (
'label' => __ ( 'Average Order Value' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $exclude_taxes , $currency ) {
$stats = new EDD\Stats (
array (
'function' => 'AVG' ,
'output' => 'formatted' ,
'relative' => true ,
'range' => $dates [ 'range' ],
'exclude_taxes' => $exclude_taxes ,
'currency' => $currency ,
)
);
return $stats -> get_order_earnings ();
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'overview_new_customers' , array (
'label' => __ ( 'New Customers' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates ) {
$stats = new EDD\Stats ();
return $stats -> get_customer_count ( array (
2023-03-17 22:34:04 +00:00
'range' => $dates [ 'range' ],
'relative' => true ,
'purchase_count' => true ,
2022-11-27 15:03:07 +00:00
) );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'overview_refunded_amount' , array (
'label' => __ ( 'Total Refund Amount' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $exclude_taxes , $currency ) {
$stats = new EDD\Stats ();
return $stats -> get_order_refund_amount ( array (
'range' => $dates [ 'range' ],
'function' => 'SUM' ,
'exclude_taxes' => $exclude_taxes ,
'currency' => $currency ,
'relative' => true ,
'output' => 'formatted' ,
) );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'overview_sales_earnings_chart' , array (
'label' => __ ( 'Sales and Earnings' , 'easy-digital-downloads' ) . ' — ' . $label . ' — ' . __ ( 'Net' , 'easy-digital-downloads' ),
'views' => array (
'chart' => array (
'data_callback' => 'edd_overview_sales_earnings_chart' ,
'type' => 'line' ,
'options' => array (
'datasets' => array (
'earnings' => array (
'label' => __ ( 'Earnings' , 'easy-digital-downloads' ),
'borderColor' => 'rgba(24,126,244,0.75)' ,
'backgroundColor' => 'rgba(24,126,244,0.1)' ,
'fill' => true ,
'borderWidth' => 2 ,
'type' => 'currency' ,
'pointRadius' => 4 ,
'pointHoverRadius' => 6 ,
'pointBackgroundColor' => 'rgb(255,255,255)' ,
'yAxisID' => 'earnings-y' ,
),
'sales' => array (
'label' => __ ( 'Sales' , 'easy-digital-downloads' ),
'borderColor' => 'rgba(252,108,18,0.75)' ,
'backgroundColor' => 'rgba(252,108,18,0.05)' ,
'fill' => true ,
'borderWidth' => 2 ,
'borderCapStyle' => 'round' ,
'borderJoinStyle' => 'round' ,
'pointRadius' => 4 ,
'pointHoverRadius' => 6 ,
'pointBackgroundColor' => 'rgb(255,255,255)' ,
'yAxisID' => 'sales-y' ,
),
),
'scales' => array (
'yAxes' => array (
array (
'id' => 'earnings-y' ,
'type' => 'linear' ,
'display' => true ,
'position' => 'left' ,
'ticks' => array (
'formattingType' => 'format' ,
'beginAtZero' => true ,
'precision' => 0 ,
),
'gridLines' => array (
'display' => true ,
),
),
array (
'id' => 'sales-y' ,
'type' => 'linear' ,
'position' => 'right' ,
'display' => true ,
'ticks' => array (
'formattingType' => 'integer' ,
'beginAtZero' => true ,
'hideNegativeTicks' => true ,
'precision' => 0 ,
),
'gridLines' => array (
'display' => true ,
'color' => 'rgba(0,0,0,0.03)' ,
),
),
),
),
),
),
),
) );
} catch ( \EDD_Exception $exception ) {
edd_debug_log_exception ( $exception );
}
}
add_action ( 'edd_reports_init' , 'edd_register_overview_report' );
/**
* Register downloads report and endpoints .
*
* @ since 3.0
*
* @ param \EDD\Reports\Data\Report_Registry $reports Report registry .
*/
function edd_register_downloads_report ( $reports ) {
try {
$options = Reports\get_dates_filter_options ();
$dates = Reports\get_filter_value ( 'dates' );
$exclude_taxes = Reports\get_taxes_excluded_filter ();
$currency = '' ;
$hbh = Reports\get_dates_filter_hour_by_hour ();
$label = $options [ $dates [ 'range' ] ] . ( $hbh ? ' (' . edd_get_timezone_abbr () . ')' : '' );
$download_data = Reports\get_filter_value ( 'products' );
$download_data = ! empty ( $download_data ) && 'all' !== Reports\get_filter_value ( 'products' )
? edd_parse_product_dropdown_value ( Reports\get_filter_value ( 'products' ) )
: false ;
$endpoint_label = __ ( 'Sales / Earnings' , 'easy-digital-downloads' );
// Mock downloads and prices in case they cannot be found later.
$download = edd_get_download ();
$prices = array ();
$download_label = '' ;
if ( $download_data ) {
$download = edd_get_download ( $download_data [ 'download_id' ] );
$prices = $download -> get_prices ();
if ( isset ( $download_data [ 'price_id' ] ) && is_numeric ( $download_data [ 'price_id' ] ) ) {
$args = array ( 'price_id' => $download_data [ 'price_id' ] );
$price_name = edd_get_price_name ( $download -> ID , $args );
if ( $price_name ) {
$download -> post_title .= ': ' . $price_name ;
}
}
$download_label = esc_html ( ' (' . $download -> post_title . ')' );
}
$tiles = array_filter ( array (
'most_valuable_download' ,
'average_download_sales_earnings' ,
'download_sales_earnings' ,
), function ( $endpoint ) use ( $download_data ) {
switch ( $endpoint ) {
case 'download_sales_earnings' :
return false !== $download_data ;
break ;
default :
return false === $download_data ;
}
} );
$charts = array_filter ( array (
'download_sales_by_variations' ,
'download_earnings_by_variations' ,
'download_sales_earnings_chart'
), function ( $endpoint ) use ( $download_data , $download ) {
switch ( $endpoint ) {
case 'download_sales_by_variations' :
case 'download_earnings_by_variations' :
return (
false !== $download_data &&
false === $download_data [ 'price_id' ] &&
true === $download -> has_variable_prices ()
);
break ;
default :
return false !== $download_data ;
}
} );
$tables = array_filter ( array (
'top_selling_downloads' ,
'earnings_by_taxonomy' ,
), function ( $endpoint ) use ( $download_data ) {
return false === $download_data ;
} );
$reports -> add_report ( 'downloads' , array (
'label' => edd_get_label_plural (),
'priority' => 10 ,
'icon' => 'download' ,
'endpoints' => array (
'tiles' => $tiles ,
'charts' => $charts ,
'tables' => $tables ,
),
'filters' => array ( 'dates' , 'products' , 'taxes' ),
) );
$reports -> register_endpoint ( 'most_valuable_download' , array (
'label' => sprintf ( __ ( 'Most Valuable %s' , 'easy-digital-downloads' ), edd_get_label_singular () ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $currency ) {
$stats = new EDD\Stats ();
$d = $stats -> get_most_valuable_order_items ( array (
'range' => $dates [ 'range' ],
'currency' => $currency ,
'function' => 'SUM'
) );
if ( ! empty ( $d ) && isset ( $d [ 0 ] ) ) {
$d = $d [ 0 ];
if ( $d -> object instanceof EDD_Download ) {
$title = $d -> object -> post_title ;
if ( $d -> object -> has_variable_prices () ) {
$prices = array_values ( wp_filter_object_list ( $d -> object -> get_prices (), array ( 'index' => absint ( $d -> price_id ) ) ) );
$title .= ( is_array ( $prices ) && isset ( $prices [ 0 ] ) )
? ': ' . $prices [ 0 ][ 'name' ]
: '' ;
}
return esc_html ( $title );
}
}
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'average_download_sales_earnings' , array (
'label' => __ ( 'Average Sales / Earnings' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $exclude_taxes , $currency ) {
$stats = new EDD\Stats ( array (
'function' => 'AVG' ,
'range' => $dates [ 'range' ],
'exclude_taxes' => $exclude_taxes ,
'currency' => $currency ,
'output' => 'formatted' ,
) );
return $stats -> get_order_item_count () . ' / ' . $stats -> get_order_item_earnings ();
},
'display_args' => array (
'comparison_label' => $label . ' — ' . __ ( 'Net ' , 'easy-digital-downloads' ),
),
),
),
) );
$reports -> register_endpoint ( 'download_sales_earnings' , array (
'label' => $endpoint_label ,
'views' => array (
'tile' => array (
'data_callback' => function () use ( $download_data , $dates , $currency ) {
$price_id = isset ( $download_data [ 'price_id' ] ) && is_numeric ( $download_data [ 'price_id' ] ) ? absint ( $download_data [ 'price_id' ] ) : null ;
$stats = new EDD\Stats ( array (
'product_id' => absint ( $download_data [ 'download_id' ] ),
'price_id' => $price_id ,
'currency' => $currency ,
'range' => $dates [ 'range' ],
'output' => 'formatted' ,
) );
$earnings = $stats -> get_order_item_earnings ( array (
'function' => 'SUM'
) );
$sales = $stats -> get_order_item_count ( array (
'function' => 'COUNT'
) );
return esc_html ( $sales . ' / ' . $earnings );
},
'display_args' => array (
'comparison_label' => $label . $download_label ,
),
),
),
) );
$reports -> register_endpoint ( 'earnings_by_taxonomy' , array (
'label' => __ ( 'Earnings By Taxonomy' , 'easy-digital-downloads' ) . ' — ' . $label ,
'views' => array (
'table' => array (
'display_args' => array (
'class_name' => '\\EDD\\Reports\\Data\\Downloads\\Earnings_By_Taxonomy_List_Table' ,
'class_file' => EDD_PLUGIN_DIR . 'includes/reports/data/downloads/class-earnings-by-taxonomy-list-table.php' ,
),
),
),
) );
$reports -> register_endpoint ( 'top_selling_downloads' , array (
'label' => sprintf ( __ ( 'Top Selling %s' , 'easy-digital-downloads' ), edd_get_label_plural () ) . ' — ' . $label ,
'views' => array (
'table' => array (
'display_args' => array (
'class_name' => '\\EDD\\Reports\\Data\\Downloads\\Top_Selling_Downloads_List_Table' ,
'class_file' => EDD_PLUGIN_DIR . 'includes/reports/data/downloads/class-top-selling-downloads-list-table.php' ,
),
),
),
) );
$reports -> register_endpoint ( 'download_sales_by_variations' , array (
'label' => __ ( 'Sales by Variation' , 'easy-digital-downloads' ) . $download_label ,
'views' => array (
'chart' => array (
'data_callback' => function () use ( $download_data , $download , $dates , $prices , $currency ) {
$stats = new EDD\Stats ();
$sales = $stats -> get_order_item_count ( array (
'product_id' => absint ( $download_data [ 'download_id' ] ),
'range' => $dates [ 'range' ],
'grouped' => true ,
'currency' => $currency
) );
// Set all values to 0.
foreach ( $prices as $key => $price ) {
$prices [ $key ][ 'sales' ] = 0 ;
}
// Parse results from the database.
foreach ( $sales as $data ) {
$prices [ $data -> price_id ][ 'sales' ] = absint ( $data -> total );
}
$sales = array_values ( wp_list_pluck ( $prices , 'sales' ) );
return array (
'sales' => $sales ,
);
},
'type' => 'pie' ,
'options' => array (
'cutoutPercentage' => 0 ,
'datasets' => array (
'sales' => array (
'label' => __ ( 'Sales' , 'easy-digital-downloads' ),
'backgroundColor' => array (
'rgb(133,175,91)' ,
'rgb(9,149,199)' ,
'rgb(8,189,231)' ,
'rgb(137,163,87)' ,
'rgb(27,98,122)' ,
),
),
),
'labels' => array_values ( wp_list_pluck ( $prices , 'name' ) )
),
),
)
) );
$reports -> register_endpoint ( 'download_earnings_by_variations' , array (
'label' => __ ( 'Earnings by Variation' , 'easy-digital-downloads' ) . $download_label ,
'views' => array (
'chart' => array (
'data_callback' => function () use ( $download_data , $prices , $dates , $currency ) {
$stats = new EDD\Stats ();
$earnings = $stats -> get_order_item_earnings ( array (
'product_id' => absint ( $download_data [ 'download_id' ] ),
'range' => $dates [ 'range' ],
'grouped' => true ,
'currency' => $currency
) );
// Set all values to 0.
foreach ( $prices as $key => $price ) {
$prices [ $key ][ 'earnings' ] = floatval ( 0 );
}
// Parse results from the database.
foreach ( $earnings as $data ) {
$prices [ $data -> price_id ][ 'earnings' ] = floatval ( $data -> total );
}
$earnings = array_values ( wp_list_pluck ( $prices , 'earnings' ) );
return array (
'earnings' => $earnings ,
);
},
'type' => 'pie' ,
'options' => array (
'cutoutPercentage' => 0 ,
'datasets' => array (
'earnings' => array (
'label' => __ ( 'Earnings' , 'easy-digital-downloads' ),
'type' => 'currency' ,
'backgroundColor' => array (
'rgb(133,175,91)' ,
'rgb(9,149,199)' ,
'rgb(8,189,231)' ,
'rgb(137,163,87)' ,
'rgb(27,98,122)' ,
),
),
),
'labels' => array_values ( wp_list_pluck ( $prices , 'name' ) )
),
),
)
) );
$reports -> register_endpoint ( 'download_sales_earnings_chart' , array (
'label' => __ ( 'Sales and Earnings' , 'easy-digital-downloads' ) . esc_html ( $download_label ),
'views' => array (
'chart' => array (
'data_callback' => function () use ( $download_data , $currency ) {
global $wpdb ;
2023-06-05 11:21:17 +00:00
$dates = Reports\get_dates_filter ( 'objects' );
$chart_dates = Reports\parse_dates_for_range ( null , 'now' , false );
$period = Reports\get_graph_period ();
$sql_clauses = Reports\get_sql_clauses ( $period , 'edd_oi.date_created' );
2022-11-27 15:03:07 +00:00
2023-01-18 16:39:57 +00:00
$union_clauses = array (
'select' => 'date' ,
2023-06-05 11:21:17 +00:00
'groupby' => 'date' ,
'orderby' => 'date' ,
2023-01-18 16:39:57 +00:00
);
2022-11-27 15:03:07 +00:00
$price_id = isset ( $download_data [ 'price_id' ] ) && is_numeric ( $download_data [ 'price_id' ] )
? sprintf ( 'AND price_id = %d' , absint ( $download_data [ 'price_id' ] ) )
: '' ;
2023-01-18 16:39:57 +00:00
$earnings_statuses = edd_get_gross_order_statuses ();
$earnings_status_string = implode ( ', ' , array_fill ( 0 , count ( $earnings_statuses ), '%s' ) );
$order_item_earnings = $wpdb -> prepare (
2023-06-05 11:21:17 +00:00
" SELECT SUM(edd_oi.total / edd_oi.rate) AS earnings, { $sql_clauses [ 'select' ] }
2023-01-18 16:39:57 +00:00
FROM { $wpdb -> edd_order_items } edd_oi
INNER JOIN { $wpdb -> edd_orders } edd_o ON edd_oi . order_id = edd_o . id
2023-06-05 11:21:17 +00:00
WHERE edd_oi . product_id = % d { $price_id } AND edd_oi . date_created >= % s AND edd_oi . date_created <= % s AND edd_o . status IN ({ $earnings_status_string })
2023-01-18 16:39:57 +00:00
GROUP BY { $sql_clauses [ 'groupby' ]} " ,
$download_data [ 'download_id' ],
$dates [ 'start' ] -> copy () -> format ( 'mysql' ),
$dates [ 'end' ] -> copy () -> format ( 'mysql' ),
... $earnings_statuses
);
/**
* The adjustments query needs a different order status check than the order items . This is due to the fact that
* adjustments refunded would end up being double counted , and therefore create an inaccurate revenue report .
*/
$adjustments_statuses = edd_get_net_order_statuses ();
$adjustments_status_string = implode ( ', ' , array_fill ( 0 , count ( $adjustments_statuses ), '%s' ) );
$order_adjustments = $wpdb -> prepare (
2023-06-05 11:21:17 +00:00
" SELECT SUM(edd_oa.total / edd_oa.rate) AS earnings, { $sql_clauses [ 'select' ] }
2023-01-18 16:39:57 +00:00
FROM { $wpdb -> edd_order_adjustments } edd_oa
INNER JOIN { $wpdb -> edd_order_items } edd_oi ON
edd_oi . id = edd_oa . object_id
AND edd_oi . product_id = % d
2023-06-05 11:21:17 +00:00
{ $price_id }
2023-01-18 16:39:57 +00:00
AND edd_oi . date_created >= % s AND edd_oi . date_created <= % s
INNER JOIN { $wpdb -> edd_orders } edd_o ON edd_oi . order_id = edd_o . id AND edd_o . type = 'sale' AND edd_o . status IN ({ $adjustments_status_string })
WHERE edd_oa . object_type = 'order_item'
AND edd_oa . type != 'discount'
GROUP BY { $sql_clauses [ 'groupby' ]} " ,
$download_data [ 'download_id' ],
$dates [ 'start' ] -> copy () -> format ( 'mysql' ),
$dates [ 'end' ] -> copy () -> format ( 'mysql' ),
... $adjustments_statuses
2022-11-27 15:03:07 +00:00
);
2023-01-18 16:39:57 +00:00
$earnings_sql = " SELECT SUM(earnings) as earnings, { $union_clauses [ 'select' ] } FROM ( { $order_item_earnings } UNION { $order_adjustments } )a GROUP BY { $union_clauses [ 'groupby' ] } ORDER BY { $union_clauses [ 'orderby' ] } " ;
$earnings_results = $wpdb -> get_results ( $earnings_sql );
2022-11-27 15:03:07 +00:00
$statuses = edd_get_net_order_statuses ();
$status_string = implode ( ', ' , array_fill ( 0 , count ( $statuses ), '%s' ) );
$join = $wpdb -> prepare (
" INNER JOIN { $wpdb -> edd_orders } edd_o ON (edd_oi.order_id = edd_o.id) AND edd_o.status IN( { $status_string } ) AND edd_o.type = 'sale' " ,
... $statuses
);
2023-01-18 16:39:57 +00:00
$sales_sql = $wpdb -> prepare (
" SELECT COUNT(edd_oi.total) AS sales, { $sql_clauses [ 'select' ] }
FROM { $wpdb -> edd_order_items } edd_oi
{ $join }
WHERE edd_oi . product_id = % d % 1 s AND edd_oi . date_created >= % s AND edd_oi . date_created <= % s AND edd_oi . status IN ({ $status_string })
GROUP BY { $sql_clauses [ 'groupby' ]}
ORDER BY { $sql_clauses [ 'orderby' ]} ASC " ,
$download_data [ 'download_id' ],
$price_id ,
$dates [ 'start' ] -> copy () -> format ( 'mysql' ),
$dates [ 'end' ] -> copy () -> format ( 'mysql' ),
... $statuses
2022-11-27 15:03:07 +00:00
);
2023-01-18 16:39:57 +00:00
$sales_results = $wpdb -> get_results ( $sales_sql );
2022-11-27 15:03:07 +00:00
$sales = array ();
$earnings = array ();
// Initialise all arrays with timestamps and set values to 0.
while ( strtotime ( $chart_dates [ 'start' ] -> copy () -> format ( 'mysql' ) ) <= strtotime ( $chart_dates [ 'end' ] -> copy () -> format ( 'mysql' ) ) ) {
$timestamp = $chart_dates [ 'start' ] -> copy () -> format ( 'U' );
$date_on_chart = $chart_dates [ 'start' ];
$sales [ $timestamp ][ 0 ] = $date_on_chart -> format ( 'Y-m-d H:i:s' );
$sales [ $timestamp ][ 1 ] = 0 ;
$earnings [ $timestamp ][ 0 ] = $date_on_chart -> format ( 'Y-m-d H:i:s' );
$earnings [ $timestamp ][ 1 ] = 0.00 ;
// Loop through each date there were sales/earnings, which we queried from the database.
foreach ( $earnings_results as $earnings_result ) {
2023-06-05 11:21:17 +00:00
$date_of_db_value = EDD () -> utils -> date ( $earnings_result -> date );
2022-11-27 15:03:07 +00:00
// Add any sales/earnings that happened during this hour.
2023-06-05 11:21:17 +00:00
if ( 'hour' === $period ) {
2022-11-27 15:03:07 +00:00
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m-d H' ) === $date_on_chart -> format ( 'Y-m-d H' ) ) {
$earnings [ $timestamp ][ 1 ] += $earnings_result -> earnings ;
}
// Add any sales/earnings that happened during this day.
2023-06-05 11:21:17 +00:00
} elseif ( 'day' === $period ) {
2022-11-27 15:03:07 +00:00
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m-d' ) === $date_on_chart -> format ( 'Y-m-d' ) ) {
$earnings [ $timestamp ][ 1 ] += $earnings_result -> earnings ;
}
// Add any sales/earnings that happened during this month.
} else {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m' ) === $date_on_chart -> format ( 'Y-m' ) ) {
$earnings [ $timestamp ][ 1 ] += $earnings_result -> earnings ;
}
}
}
// Loop through each date there were sales/earnings, which we queried from the database.
foreach ( $sales_results as $sales_result ) {
2023-06-05 11:21:17 +00:00
$date_of_db_value = EDD () -> utils -> date ( $sales_result -> date );
2022-11-27 15:03:07 +00:00
// Add any sales/earnings that happened during this hour.
2023-06-05 11:21:17 +00:00
if ( 'hour' === $period ) {
2022-11-27 15:03:07 +00:00
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m-d H' ) === $date_on_chart -> format ( 'Y-m-d H' ) ) {
$sales [ $timestamp ][ 1 ] += $sales_result -> sales ;
}
// Add any sales/earnings that happened during this day.
2023-06-05 11:21:17 +00:00
} elseif ( 'day' === $period ) {
2022-11-27 15:03:07 +00:00
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m-d' ) === $date_on_chart -> format ( 'Y-m-d' ) ) {
$sales [ $timestamp ][ 1 ] += $sales_result -> sales ;
}
// Add any sales/earnings that happened during this month.
} else {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m' ) === $date_on_chart -> format ( 'Y-m' ) ) {
$sales [ $timestamp ][ 1 ] += $sales_result -> sales ;
}
}
}
// Move the chart along to the next hour/day/month to get ready for the next loop.
2023-06-05 11:21:17 +00:00
if ( 'hour' === $period ) {
2022-11-27 15:03:07 +00:00
$chart_dates [ 'start' ] -> addHour ( 1 );
2023-06-05 11:21:17 +00:00
} elseif ( 'day' === $period ) {
2022-11-27 15:03:07 +00:00
$chart_dates [ 'start' ] -> addDays ( 1 );
} else {
$chart_dates [ 'start' ] -> addMonth ( 1 );
}
}
return array (
'earnings' => array_values ( $earnings ),
'sales' => array_values ( $sales ),
);
},
'type' => 'line' ,
'options' => array (
'datasets' => array (
'earnings' => array (
'label' => __ ( 'Earnings' , 'easy-digital-downloads' ),
'borderColor' => 'rgba(24,126,244,0.75)' ,
'backgroundColor' => 'rgba(24,126,244,0.1)' ,
'fill' => true ,
'borderWidth' => 2 ,
'type' => 'currency' ,
'pointRadius' => 4 ,
'pointHoverRadius' => 6 ,
'pointBackgroundColor' => 'rgb(255,255,255)' ,
'yAxisID' => 'earnings-y' ,
),
'sales' => array (
'label' => __ ( 'Sales' , 'easy-digital-downloads' ),
'borderColor' => 'rgba(252,108,18,0.75)' ,
'backgroundColor' => 'rgba(252,108,18,0.05)' ,
'fill' => true ,
'borderWidth' => 2 ,
'borderCapStyle' => 'round' ,
'borderJoinStyle' => 'round' ,
'pointRadius' => 4 ,
'pointHoverRadius' => 6 ,
'pointBackgroundColor' => 'rgb(255,255,255)' ,
'yAxisID' => 'sales-y' ,
),
),
'scales' => array (
'yAxes' => array (
array (
'id' => 'earnings-y' ,
'type' => 'linear' ,
'display' => true ,
'position' => 'left' ,
'ticks' => array (
'maxTicksLimit' => 5 ,
'formattingType' => 'format' ,
'suggestedMin' => 0 ,
'beginAtZero' => true ,
),
'gridLines' => array (
'display' => true ,
),
),
array (
'id' => 'sales-y' ,
'type' => 'linear' ,
'position' => 'right' ,
'display' => true ,
'ticks' => array (
'maxTicksLimit' => 5 ,
'formattingType' => 'integer' ,
'suggestedMin' => 0 ,
'beginAtZero' => true ,
'hideNegativeTicks' => true ,
),
'gridLines' => array (
'display' => true ,
'color' => 'rgba(0,0,0,0.03)' ,
),
),
),
),
),
),
),
) );
} catch ( \EDD_Exception $exception ) {
edd_debug_log_exception ( $exception );
}
}
add_action ( 'edd_reports_init' , 'edd_register_downloads_report' );
/**
* Register refunds report and endpoints .
*
* @ since 3.0
*
* @ param \EDD\Reports\Data\Report_Registry $reports Report registry .
*/
function edd_register_refunds_report ( $reports ) {
try {
// Variables to hold date filter values.
$options = Reports\get_dates_filter_options ();
$dates = Reports\get_filter_value ( 'dates' );
$exclude_taxes = Reports\get_taxes_excluded_filter ();
$currency = Reports\get_filter_value ( 'currencies' );
$hbh = Reports\get_dates_filter_hour_by_hour ();
$label = $options [ $dates [ 'range' ] ] . ( $hbh ? ' (' . edd_get_timezone_abbr () . ')' : '' );
$reports -> add_report ( 'refunds' , array (
'label' => __ ( 'Refunds' , 'easy-digital-downloads' ),
'icon' => 'image-rotate' ,
'priority' => 15 ,
'endpoints' => array (
'tiles' => array (
'refund_count' ,
'fully_refunded_order_count' ,
'fully_refunded_order_item_count' ,
'refund_amount' ,
'average_refund_amount' ,
'average_time_to_refund' ,
'refund_rate' ,
),
'charts' => array (
'refunds_chart' ,
),
),
'filters' => array (
'dates' ,
'taxes' ,
'currencies'
)
) );
$reports -> register_endpoint ( 'refund_count' , array (
'label' => __ ( 'Number of Refunds' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $currency ) {
$stats = new EDD\Stats ();
$number = $stats -> get_order_refund_count ( array (
'range' => $dates [ 'range' ],
'currency' => $currency
) );
return esc_html ( $number );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'fully_refunded_order_count' , array (
'label' => __ ( 'Number of Fully Refunded Orders' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $currency ) {
$stats = new EDD\Stats ();
$number = $stats -> get_order_refund_count ( array (
'range' => $dates [ 'range' ],
'status' => array ( 'complete' ),
'currency' => $currency
) );
return esc_html ( $number );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'fully_refunded_order_item_count' , array (
'label' => __ ( 'Number of Fully Refunded Items' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $currency ) {
$stats = new EDD\Stats ();
$number = $stats -> get_order_item_refund_count ( array (
'range' => $dates [ 'range' ],
'status' => array ( 'refunded' ),
'currency' => $currency
) );
return esc_html ( $number );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'refund_amount' , array (
'label' => __ ( 'Total Refund Amount' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $exclude_taxes , $currency ) {
$stats = new EDD\Stats ();
return $stats -> get_order_refund_amount ( array (
'range' => $dates [ 'range' ],
'exclude_taxes' => $exclude_taxes ,
'output' => 'formatted' ,
'currency' => $currency
) );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'average_refund_amount' , array (
'label' => __ ( 'Average Refund Amount' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $exclude_taxes , $currency ) {
$stats = new EDD\Stats ();
return $stats -> get_order_refund_amount ( array (
'function' => 'AVG' ,
'range' => $dates [ 'range' ],
'exclude_taxes' => $exclude_taxes ,
'output' => 'formatted' ,
'currency' => $currency
) );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'average_time_to_refund' , array (
'label' => __ ( 'Average Time to Refund' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $currency ) {
$stats = new EDD\Stats ();
return $stats -> get_average_refund_time ( array (
'range' => $dates [ 'range' ],
'currency' => $currency
) );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'refund_rate' , array (
'label' => __ ( 'Refund Rate' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $currency ) {
$stats = new EDD\Stats ();
return $stats -> get_refund_rate ( array (
'range' => $dates [ 'range' ],
'output' => 'formatted' ,
'status' => edd_get_gross_order_statuses (),
'currency' => $currency
) );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'refunds_chart' , array (
'label' => __ ( 'Refunds' , 'easy-digital-downloads' ) . ' — ' . $label ,
'views' => array (
'chart' => array (
'data_callback' => 'edd_overview_refunds_chart' ,
'type' => 'line' ,
'options' => array (
'datasets' => array (
'amount' => array (
'label' => __ ( 'Amount' , 'easy-digital-downloads' ),
'borderColor' => 'rgba(24,126,244,0.75)' ,
'backgroundColor' => 'rgba(24,126,244,0.1)' ,
'fill' => true ,
'borderWidth' => 2 ,
'type' => 'currency' ,
'pointRadius' => 4 ,
'pointHoverRadius' => 6 ,
'pointBackgroundColor' => 'rgb(255,255,255)' ,
'yAxisID' => 'amount-y' ,
),
'number' => array (
'label' => __ ( 'Number' , 'easy-digital-downloads' ),
'borderColor' => 'rgba(252,108,18,0.75)' ,
'backgroundColor' => 'rgba(252,108,18,0.05)' ,
'fill' => true ,
'borderWidth' => 2 ,
'borderCapStyle' => 'round' ,
'borderJoinStyle' => 'round' ,
'pointRadius' => 4 ,
'pointHoverRadius' => 6 ,
'pointBackgroundColor' => 'rgb(255,255,255)' ,
'yAxisID' => 'number-y' ,
),
),
'scales' => array (
'yAxes' => array (
array (
'id' => 'amount-y' ,
'type' => 'linear' ,
'display' => true ,
'position' => 'left' ,
'ticks' => array (
'maxTicksLimit' => 5 ,
'formattingType' => 'format' ,
'suggestedMin' => 0 ,
'beginAtZero' => true ,
'precision' => 0 ,
),
'gridLines' => array (
'display' => true ,
),
),
array (
'id' => 'number-y' ,
'type' => 'linear' ,
'position' => 'right' ,
'display' => true ,
'ticks' => array (
'maxTicksLimit' => 5 ,
'formattingType' => 'integer' ,
'suggestedMin' => 0 ,
'beginAtZero' => true ,
'precision' => 0 ,
),
'gridLines' => array (
'display' => true ,
'color' => 'rgba(0,0,0,0.03)' ,
),
),
),
),
),
),
),
) );
} catch ( \EDD_Exception $exception ) {
edd_debug_log_exception ( $exception );
}
}
add_action ( 'edd_reports_init' , 'edd_register_refunds_report' );
/**
* Register payment gateways report and endpoints .
*
* @ since 3.0
*
* @ param \EDD\Reports\Data\Report_Registry $reports Report registry .
*/
function edd_register_payment_gateways_report ( $reports ) {
try {
// Variables to hold date filter values.
$options = Reports\get_dates_filter_options ();
$dates = Reports\get_filter_value ( 'dates' );
$exclude_taxes = Reports\get_taxes_excluded_filter ();
$currency = Reports\get_filter_value ( 'currencies' );
$gateway = Reports\get_filter_value ( 'gateways' );
$hbh = Reports\get_dates_filter_hour_by_hour ();
$label = $options [ $dates [ 'range' ] ] . ( $hbh ? ' (' . edd_get_timezone_abbr () . ')' : '' );
$tiles = array (
'sales_per_gateway' ,
'earnings_per_gateway' ,
'refunds_per_gateway' ,
'average_value_per_gateway' ,
);
$tables = array_filter ( array (
'gateway_stats' ,
), function ( $endpoint ) use ( $gateway ) {
return empty ( $gateway ) || 'all' === $gateway ;
} );
$charts = array_filter ( array (
'gateway_sales_breakdown' ,
'gateway_earnings_breakdown' ,
'gateway_sales_earnings_chart' ,
), function ( $endpoint ) use ( $gateway ) {
switch ( $endpoint ) {
case 'gateway_sales_earnings_chart' :
return ! empty ( $gateway ) && 'all' !== $gateway ;
break ;
default :
return ( empty ( $gateway ) || 'all' === $gateway );
}
} );
$reports -> add_report ( 'gateways' , array (
'label' => __ ( 'Payment Gateways' , 'easy-digital-downloads' ),
'icon' => 'image-filter' ,
'priority' => 20 ,
'endpoints' => array (
'tiles' => $tiles ,
'tables' => $tables ,
'charts' => $charts ,
),
'filters' => array ( 'dates' , 'gateways' , 'taxes' , 'currencies' ),
) );
$reports -> register_endpoint ( 'sales_per_gateway' , array (
'label' => __ ( 'Sales' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $currency ) {
$gateway = 'all' !== Reports\get_filter_value ( 'gateways' )
? Reports\get_filter_value ( 'gateways' )
: '' ;
$stats = new EDD\Stats ();
return $stats -> get_gateway_sales ( array (
'range' => $dates [ 'range' ],
'gateway' => $gateway ,
'currency' => $currency ,
) );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'earnings_per_gateway' , array (
'label' => __ ( 'Earnings' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $exclude_taxes , $currency ) {
$gateway = 'all' !== Reports\get_filter_value ( 'gateways' )
? Reports\get_filter_value ( 'gateways' )
: '' ;
$stats = new EDD\Stats ();
return $stats -> get_gateway_earnings ( array (
'range' => $dates [ 'range' ],
'exclude_taxes' => $exclude_taxes ,
'gateway' => $gateway ,
'output' => 'formatted' ,
'currency' => $currency
) );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'refunds_per_gateway' , array (
'label' => __ ( 'Refunds' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $currency ) {
$gateway = 'all' !== Reports\get_filter_value ( 'gateways' )
? Reports\get_filter_value ( 'gateways' )
: '' ;
$stats = new EDD\Stats ();
return $stats -> get_gateway_earnings ( array (
'range' => $dates [ 'range' ],
'gateway' => $gateway ,
'output' => 'formatted' ,
'type' => 'refund' ,
'status' => array ( 'complete' ),
'currency' => $currency
) );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'average_value_per_gateway' , array (
'label' => __ ( 'Average Order Value' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $exclude_taxes , $currency ) {
$gateway = 'all' !== Reports\get_filter_value ( 'gateways' )
? Reports\get_filter_value ( 'gateways' )
: '' ;
$stats = new EDD\Stats ();
if ( empty ( $gateway ) ) {
return $stats -> get_order_earnings ( array (
'range' => $dates [ 'range' ],
'exclude_taxes' => $exclude_taxes ,
'function' => 'AVG' ,
'output' => 'formatted' ,
'currency' => $currency
) );
} else {
return $stats -> get_gateway_earnings ( array (
'range' => $dates [ 'range' ],
'exclude_taxes' => $exclude_taxes ,
'gateway' => $gateway ,
'function' => 'AVG' ,
'output' => 'formatted' ,
'currency' => $currency
) );
}
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'gateway_stats' , array (
'label' => __ ( 'Gateway Stats' , 'easy-digital-downloads' ) . ' — ' . $options [ $dates [ 'range' ] ],
'views' => array (
'table' => array (
'display_args' => array (
'class_name' => '\\EDD\\Reports\\Data\\Payment_Gateways\\Gateway_Stats' ,
'class_file' => EDD_PLUGIN_DIR . 'includes/reports/data/payment-gateways/class-gateway-stats-list-table.php' ,
),
),
),
) );
$gateway_list = array_map ( 'edd_get_gateway_admin_label' , array_keys ( edd_get_payment_gateways () ) );
$reports -> register_endpoint ( 'gateway_sales_breakdown' , array (
'label' => __ ( 'Gateway Sales' , 'easy-digital-downloads' ) . ' — ' . $options [ $dates [ 'range' ] ],
'views' => array (
'chart' => array (
'data_callback' => function () use ( $dates , $currency ) {
$stats = new EDD\Stats ();
$g = $stats -> get_gateway_sales ( array (
'range' => $dates [ 'range' ],
'grouped' => true ,
'currency' => $currency
) );
$gateways = array_flip ( array_keys ( edd_get_payment_gateways () ) );
foreach ( $g as $data ) {
$gateways [ $data -> gateway ] = $data -> total ;
}
$gateways = array_map ( function ( $v ) {
return null === $v
? 0
: $v ;
}, $gateways );
return array (
'sales' => array_values ( $gateways ),
);
},
'type' => 'pie' ,
'options' => array (
'cutoutPercentage' => 0 ,
'datasets' => array (
'sales' => array (
'label' => __ ( 'Sales' , 'easy-digital-downloads' ),
'backgroundColor' => array (
'rgb(133,175,91)' ,
'rgb(9,149,199)' ,
'rgb(8,189,231)' ,
'rgb(137,163,87)' ,
'rgb(27,98,122)' ,
),
),
),
'labels' => $gateway_list ,
),
),
)
) );
$reports -> register_endpoint ( 'gateway_earnings_breakdown' , array (
'label' => __ ( 'Gateway Earnings' , 'easy-digital-downloads' ) . ' — ' . $options [ $dates [ 'range' ] ],
'views' => array (
'chart' => array (
'data_callback' => function () use ( $dates , $exclude_taxes , $currency ) {
$stats = new EDD\Stats ();
$g = $stats -> get_gateway_earnings ( array (
'grouped' => true ,
'range' => $dates [ 'range' ],
'exclude_taxes' => $exclude_taxes ,
'currency' => $currency
) );
$gateways = array_flip ( array_keys ( edd_get_payment_gateways () ) );
foreach ( $g as $data ) {
$gateways [ $data -> gateway ] = $data -> earnings ;
}
$gateways = array_values ( array_map ( function ( $v ) {
return null === $v
? 0.00
: $v ;
}, $gateways ) );
return array (
'earnings' => $gateways ,
);
},
'type' => 'pie' ,
'options' => array (
'cutoutPercentage' => 0 ,
'datasets' => array (
'earnings' => array (
'label' => __ ( 'Earnings' , 'easy-digital-downloads' ),
'backgroundColor' => array (
'rgb(133,175,91)' ,
'rgb(9,149,199)' ,
'rgb(8,189,231)' ,
'rgb(137,163,87)' ,
'rgb(27,98,122)' ,
),
'type' => 'currency' ,
),
),
'labels' => $gateway_list ,
),
),
)
) );
$reports -> register_endpoint ( 'gateway_sales_earnings_chart' , array (
'label' => __ ( 'Sales and Earnings' , 'easy-digital-downloads' ) . ' — ' . $label ,
'views' => array (
'chart' => array (
'data_callback' => function () use ( $dates , $exclude_taxes , $currency ) {
global $wpdb ;
$dates = Reports\get_dates_filter ( 'objects' );
$chart_dates = Reports\parse_dates_for_range ( null , 'now' , false );
2023-06-05 11:21:17 +00:00
$period = Reports\get_graph_period ();
$sql_clauses = Reports\get_sql_clauses ( $period , 'date_created' );
2022-11-27 15:03:07 +00:00
$gateway = Reports\get_filter_value ( 'gateways' );
$column = $exclude_taxes
? '( total - tax ) / rate'
: 'total / rate' ;
$currency_sql = '' ;
if ( ! empty ( $currency ) && array_key_exists ( strtoupper ( $currency ), edd_get_currencies () ) ) {
$currency_sql = $wpdb -> prepare (
" AND currency = %s " ,
strtoupper ( $currency )
);
}
$results = $wpdb -> get_results ( $wpdb -> prepare (
" SELECT COUNT( { $column } ) AS sales, SUM( { $column } ) AS earnings, { $sql_clauses [ 'select' ] }
FROM { $wpdb -> edd_orders } o
WHERE gateway = % s AND status IN ( 'complete' , 'revoked' ) { $currency_sql } AND date_created >= % s AND date_created <= % s
GROUP BY { $sql_clauses [ 'groupby' ]}
ORDER BY { $sql_clauses [ 'orderby' ]} ASC " ,
esc_sql ( $gateway ), $dates [ 'start' ] -> copy () -> format ( 'mysql' ), $dates [ 'end' ] -> copy () -> format ( 'mysql' ) ) );
2023-06-05 11:21:17 +00:00
$sales = array ();
2022-11-27 15:03:07 +00:00
$earnings = array ();
/**
* Initialise all arrays with timestamps and set values to 0.
*
* We use the Chart based dates for this loop , so the graph shows in the proper date ranges while the actual DB queries are all UTC based .
*/
while ( strtotime ( $chart_dates [ 'start' ] -> copy () -> format ( 'mysql' ) ) <= strtotime ( $chart_dates [ 'end' ] -> copy () -> format ( 'mysql' ) ) ) {
$timestamp = $chart_dates [ 'start' ] -> copy () -> format ( 'U' );
$date_on_chart = $chart_dates [ 'start' ];
$sales [ $timestamp ][ 0 ] = $date_on_chart -> format ( 'Y-m-d H:i:s' );
$sales [ $timestamp ][ 1 ] = 0 ;
$earnings [ $timestamp ][ 0 ] = $date_on_chart -> format ( 'Y-m-d H:i:s' );
$earnings [ $timestamp ][ 1 ] = 0.00 ;
// Loop through each date there were sales/earnings, which we queried from the database.
foreach ( $results as $result ) {
2023-06-05 11:21:17 +00:00
$date_of_db_value = EDD () -> utils -> date ( $result -> date );
2022-11-27 15:03:07 +00:00
// Add any sales/earnings that happened during this hour.
2023-06-05 11:21:17 +00:00
if ( 'hour' === $period ) {
2022-11-27 15:03:07 +00:00
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m-d H' ) === $date_on_chart -> format ( 'Y-m-d H' ) ) {
$sales [ $timestamp ][ 1 ] += $result -> sales ;
$earnings [ $timestamp ][ 1 ] += $result -> earnings ;
}
// Add any sales/earnings that happened during this day.
2023-06-05 11:21:17 +00:00
} elseif ( 'day' === $period ) {
2022-11-27 15:03:07 +00:00
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m-d' ) === $date_on_chart -> format ( 'Y-m-d' ) ) {
$sales [ $timestamp ][ 1 ] += $result -> sales ;
$earnings [ $timestamp ][ 1 ] += $result -> earnings ;
}
// Add any sales/earnings that happened during this month.
} else {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m' ) === $date_on_chart -> format ( 'Y-m' ) ) {
$sales [ $timestamp ][ 1 ] += $result -> sales ;
$earnings [ $timestamp ][ 1 ] += $result -> earnings ;
}
}
}
// Move the chart along to the next hour/day/month to get ready for the next loop.
2023-06-05 11:21:17 +00:00
if ( 'hour' === $period ) {
2022-11-27 15:03:07 +00:00
$chart_dates [ 'start' ] -> addHour ( 1 );
2023-06-05 11:21:17 +00:00
} elseif ( 'day' === $period ) {
2022-11-27 15:03:07 +00:00
$chart_dates [ 'start' ] -> addDays ( 1 );
} else {
$chart_dates [ 'start' ] -> addMonth ( 1 );
}
}
$sales = array_values ( $sales );
$earnings = array_values ( $earnings );
return array (
'earnings' => $earnings ,
'sales' => $sales ,
);
},
'type' => 'line' ,
'options' => array (
'datasets' => array (
'earnings' => array (
'label' => __ ( 'Earnings' , 'easy-digital-downloads' ),
'borderColor' => 'rgba(24,126,244,0.75)' ,
'backgroundColor' => 'rgba(24,126,244,0.1)' ,
'fill' => true ,
'borderWidth' => 2 ,
'type' => 'currency' ,
'pointRadius' => 4 ,
'pointHoverRadius' => 6 ,
'pointBackgroundColor' => 'rgb(255,255,255)' ,
'yAxisID' => 'earnings-y' ,
),
'sales' => array (
'label' => __ ( 'Sales' , 'easy-digital-downloads' ),
'borderColor' => 'rgba(252,108,18,0.75)' ,
'backgroundColor' => 'rgba(252,108,18,0.05)' ,
'fill' => true ,
'borderWidth' => 2 ,
'borderCapStyle' => 'round' ,
'borderJoinStyle' => 'round' ,
'pointRadius' => 4 ,
'pointHoverRadius' => 6 ,
'pointBackgroundColor' => 'rgb(255,255,255)' ,
'yAxisID' => 'sales-y' ,
),
),
'scales' => array (
'yAxes' => array (
array (
'id' => 'earnings-y' ,
'type' => 'linear' ,
'display' => true ,
'position' => 'left' ,
'ticks' => array (
'maxTicksLimit' => 5 ,
'formattingType' => 'format' ,
'suggestedMin' => 0 ,
'beginAtZero' => true ,
'precision' => 0 ,
),
'gridLines' => array (
'display' => true ,
),
),
array (
'id' => 'sales-y' ,
'type' => 'linear' ,
'position' => 'right' ,
'display' => true ,
'ticks' => array (
'maxTicksLimit' => 5 ,
'formattingType' => 'integer' ,
'suggestedMin' => 0 ,
'beginAtZero' => true ,
'hideNegativeTicks' => true ,
'precision' => 0 ,
),
'gridLines' => array (
'display' => true ,
'color' => 'rgba(0,0,0,0.03)' ,
),
),
),
),
),
),
),
) );
} catch ( \EDD_Exception $exception ) {
edd_debug_log_exception ( $exception );
}
}
add_action ( 'edd_reports_init' , 'edd_register_payment_gateways_report' );
/**
* Register taxes report and endpoints .
*
* @ since 3.0
*
* @ param \EDD\Reports\Data\Report_Registry $reports Report registry .
*/
function edd_register_taxes_report ( $reports ) {
try {
// Variables to hold date filter values.
$options = Reports\get_dates_filter_options ();
$dates = Reports\get_filter_value ( 'dates' );
$currency = Reports\get_filter_value ( 'currencies' );
$hbh = Reports\get_dates_filter_hour_by_hour ();
$label = $options [ $dates [ 'range' ] ] . ( $hbh ? ' (' . edd_get_timezone_abbr () . ')' : '' );
$download_data = Reports\get_filter_value ( 'products' );
$download_data = ! empty ( $download_data ) && 'all' !== Reports\get_filter_value ( 'products' )
? edd_parse_product_dropdown_value ( Reports\get_filter_value ( 'products' ) )
: false ;
$download_label = '' ;
if ( $download_data ) {
$download = edd_get_download ( $download_data [ 'download_id' ] );
if ( isset ( $download_data [ 'price_id' ] ) && is_numeric ( $download_data [ 'price_id' ] ) ) {
$args = array ( 'price_id' => $download_data [ 'price_id' ] );
$price_name = edd_get_price_name ( $download -> ID , $args );
if ( $price_name ) {
$download -> post_title .= ': ' . $price_name ;
}
}
$download_label = esc_html ( ' (' . $download -> post_title . ')' );
}
$country = Reports\get_filter_value ( 'countries' );
$region = Reports\get_filter_value ( 'regions' );
$tiles = array (
'total_tax_collected' ,
'total_tax_collected_for_location' ,
);
$tables = array_filter ( array (
'tax_collected_by_location' ,
), function ( $table ) use ( $download_data ) {
return false === $download_data ;
} );
$reports -> add_report ( 'taxes' , array (
'label' => __ ( 'Taxes' , 'easy-digital-downloads' ),
'priority' => 25 ,
'icon' => 'editor-paste-text' ,
'endpoints' => array (
'tiles' => $tiles ,
'tables' => $tables ,
),
'filters' => array ( 'dates' , 'products' , 'countries' , 'regions' , 'currencies' ),
) );
$reports -> register_endpoint ( 'total_tax_collected' , array (
'label' => __ ( 'Total Tax Collected' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $currency ) {
$download = Reports\get_filter_value ( 'products' );
$download = ! empty ( $download ) && 'all' !== Reports\get_filter_value ( 'products' )
? edd_parse_product_dropdown_value ( Reports\get_filter_value ( 'products' ) )
: array ( 'download_id' => '' , 'price_id' => '' );
$stats = new EDD\Stats ();
return $stats -> get_tax ( array (
'output' => 'formatted' ,
'range' => $dates [ 'range' ],
'download_id' => $download [ 'download_id' ],
'price_id' => ( string ) $download [ 'price_id' ],
'currency' => $currency
) );
},
'display_args' => array (
'comparison_label' => $label . $download_label ,
),
),
),
) );
if ( ! empty ( $country ) && 'all' !== $country ) {
$location = '' ;
if ( ! empty ( $region ) && 'all' !== $region ) {
$location = edd_get_state_name ( $country , $region ) . ', ' ;
}
$location .= edd_get_country_name ( $country );
$reports -> register_endpoint ( 'total_tax_collected_for_location' , array (
'label' => __ ( 'Total Tax Collected for ' , 'easy-digital-downloads' ) . $location ,
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates , $country , $region , $currency ) {
$download = Reports\get_filter_value ( 'products' );
$download = ! empty ( $download ) && 'all' !== Reports\get_filter_value ( 'products' )
? edd_parse_product_dropdown_value ( Reports\get_filter_value ( 'products' ) )
: array ( 'download_id' => '' , 'price_id' => '' );
$stats = new EDD\Stats ();
return $stats -> get_tax_by_location ( array (
'output' => 'formatted' ,
'range' => $dates [ 'range' ],
'download_id' => $download [ 'download_id' ],
'price_id' => ( string ) $download [ 'price_id' ],
'country' => $country ,
'region' => $region ,
'currency' => $currency
) );
},
'display_args' => array (
'comparison_label' => $label . $download_label ,
),
),
),
) );
}
$reports -> register_endpoint ( 'tax_collected_by_location' , array (
'label' => __ ( 'Tax Collected by Location' , 'easy-digital-downloads' ),
'views' => array (
'table' => array (
'display_args' => array (
'class_name' => '\\EDD\\Reports\\Data\\Taxes\\Tax_Collected_By_Location' ,
'class_file' => EDD_PLUGIN_DIR . 'includes/reports/data/taxes/class-tax-collected-by-location-list-table.php' ,
),
),
),
) );
} catch ( \EDD_Exception $exception ) {
edd_debug_log_exception ( $exception );
}
}
add_action ( 'edd_reports_init' , 'edd_register_taxes_report' );
/**
* Register file downloads report and endpoints .
*
* @ since 3.0
*
* @ param \EDD\Reports\Data\Report_Registry $reports Report registry .
*/
function edd_register_file_downloads_report ( $reports ) {
try {
// Variables to hold date filter values.
$options = Reports\get_dates_filter_options ();
$filter = Reports\get_filter_value ( 'dates' );
$hbh = Reports\get_dates_filter_hour_by_hour ();
$label = $options [ $filter [ 'range' ] ] . ( $hbh ? ' (' . edd_get_timezone_abbr () . ')' : '' );
$download_data = Reports\get_filter_value ( 'products' );
$download_data = ! empty ( $download_data ) && 'all' !== Reports\get_filter_value ( 'products' )
? edd_parse_product_dropdown_value ( Reports\get_filter_value ( 'products' ) )
: false ;
$download_label = '' ;
if ( $download_data ) {
$download = edd_get_download ( $download_data [ 'download_id' ] );
if ( isset ( $download_data [ 'price_id' ] ) && is_numeric ( $download_data [ 'price_id' ] ) ) {
$args = array ( 'price_id' => $download_data [ 'price_id' ] );
$price_name = edd_get_price_name ( $download -> ID , $args );
if ( $price_name ) {
$download -> post_title .= ': ' . $price_name ;
}
}
$download_label = esc_html ( ' (' . $download -> post_title . ')' );
}
$tiles = array_filter ( array (
'number_of_file_downloads' ,
'average_file_downloads_per_customer' ,
'most_downloaded_product' ,
'average_file_downloads_per_order' ,
), function ( $endpoint ) use ( $download_data ) {
switch ( $endpoint ) {
case 'average_file_downloads_per_customer' :
case 'most_downloaded_product' :
case 'average_file_downloads_per_order' :
return false === $download_data ;
break ;
default :
return true ;
}
} );
$tables = array_filter ( array (
'top_five_most_downloaded_products' ,
), function ( $endpoint ) use ( $download_data ) {
return false === $download_data ;
} );
$charts = array (
'file_downloads_chart' ,
);
$reports -> add_report ( 'file_downloads' , array (
'label' => __ ( 'File Downloads' , 'easy-digital-downloads' ),
'icon' => 'download' ,
'priority' => 30 ,
'endpoints' => array (
'tiles' => $tiles ,
'tables' => $tables ,
'charts' => $charts ,
),
'filters' => array ( 'dates' , 'products' ),
) );
$reports -> register_endpoint ( 'number_of_file_downloads' , array (
'label' => __ ( 'Number of File Downloads' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $filter ) {
$download = Reports\get_filter_value ( 'products' );
$download = ! empty ( $download ) && 'all' !== Reports\get_filter_value ( 'products' )
? edd_parse_product_dropdown_value ( Reports\get_filter_value ( 'products' ) )
: array ( 'download_id' => '' , 'price_id' => '' );
$stats = new EDD\Stats ();
return $stats -> get_file_download_count ( array (
'range' => $filter [ 'range' ],
'download_id' => $download [ 'download_id' ],
'price_id' => ( string ) $download [ 'price_id' ],
) );
},
'display_args' => array (
'comparison_label' => $label . $download_label ,
),
),
),
) );
$reports -> register_endpoint ( 'average_file_downloads_per_customer' , array (
'label' => __ ( 'Average per Customer' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $filter ) {
$stats = new EDD\Stats ();
return $stats -> get_average_file_download_count ( array (
'range' => $filter [ 'range' ],
'column' => 'customer_id' ,
) );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'average_file_downloads_per_order' , array (
'label' => __ ( 'Average per Order' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $filter ) {
$stats = new EDD\Stats ();
return $stats -> get_average_file_download_count ( array (
'range' => $filter [ 'range' ],
'column' => 'order_id' ,
) );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'most_downloaded_product' , array (
'label' => __ ( 'Most Downloaded Product' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $filter ) {
$stats = new EDD\Stats ();
$d = $stats -> get_most_downloaded_products ( array ( 'range' => $filter [ 'range' ] ) );
if ( $d ) {
return esc_html ( $d [ 0 ] -> object -> post_title );
}
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'top_five_most_downloaded_products' , array (
'label' => __ ( 'Top Five Most Downloaded Products' , 'easy-digital-downloads' ) . ' – ' . $label ,
'views' => array (
'table' => array (
'display_args' => array (
'class_name' => '\\EDD\\Reports\\Data\\File_Downloads\\Top_Five_Most_Downloaded_List_Table' ,
'class_file' => EDD_PLUGIN_DIR . 'includes/reports/data/file-downloads/class-top-five-most-downloaded-list-table.php' ,
),
),
),
) );
$reports -> register_endpoint ( 'file_downloads_chart' , array (
'label' => __ ( 'Number of File Downloads' , 'easy-digital-downloads' ) . $download_label ,
'views' => array (
'chart' => array (
'data_callback' => function () use ( $filter , $download_data ) {
global $wpdb ;
2023-06-05 11:21:17 +00:00
$dates = Reports\get_dates_filter ( 'objects' );
$chart_dates = Reports\parse_dates_for_range ( null , 'now' , false );
$period = Reports\get_graph_period ();
$sql_clauses = Reports\get_sql_clauses ( $period );
2022-11-27 15:03:07 +00:00
$product_id = '' ;
$price_id = '' ;
if ( is_array ( $download_data ) ) {
$product_id = $wpdb -> prepare ( 'AND product_id = %d' , absint ( $download_data [ 'download_id' ] ) );
$price_id = isset ( $download_data [ 'price_id' ] ) && is_numeric ( $download_data [ 'price_id' ] )
? $wpdb -> prepare ( 'AND price_id = %d' , absint ( $download_data [ 'price_id' ] ) )
: '' ;
}
$results = $wpdb -> get_results ( $wpdb -> prepare (
" SELECT COUNT(id) AS total, { $sql_clauses [ 'select' ] }
FROM { $wpdb -> edd_logs_file_downloads } edd_lfd
WHERE edd_lfd . date_created >= % s AND edd_lfd . date_created <= % s { $product_id } { $price_id }
GROUP BY { $sql_clauses [ 'groupby' ]}
ORDER BY { $sql_clauses [ 'orderby' ]} ASC " ,
$dates [ 'start' ] -> copy () -> format ( 'mysql' ), $dates [ 'end' ] -> copy () -> format ( 'mysql' ) ) );
$file_downloads = array ();
// Initialise all arrays with timestamps and set values to 0.
while ( strtotime ( $chart_dates [ 'start' ] -> copy () -> format ( 'mysql' ) ) <= strtotime ( $chart_dates [ 'end' ] -> copy () -> format ( 'mysql' ) ) ) {
$timestamp = $chart_dates [ 'start' ] -> copy () -> format ( 'U' );
$date_on_chart = $chart_dates [ 'start' ];
$file_downloads [ $timestamp ][ 0 ] = $date_on_chart -> format ( 'Y-m-d H:i:s' );
$file_downloads [ $timestamp ][ 1 ] = 0 ;
foreach ( $results as $result ) {
2023-06-05 11:21:17 +00:00
$date_of_db_value = EDD () -> utils -> date ( $result -> date );
2022-11-27 15:03:07 +00:00
// Add any file downloads that happened during this hour.
2023-06-05 11:21:17 +00:00
if ( 'hour' === $period ) {
2022-11-27 15:03:07 +00:00
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m-d H' ) === $date_on_chart -> format ( 'Y-m-d H' ) ) {
$file_downloads [ $timestamp ][ 1 ] += absint ( $result -> total );
}
// Add any file downloads that happened during this day.
2023-06-05 11:21:17 +00:00
} elseif ( 'day' === $period ) {
2022-11-27 15:03:07 +00:00
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m-d' ) === $date_on_chart -> format ( 'Y-m-d' ) ) {
$file_downloads [ $timestamp ][ 1 ] += absint ( $result -> total );
}
// Add any file downloads that happened during this month.
} else {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m' ) === $date_on_chart -> format ( 'Y-m' ) ) {
$file_downloads [ $timestamp ][ 1 ] += absint ( $result -> total );
}
}
}
// Move the chart along to the next hour/day/month to get ready for the next loop.
2023-06-05 11:21:17 +00:00
if ( 'hour' === $period ) {
2022-11-27 15:03:07 +00:00
$chart_dates [ 'start' ] -> addHour ( 1 );
2023-06-05 11:21:17 +00:00
} elseif ( 'day' === $period ) {
2022-11-27 15:03:07 +00:00
$chart_dates [ 'start' ] -> addDays ( 1 );
} else {
$chart_dates [ 'start' ] -> addMonth ( 1 );
}
}
$file_downloads = array_values ( $file_downloads );
return array ( 'file_downloads' => $file_downloads );
},
'type' => 'line' ,
'options' => array (
'datasets' => array (
'file_downloads' => array (
'label' => __ ( 'File Downloads' , 'easy-digital-downloads' ),
'borderColor' => 'rgba(24,126,244,0.75)' ,
'backgroundColor' => 'rgba(24,126,244,0.1)' ,
'fill' => true ,
'borderWidth' => 2 ,
'pointRadius' => 4 ,
'pointHoverRadius' => 6 ,
'pointBackgroundColor' => 'rgb(255,255,255)' ,
'yAxisID' => 'file-downloads-y' ,
),
),
'scales' => array (
'yAxes' => array (
array (
'id' => 'file-downloads-y' ,
'type' => 'linear' ,
'display' => true ,
'position' => 'left' ,
'ticks' => array (
'maxTicksLimit' => 5 ,
'formattingType' => 'integer' ,
'suggestedMin' => 0 ,
'beginAtZero' => true ,
'precision' => 0 ,
),
),
),
),
),
),
),
) );
} catch ( \EDD_Exception $exception ) {
edd_debug_log_exception ( $exception );
}
}
add_action ( 'edd_reports_init' , 'edd_register_file_downloads_report' );
/**
* Register discounts report and endpoints .
*
* @ since 3.0
*
* @ param \EDD\Reports\Data\Report_Registry $reports Report registry .
*/
function edd_register_discounts_report ( $reports ) {
try {
// Variables to hold date filter values.
$options = Reports\get_dates_filter_options ();
$filter = Reports\get_filter_value ( 'dates' );
$currency = Reports\get_filter_value ( 'currencies' );
$hbh = Reports\get_dates_filter_hour_by_hour ();
$label = $options [ $filter [ 'range' ] ] . ( $hbh ? ' (' . edd_get_timezone_abbr () . ')' : '' );
$discount = Reports\get_filter_value ( 'discounts' );
$discount = ! empty ( $discount ) && 'all' !== $discount
? $discount
: 0 ;
$d = edd_get_discount ( $discount );
$discount_label = false !== $d
? esc_html ( ' (' . $d -> name . ')' )
: '' ;
$tiles = array_filter ( array (
'number_of_discounts_used' ,
'ratio_of_discounted_orders' ,
'customer_savings' ,
'average_discount_amount' ,
'most_popular_discount' ,
'discount_usage_count' ,
), function ( $tile ) use ( $discount ) {
switch ( $tile ) {
case 'discount_usage_count' :
return 0 !== $discount ;
break ;
default :
return 0 === $discount ;
}
} );
$tables = array_filter ( array (
'top_five_discounts' ,
), function ( $table ) use ( $discount ) {
return 0 === $discount ;
} );
$charts = array (
'discount_usage_chart' ,
);
$reports -> add_report ( 'discounts' , array (
'label' => __ ( 'Discounts' , 'easy-digital-downloads' ),
'icon' => 'tickets-alt' ,
'priority' => 35 ,
'endpoints' => array (
'tiles' => $tiles ,
'tables' => $tables ,
'charts' => $charts ,
),
'filters' => array ( 'dates' , 'discounts' ),
) );
$reports -> register_endpoint ( 'number_of_discounts_used' , array (
'label' => __ ( 'Number of Discounts Used' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $filter ) {
$stats = new EDD\Stats ();
return $stats -> get_discount_usage_count ( array (
'range' => $filter [ 'range' ],
) );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'ratio_of_discounted_orders' , array (
'label' => __ ( 'Discount Ratio' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $filter ) {
$stats = new EDD\Stats ();
return $stats -> get_ratio_of_discounted_orders ( array (
'range' => $filter [ 'range' ],
) );
},
'display_args' => array (
'context' => 'secondary' ,
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'customer_savings' , array (
'label' => __ ( 'Customer Savings' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $filter , $d ) {
$stats = new EDD\Stats ();
return $stats -> get_discount_savings ( array (
'range' => $filter [ 'range' ],
'output' => 'formatted' ,
'discount_code' => isset ( $d -> code )
? $d -> code
: '' ,
) );
},
'display_args' => array (
'comparison_label' => $label . $discount_label ,
),
),
),
) );
$reports -> register_endpoint ( 'average_discount_amount' , array (
'label' => __ ( 'Average Discount Amount' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $filter ) {
$stats = new EDD\Stats ();
return $stats -> get_average_discount_amount ( array (
'range' => $filter [ 'range' ],
'output' => 'formatted' ,
) );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'most_popular_discount' , array (
'label' => __ ( 'Most Popular Discount' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $filter ) {
$stats = new EDD\Stats ();
$r = $stats -> get_most_popular_discounts ( array (
'range' => $filter [ 'range' ],
'number' => 1 ,
) );
if ( ! empty ( $r ) ) {
$r = $r [ 0 ];
return esc_html ( $r -> code . ' (' . $r -> count . ')' );
}
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
if ( $d ) {
$reports -> register_endpoint ( 'discount_usage_count' , array (
'label' => __ ( 'Discount Usage Count' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $filter , $d ) {
$stats = new EDD\Stats ();
return $stats -> get_discount_usage_count ( array (
'range' => $filter [ 'range' ],
'discount_code' => $d -> code ,
) );
},
'display_args' => array (
'comparison_label' => $label . $discount_label ,
),
),
),
) );
}
$reports -> register_endpoint ( 'top_five_discounts' , array (
'label' => __ ( 'Top Five Discounts' , 'easy-digital-downloads' ) . ' – ' . $label ,
'views' => array (
'table' => array (
'display_args' => array (
'class_name' => '\\EDD\\Reports\\Data\\Discounts\\Top_Five_Discounts_List_Table' ,
'class_file' => EDD_PLUGIN_DIR . 'includes/reports/data/discounts/class-top-five-discounts-list-table.php' ,
),
),
),
) );
if ( $d ) {
$reports -> register_endpoint ( 'discount_usage_chart' , array (
'label' => __ ( 'Discount Usage' , 'easy-digital-downloads' ),
'views' => array (
'chart' => array (
'data_callback' => function () use ( $filter , $d ) {
global $wpdb ;
$dates = Reports\get_dates_filter ( 'objects' );
$chart_dates = Reports\parse_dates_for_range ( null , 'now' , false );
2023-06-05 11:21:17 +00:00
$period = Reports\get_graph_period ();
$sql_clauses = Reports\get_sql_clauses ( $period , 'edd_oa.date_created' );
2022-11-27 15:03:07 +00:00
$discount_code = ! empty ( $d -> code )
? $wpdb -> prepare ( 'AND type = %s AND description = %s' , 'discount' , esc_sql ( $d -> code ) )
: $wpdb -> prepare ( 'AND type = %s' , 'discount' );
$results = $wpdb -> get_results ( $wpdb -> prepare (
" SELECT COUNT(id) AS total, { $sql_clauses [ 'select' ] }
FROM { $wpdb -> edd_order_adjustments } edd_oa
WHERE 1 = 1 { $discount_code } AND edd_oa . date_created >= % s AND edd_oa . date_created <= % s
GROUP BY { $sql_clauses [ 'groupby' ]}
ORDER BY { $sql_clauses [ 'orderby' ]} ASC " ,
$dates [ 'start' ] -> copy () -> format ( 'mysql' ), $dates [ 'end' ] -> copy () -> format ( 'mysql' ) ) );
$discount_usage = array ();
// Initialise all arrays with timestamps and set values to 0.
while ( strtotime ( $chart_dates [ 'start' ] -> copy () -> format ( 'mysql' ) ) <= strtotime ( $chart_dates [ 'end' ] -> copy () -> format ( 'mysql' ) ) ) {
$timestamp = $chart_dates [ 'start' ] -> copy () -> format ( 'U' );
$date_on_chart = $chart_dates [ 'start' ];
$discount_usage [ $timestamp ][ 0 ] = $date_on_chart -> format ( 'Y-m-d H:i:s' );
$discount_usage [ $timestamp ][ 1 ] = 0 ;
// Loop through each date in which there were discount codes used, which we queried from the database.
foreach ( $results as $result ) {
2023-06-05 11:21:17 +00:00
$date_of_db_value = EDD () -> utils -> date ( $result -> date );
2022-11-27 15:03:07 +00:00
// Add any discount codes that were used during this hour.
2023-06-05 11:21:17 +00:00
if ( 'hour' === $period ) {
2022-11-27 15:03:07 +00:00
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m-d H' ) === $date_on_chart -> format ( 'Y-m-d H' ) ) {
$discount_usage [ $timestamp ][ 1 ] += abs ( $result -> total );
}
// Add any discount codes that were used during this day.
2023-06-05 11:21:17 +00:00
} elseif ( 'day' === $period ) {
2022-11-27 15:03:07 +00:00
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m-d' ) === $date_on_chart -> format ( 'Y-m-d' ) ) {
$discount_usage [ $timestamp ][ 1 ] += abs ( $result -> total );
}
// Add any discount codes that were used during this month.
} else {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m' ) === $date_on_chart -> format ( 'Y-m' ) ) {
$discount_usage [ $timestamp ][ 1 ] += abs ( $result -> total );
}
}
}
// Move the chart along to the next hour/day/month to get ready for the next loop.
2023-06-05 11:21:17 +00:00
if ( 'hour' === $period ) {
2022-11-27 15:03:07 +00:00
$chart_dates [ 'start' ] -> addHour ( 1 );
2023-06-05 11:21:17 +00:00
} elseif ( 'day' === $period ) {
2022-11-27 15:03:07 +00:00
$chart_dates [ 'start' ] -> addDays ( 1 );
} else {
$chart_dates [ 'start' ] -> addMonth ( 1 );
}
}
$discount_usage = array_values ( $discount_usage );
return array ( 'discount_usage' => $discount_usage );
},
'type' => 'line' ,
'options' => array (
'datasets' => array (
'discount_usage' => array (
'label' => __ ( 'Discount Usage' , 'easy-digital-downloads' ),
'borderColor' => 'rgba(24,126,244,0.75)' ,
'backgroundColor' => 'rgba(24,126,244,0.1)' ,
'fill' => true ,
'borderWidth' => 2 ,
'pointRadius' => 4 ,
'pointHoverRadius' => 6 ,
'pointBackgroundColor' => 'rgb(255,255,255)' ,
),
),
'scales' => array (
'yAxes' => array (
array (
'type' => 'linear' ,
'display' => true ,
'position' => 'left' ,
'ticks' => array (
'maxTicksLimit' => 2 ,
'formattingType' => 'integer' ,
'suggestedMin' => 0 ,
'beginAtZero' => true ,
'precision' => 0 ,
),
),
),
),
),
),
),
) );
}
} catch ( \EDD_Exception $exception ) {
edd_debug_log_exception ( $exception );
}
}
add_action ( 'edd_reports_init' , 'edd_register_discounts_report' );
/**
* Register customer report and endpoints .
*
* @ since 3.0
*
* @ param \EDD\Reports\Data\Report_Registry $reports Report registry .
*/
function edd_register_customer_report ( $reports ) {
try {
// Variables to hold date filter values.
$options = Reports\get_dates_filter_options ();
$dates = Reports\get_filter_value ( 'dates' );
$exclude_taxes = Reports\get_taxes_excluded_filter ();
$hbh = Reports\get_dates_filter_hour_by_hour ();
$label = $options [ $dates [ 'range' ] ] . ( $hbh ? ' (' . edd_get_timezone_abbr () . ')' : '' );
$reports -> add_report ( 'customers' , array (
'label' => __ ( 'Customers' , 'easy-digital-downloads' ),
'icon' => 'groups' ,
'priority' => 40 ,
'endpoints' => array (
'tiles' => array (
'new_customer_growth' ,
'average_revenue_per_customer' ,
'average_number_of_orders_per_customer' ,
),
'tables' => array (
'top_five_customers' ,
'most_valuable_customers' ,
),
'charts' => array (
'new_customers' ,
),
),
) );
$reports -> register_endpoint ( 'new_customer_growth' , array (
'label' => __ ( 'New Customers' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates ) {
$stats = new EDD\Stats ();
return $stats -> get_customer_count ( array (
2023-03-17 22:34:04 +00:00
'range' => $dates [ 'range' ],
'relative' => true ,
'purchase_count' => true ,
2022-11-27 15:03:07 +00:00
) );
},
'display_args' => array (
'comparison_label' => $label ,
),
),
),
) );
$reports -> register_endpoint ( 'average_revenue_per_customer' , array (
'label' => __ ( 'Average Revenue per Customer' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () {
$stats = new EDD\Stats ();
return $stats -> get_customer_lifetime_value ( array (
'function' => 'AVG' ,
'output' => 'formatted' ,
) );
},
),
),
) );
$reports -> register_endpoint ( 'average_number_of_orders_per_customer' , array (
'label' => __ ( 'Average Orders per Customer' , 'easy-digital-downloads' ),
'views' => array (
'tile' => array (
'data_callback' => function () use ( $dates ) {
$stats = new EDD\Stats ();
return $stats -> get_customer_order_count ( array (
'range' => $dates [ 'range' ],
'function' => 'AVG' ,
'relative' => true ,
) );
},
),
),
) );
$reports -> register_endpoint ( 'top_five_customers' , array (
'label' => __ ( 'Top Five Customers — All Time' , 'easy-digital-downloads' ),
'views' => array (
'table' => array (
'display_args' => array (
'class_name' => '\\EDD\\Reports\\Data\\Customers\\Top_Five_Customers_List_Table' ,
'class_file' => EDD_PLUGIN_DIR . 'includes/reports/data/customers/class-top-five-customers-list-table.php' ,
),
),
),
) );
$reports -> register_endpoint ( 'most_valuable_customers' , array (
'label' => __ ( 'Most Valuable Customers' , 'easy-digital-downloads' ) . ' — ' . $label ,
'views' => array (
'table' => array (
'display_args' => array (
'class_name' => '\\EDD\\Reports\\Data\\Customers\\Most_Valuable_Customers_List_Table' ,
'class_file' => EDD_PLUGIN_DIR . 'includes/reports/data/customers/class-most-valuable-customers-list-table.php' ,
),
),
),
) );
$reports -> register_endpoint ( 'new_customers' , array (
'label' => __ ( 'New Customers' , 'easy-digital-downloads' ) . ' — ' . $label ,
'views' => array (
'chart' => array (
'data_callback' => function () {
global $wpdb ;
$dates = Reports\get_dates_filter ( 'objects' );
$chart_dates = Reports\parse_dates_for_range ( null , 'now' , false );
2023-06-05 11:21:17 +00:00
$period = Reports\get_graph_period ();
$sql_clauses = Reports\get_sql_clauses ( $period );
2022-11-27 15:03:07 +00:00
$results = $wpdb -> get_results ( $wpdb -> prepare (
" SELECT COUNT(c.id) AS total, { $sql_clauses [ 'select' ] }
2023-03-17 22:34:04 +00:00
FROM { $wpdb -> edd_customers } c
WHERE c . date_created >= % s AND c . date_created <= % s
AND c . purchase_count > 0
GROUP BY { $sql_clauses [ 'groupby' ]}
ORDER BY { $sql_clauses [ 'orderby' ]} ASC " ,
$dates [ 'start' ] -> copy () -> format ( 'mysql' ),
$dates [ 'end' ] -> copy () -> format ( 'mysql' ) ) );
2022-11-27 15:03:07 +00:00
$customers = array ();
// Initialise all arrays with timestamps and set values to 0.
while ( strtotime ( $chart_dates [ 'start' ] -> copy () -> format ( 'mysql' ) ) <= strtotime ( $chart_dates [ 'end' ] -> copy () -> format ( 'mysql' ) ) ) {
$timestamp = $chart_dates [ 'start' ] -> copy () -> format ( 'U' );
$date_on_chart = $chart_dates [ 'start' ];
$customers [ $timestamp ][ 0 ] = $date_on_chart -> format ( 'Y-m-d H:i:s' );
$customers [ $timestamp ][ 1 ] = 0 ;
foreach ( $results as $result ) {
2023-06-05 11:21:17 +00:00
$date_of_db_value = EDD () -> utils -> date ( $result -> date );
2022-11-27 15:03:07 +00:00
// Add any new customers that were created during this hour.
2023-06-05 11:21:17 +00:00
if ( 'hour' === $period ) {
2022-11-27 15:03:07 +00:00
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m-d H' ) === $date_on_chart -> format ( 'Y-m-d H' ) ) {
$customers [ $timestamp ][ 1 ] += $result -> total ;
}
// Add any new customers that were created during this day.
2023-06-05 11:21:17 +00:00
} elseif ( 'day' === $period ) {
2022-11-27 15:03:07 +00:00
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m-d' ) === $date_on_chart -> format ( 'Y-m-d' ) ) {
$customers [ $timestamp ][ 1 ] += $result -> total ;
}
// Add any new customers that were created during this month.
} else {
// If the date of this db value matches the date on this line graph/chart, set the y axis value for the chart to the number in the DB result.
if ( $date_of_db_value -> format ( 'Y-m' ) === $date_on_chart -> format ( 'Y-m' ) ) {
$customers [ $timestamp ][ 1 ] += $result -> total ;
}
}
}
// Move the chart along to the next hour/day/month to get ready for the next loop.
2023-06-05 11:21:17 +00:00
if ( 'hour' === $period ) {
2022-11-27 15:03:07 +00:00
$chart_dates [ 'start' ] -> addHour ( 1 );
2023-06-05 11:21:17 +00:00
} elseif ( 'day' === $period ) {
2022-11-27 15:03:07 +00:00
$chart_dates [ 'start' ] -> addDays ( 1 );
} else {
$chart_dates [ 'start' ] -> addMonth ( 1 );
}
}
return array (
'customers' => array_values ( $customers ),
);
},
'type' => 'line' ,
'options' => array (
'datasets' => array (
'customers' => array (
'label' => __ ( 'New Customers' , 'easy-digital-downloads' ),
'borderColor' => 'rgba(24,126,244,0.75)' ,
'backgroundColor' => 'rgba(24,126,244,0.1)' ,
'fill' => true ,
'borderWidth' => 2 ,
'pointRadius' => 4 ,
'pointHoverRadius' => 6 ,
'pointBackgroundColor' => 'rgb(255,255,255)' ,
),
),
'scales' => array (
'yAxes' => array (
array (
'type' => 'linear' ,
'display' => true ,
'position' => 'left' ,
'ticks' => array (
'maxTicksLimit' => 5 ,
'formattingType' => 'integer' ,
'suggestedMin' => 0 ,
'beginAtZero' => true ,
'precision' => 0 ,
),
),
),
),
),
),
),
) );
} catch ( \EDD_Exception $exception ) {
edd_debug_log_exception ( $exception );
}
}
add_action ( 'edd_reports_init' , 'edd_register_customer_report' );
/**
* Register export report and endpoints .
*
* @ since 3.0
*
* @ param \EDD\Reports\Data\Report_Registry $reports Report registry .
*/
function edd_register_export_report ( $reports ) {
try {
$reports -> add_report ( 'export' , array (
'label' => __ ( 'Export' , 'easy-digital-downloads' ),
'icon' => 'migrate' ,
'priority' => 1000 ,
'capability' => 'export_shop_reports' ,
'display_callback' => 'display_export_report' ,
'filters' => false ,
) );
} catch ( \EDD_Exception $exception ) {
edd_debug_log_exception ( $exception );
}
}
add_action ( 'edd_reports_init' , 'edd_register_export_report' );
/**
* Render the `Export` report .
*
* @ since 3.0
*/
function display_export_report () {
wp_enqueue_script ( 'edd-admin-tools-export' );
?>
< div id = " edd-dashboard-widgets-wrap " >
< div class = " metabox-holder " >
< div id = " post-body " >
< div id = " post-body-content " class = " edd-reports-export edd-admin--has-grid " >
2023-03-17 22:34:04 +00:00
< ? php
do_action ( 'edd_reports_tab_export_content_top' );
$views = array (
'earnings-report' ,
'sales-earnings' ,
'sales' ,
'orders' ,
'taxed-orders' ,
'customers' ,
'taxed-customers' ,
'downloads' ,
'api-requests' ,
'download-history' ,
);
foreach ( $views as $view ) {
include " views/export- { $view } .php " ;
}
do_action ( 'edd_reports_tab_export_content_bottom' );
?>
2022-11-27 15:03:07 +00:00
</ div >
</ div >
</ div >
</ div >
< ? php
}
/**
* Retrieves estimated monthly earnings and sales
*
* @ since 1.5
*
* @ param bool $include_taxes If the estimated earnings should include taxes
* @ return array
*/
function edd_estimated_monthly_stats ( $include_taxes = true ) {
$estimated = get_transient ( 'edd_estimated_monthly_stats' . $include_taxes );
if ( false === $estimated ) {
$estimated = array (
'earnings' => 0 ,
'sales' => 0
);
$stats = new EDD_Payment_Stats ;
$to_date_earnings = $stats -> get_earnings ( 0 , 'this_month' , null , $include_taxes );
$to_date_sales = $stats -> get_sales ( 0 , 'this_month' );
$current_day = date ( 'd' , current_time ( 'timestamp' ) );
$current_month = date ( 'n' , current_time ( 'timestamp' ) );
$current_year = date ( 'Y' , current_time ( 'timestamp' ) );
$days_in_month = cal_days_in_month ( CAL_GREGORIAN , $current_month , $current_year );
$estimated [ 'earnings' ] = ( $to_date_earnings / $current_day ) * $days_in_month ;
$estimated [ 'sales' ] = ( $to_date_sales / $current_day ) * $days_in_month ;
// Cache for one day
set_transient ( 'edd_estimated_monthly_stats' . $include_taxes , $estimated , 86400 );
}
return maybe_unserialize ( $estimated );
}
/**
* Adds postbox nonces , which are used to save the position of tile endpoint meta boxes .
*
* @ since 3.0
*/
function edd_add_screen_options_nonces () {
wp_nonce_field ( 'closedpostboxes' , 'closedpostboxesnonce' , false );
wp_nonce_field ( 'meta-box-order' , 'meta-box-order-nonce' , false );
}
add_action ( 'admin_footer' , 'edd_add_screen_options_nonces' );
/**
* This function adds a notice to the bottom of the Tax reports screen if a default tax rate is detected , stating
* that we cannot report on the default tax rate .
*
* @ since 3.0
* @ param \EDD\Reports\Data\Report | \WP_Error $report The current report object , or WP_Error if invalid .
*/
function edd_tax_report_notice ( $report ) {
if ( 'taxes' === $report -> object_id && false !== edd_get_option ( 'tax_rate' ) ) {
?>
< p class = " description " >
< strong >< ? php esc_html_e ( 'Notice' , 'easy-digital-downloads' ); ?> : </strong>
< ? php esc_html_e ( 'Tax reports are only generated for taxes associated with a location. The legacy default tax rate is unable to be reported on.' , 'easy-digital-downloads' ); ?>
</ p >
< ? php
}
}
add_action ( 'edd_reports_page_bottom' , 'edd_tax_report_notice' , 10 , 1 );
/**
* Will return HTML for relative date ranges dropdown .
*
* @ since 3.1
*/
function edd_reports_get_relative_date_ranges () {
require_once EDD_PLUGIN_DIR . 'includes/reports/reports-functions.php' ;
$range = isset ( $_REQUEST [ 'range' ] )
? sanitize_text_field ( $_REQUEST [ 'range' ] )
: '' ;
$relative_range = isset ( $_REQUEST [ 'relative_range' ] )
? sanitize_text_field ( $_REQUEST [ 'relative_range' ] )
: '' ;
if ( empty ( $range ) || empty ( $relative_range ) ) {
return ;
}
echo Reports\display_relative_dates_dropdown_options ( $range , $relative_range );
edd_die ();
}
add_action ( 'wp_ajax_edd_reports_get_relative_date_ranges' , 'edd_reports_get_relative_date_ranges' );