2018-09-17 14:32:03 +00:00
< ? php
/**
* REST API Reports orders stats controller
*
* Handles requests to the / reports / orders / stats endpoint .
*
2018-09-17 19:13:19 +00:00
* @ package WooCommerce Admin / API
2018-09-17 14:32:03 +00:00
*/
defined ( 'ABSPATH' ) || exit ;
/**
* REST API Reports orders stats controller class .
*
* @ package WooCommerce / API
2019-01-15 01:53:02 +00:00
* @ extends WC_Admin_REST_Reports_Controller
2018-09-17 14:32:03 +00:00
*/
2019-01-15 01:53:02 +00:00
class WC_Admin_REST_Reports_Orders_Stats_Controller extends WC_Admin_REST_Reports_Controller {
2018-09-17 14:32:03 +00:00
/**
* Endpoint namespace .
*
* @ var string
*/
2019-01-18 02:52:58 +00:00
protected $namespace = 'wc/v4' ;
2018-09-17 14:32:03 +00:00
/**
* Route base .
*
* @ var string
*/
protected $rest_base = 'reports/orders/stats' ;
/**
* Maps query arguments from the REST request .
*
* @ param array $request Request array .
* @ return array
*/
protected function prepare_reports_query ( $request ) {
2018-11-01 11:37:49 +00:00
$args = array ();
$args [ 'before' ] = $request [ 'before' ];
$args [ 'after' ] = $request [ 'after' ];
$args [ 'interval' ] = $request [ 'interval' ];
$args [ 'page' ] = $request [ 'page' ];
$args [ 'per_page' ] = $request [ 'per_page' ];
$args [ 'orderby' ] = $request [ 'orderby' ];
$args [ 'order' ] = $request [ 'order' ];
2018-11-13 15:24:57 +00:00
$args [ 'match' ] = $request [ 'match' ];
$args [ 'status_is' ] = ( array ) $request [ 'status_is' ];
$args [ 'status_is_not' ] = ( array ) $request [ 'status_is_not' ];
$args [ 'product_includes' ] = ( array ) $request [ 'product_includes' ];
$args [ 'product_excludes' ] = ( array ) $request [ 'product_excludes' ];
2018-12-20 11:35:45 +00:00
$args [ 'coupon_includes' ] = ( array ) $request [ 'coupon_includes' ];
$args [ 'coupon_excludes' ] = ( array ) $request [ 'coupon_excludes' ];
2018-11-16 16:51:33 +00:00
$args [ 'customer' ] = $request [ 'customer' ];
2018-11-13 15:24:57 +00:00
$args [ 'categories' ] = ( array ) $request [ 'categories' ];
2018-12-20 11:35:45 +00:00
$args [ 'segmentby' ] = $request [ 'segmentby' ];
2018-09-17 14:32:03 +00:00
return $args ;
}
/**
* Get all reports .
*
* @ param WP_REST_Request $request Request data .
* @ return array | WP_Error
*/
public function get_items ( $request ) {
$query_args = $this -> prepare_reports_query ( $request );
2018-09-17 19:13:19 +00:00
$orders_query = new WC_Admin_Reports_Orders_Stats_Query ( $query_args );
2019-01-29 11:13:52 +00:00
try {
$report_data = $orders_query -> get_data ();
} catch ( WC_Admin_Reports_Parameter_Exception $e ) {
return new WP_Error ( $e -> getErrorCode (), $e -> getMessage (), array ( 'status' => $e -> getCode () ) );
}
2018-09-17 14:32:03 +00:00
$out_data = array (
'totals' => get_object_vars ( $report_data -> totals ),
'intervals' => array (),
);
foreach ( $report_data -> intervals as $interval_data ) {
$item = $this -> prepare_item_for_response ( $interval_data , $request );
$out_data [ 'intervals' ][] = $this -> prepare_response_for_collection ( $item );
}
$response = rest_ensure_response ( $out_data );
$response -> header ( 'X-WP-Total' , ( int ) $report_data -> total );
$response -> header ( 'X-WP-TotalPages' , ( int ) $report_data -> pages );
$page = $report_data -> page_no ;
$max_pages = $report_data -> pages ;
$base = add_query_arg ( $request -> get_query_params (), rest_url ( sprintf ( '/%s/%s' , $this -> namespace , $this -> rest_base ) ) );
if ( $page > 1 ) {
$prev_page = $page - 1 ;
if ( $prev_page > $max_pages ) {
$prev_page = $max_pages ;
}
$prev_link = add_query_arg ( 'page' , $prev_page , $base );
$response -> link_header ( 'prev' , $prev_link );
}
if ( $max_pages > $page ) {
$next_page = $page + 1 ;
$next_link = add_query_arg ( 'page' , $next_page , $base );
$response -> link_header ( 'next' , $next_link );
}
return $response ;
}
/**
* Prepare a report object for serialization .
*
* @ param Array $report Report data .
* @ param WP_REST_Request $request Request object .
* @ return WP_REST_Response
*/
public function prepare_item_for_response ( $report , $request ) {
$data = $report ;
$context = ! empty ( $request [ 'context' ] ) ? $request [ 'context' ] : 'view' ;
$data = $this -> add_additional_fields_to_object ( $data , $request );
$data = $this -> filter_response_by_context ( $data , $context );
// Wrap the data in a response object.
$response = rest_ensure_response ( $data );
/**
* Filter a report returned from the API .
*
* Allows modification of the report data right before it is returned .
*
* @ param WP_REST_Response $response The response object .
* @ param object $report The original report object .
* @ param WP_REST_Request $request Request used to generate the response .
*/
return apply_filters ( 'woocommerce_rest_prepare_report_orders_stats' , $response , $report , $request );
}
/**
* Get the Report ' s schema , conforming to JSON Schema .
*
* @ return array
*/
public function get_item_schema () {
2018-12-20 11:35:45 +00:00
$data_values = array (
'net_revenue' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Net revenue.' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'number' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
2019-01-17 14:08:59 +00:00
'format' => 'currency' ,
2018-09-17 14:32:03 +00:00
),
2018-12-20 11:35:45 +00:00
'orders_count' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Amount of orders' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'integer' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
2019-01-17 14:08:59 +00:00
'indicator' => true ,
),
2019-03-13 17:14:02 +00:00
'avg_order_value' => array (
'description' => __ ( 'Average order value.' , 'woocommerce-admin' ),
2019-01-17 14:08:59 +00:00
'type' => 'number' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
'indicator' => true ,
'format' => 'currency' ,
2018-09-17 14:32:03 +00:00
),
2018-12-20 11:35:45 +00:00
'avg_items_per_order' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Average items per order' , 'woocommerce-admin' ),
2019-02-14 03:14:01 +00:00
'type' => 'number' ,
2018-09-17 14:32:03 +00:00
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
),
2019-01-11 14:22:19 +00:00
'num_items_sold' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Number of items sold' , 'woocommerce-admin' ),
2019-01-11 14:22:19 +00:00
'type' => 'integer' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
),
2019-04-10 08:49:00 +00:00
'coupons' => array (
2019-04-01 02:16:57 +00:00
'description' => __ ( 'Amount discounted by coupons.' , 'woocommerce-admin' ),
'type' => 'number' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
),
'coupons_count' => array (
'description' => __ ( 'Unique coupons count.' , 'woocommerce-admin' ),
2018-12-20 11:35:45 +00:00
'type' => 'number' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
),
'num_returning_customers' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Number of orders done by returning customers' , 'woocommerce-admin' ),
2018-12-20 11:35:45 +00:00
'type' => 'integer' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
),
'num_new_customers' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Number of orders done by new customers' , 'woocommerce-admin' ),
2018-12-20 11:35:45 +00:00
'type' => 'integer' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
),
'products' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Number of distinct products sold.' , 'woocommerce-admin' ),
2018-12-20 11:35:45 +00:00
'type' => 'number' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
),
2018-09-17 14:32:03 +00:00
);
2018-12-20 11:35:45 +00:00
$segments = array (
'segments' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Reports data grouped by segment condition.' , 'woocommerce-admin' ),
2018-12-20 11:35:45 +00:00
'type' => 'array' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
'items' => array (
'type' => 'object' ,
'properties' => array (
'segment_id' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Segment identificator.' , 'woocommerce-admin' ),
2019-02-01 17:30:39 +00:00
'type' => 'integer' ,
2018-12-20 11:35:45 +00:00
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
),
'subtotals' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Interval subtotals.' , 'woocommerce-admin' ),
2018-12-20 11:35:45 +00:00
'type' => 'object' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
'properties' => $data_values ,
),
),
),
),
);
$totals = array_merge ( $data_values , $segments );
// Products is not shown in intervals.
unset ( $data_values [ 'products' ] );
2019-01-11 14:22:19 +00:00
$intervals = array_merge ( $data_values , $segments );
2018-09-17 14:32:03 +00:00
$schema = array (
'$schema' => 'http://json-schema.org/draft-04/schema#' ,
'title' => 'report_orders_stats' ,
'type' => 'object' ,
'properties' => array (
'totals' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Totals data.' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'object' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
'properties' => $totals ,
),
'intervals' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Reports data grouped by intervals.' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'array' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
'items' => array (
'type' => 'object' ,
'properties' => array (
'interval' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Type of interval.' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'string' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
'enum' => array ( 'day' , 'week' , 'month' , 'year' ),
),
'date_start' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( " The date the report start, in the site's timezone. " , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'date-time' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
),
'date_start_gmt' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'The date the report start, as GMT.' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'date-time' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
),
'date_end' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( " The date the report end, in the site's timezone. " , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'date-time' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
),
'date_end_gmt' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'The date the report end, as GMT.' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'date-time' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
),
'subtotals' => array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Interval subtotals.' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'object' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
2019-01-11 14:22:19 +00:00
'properties' => $intervals ,
2018-09-17 14:32:03 +00:00
),
),
),
),
),
);
return $this -> add_additional_fields_schema ( $schema );
}
/**
* Get the query params for collections .
*
* @ return array
*/
public function get_collection_params () {
2018-11-15 18:01:22 +00:00
$params = array ();
$params [ 'context' ] = $this -> get_context_param ( array ( 'default' => 'view' ) );
$params [ 'page' ] = array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Current page of the collection.' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'integer' ,
'default' => 1 ,
'sanitize_callback' => 'absint' ,
'validate_callback' => 'rest_validate_request_arg' ,
'minimum' => 1 ,
);
2018-11-15 18:01:22 +00:00
$params [ 'per_page' ] = array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Maximum number of items to be returned in result set.' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'integer' ,
'default' => 10 ,
'minimum' => 1 ,
'maximum' => 100 ,
'sanitize_callback' => 'absint' ,
'validate_callback' => 'rest_validate_request_arg' ,
);
2018-11-15 18:01:22 +00:00
$params [ 'after' ] = array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Limit response to resources published after a given ISO8601 compliant date.' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'string' ,
'format' => 'date-time' ,
'validate_callback' => 'rest_validate_request_arg' ,
);
2018-11-15 18:01:22 +00:00
$params [ 'before' ] = array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Limit response to resources published before a given ISO8601 compliant date.' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'string' ,
'format' => 'date-time' ,
'validate_callback' => 'rest_validate_request_arg' ,
);
2018-11-15 18:01:22 +00:00
$params [ 'order' ] = array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Order sort attribute ascending or descending.' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'string' ,
'default' => 'desc' ,
'enum' => array ( 'asc' , 'desc' ),
'validate_callback' => 'rest_validate_request_arg' ,
);
2018-11-15 18:01:22 +00:00
$params [ 'orderby' ] = array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Sort collection by object attribute.' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'string' ,
'default' => 'date' ,
'enum' => array (
'date' ,
'net_revenue' ,
'orders_count' ,
'avg_order_value' ,
),
'validate_callback' => 'rest_validate_request_arg' ,
);
2018-11-15 18:01:22 +00:00
$params [ 'interval' ] = array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Time interval to use for buckets in the returned data.' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'string' ,
'default' => 'week' ,
'enum' => array (
'hour' ,
'day' ,
'week' ,
'month' ,
'quarter' ,
'year' ,
),
'validate_callback' => 'rest_validate_request_arg' ,
);
2018-11-15 18:01:22 +00:00
$params [ 'match' ] = array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Indicates whether all the conditions should be true for the resulting set, or if any one of them is sufficient. Match affects the following parameters: status_is, status_is_not, product_includes, product_excludes, coupon_includes, coupon_excludes, customer, categories' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'string' ,
2018-11-15 18:01:22 +00:00
'default' => 'all' ,
'enum' => array (
'all' ,
'any' ,
),
2018-09-17 14:32:03 +00:00
'validate_callback' => 'rest_validate_request_arg' ,
);
2018-11-15 18:01:22 +00:00
$params [ 'status_is' ] = array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Limit result set to items that have the specified order status.' , 'woocommerce-admin' ),
2018-11-15 18:01:22 +00:00
'type' => 'array' ,
'sanitize_callback' => 'wp_parse_slug_list' ,
2018-09-17 14:32:03 +00:00
'validate_callback' => 'rest_validate_request_arg' ,
2019-01-16 02:23:00 +00:00
'default' => null ,
2018-11-15 18:01:22 +00:00
'items' => array (
'enum' => $this -> get_order_statuses (),
'type' => 'string' ,
),
2018-09-17 14:32:03 +00:00
);
2018-11-15 18:01:22 +00:00
$params [ 'status_is_not' ] = array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Limit result set to items that don\'t have the specified order status.' , 'woocommerce-admin' ),
2018-09-17 14:32:03 +00:00
'type' => 'array' ,
'sanitize_callback' => 'wp_parse_slug_list' ,
'validate_callback' => 'rest_validate_request_arg' ,
'items' => array (
'enum' => $this -> get_order_statuses (),
'type' => 'string' ,
),
);
2018-11-15 18:01:22 +00:00
$params [ 'product_includes' ] = array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Limit result set to items that have the specified product(s) assigned.' , 'woocommerce-admin' ),
2018-11-15 18:01:22 +00:00
'type' => 'array' ,
'items' => array (
'type' => 'integer' ,
),
'default' => array (),
'sanitize_callback' => 'wp_parse_id_list' ,
);
$params [ 'product_excludes' ] = array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Limit result set to items that don\'t have the specified product(s) assigned.' , 'woocommerce-admin' ),
2018-11-15 18:01:22 +00:00
'type' => 'array' ,
'items' => array (
'type' => 'integer' ,
),
'default' => array (),
'sanitize_callback' => 'wp_parse_id_list' ,
);
2018-12-20 11:35:45 +00:00
$params [ 'coupon_includes' ] = array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Limit result set to items that have the specified coupon(s) assigned.' , 'woocommerce-admin' ),
2018-11-15 18:01:22 +00:00
'type' => 'array' ,
'items' => array (
'type' => 'integer' ,
),
'default' => array (),
'sanitize_callback' => 'wp_parse_id_list' ,
);
2018-12-20 11:35:45 +00:00
$params [ 'coupon_excludes' ] = array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Limit result set to items that don\'t have the specified coupon(s) assigned.' , 'woocommerce-admin' ),
2018-11-15 18:01:22 +00:00
'type' => 'array' ,
'items' => array (
'type' => 'integer' ,
),
'default' => array (),
'sanitize_callback' => 'wp_parse_id_list' ,
);
$params [ 'customer' ] = array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Limit result set to items that don\'t have the specified coupon(s) assigned.' , 'woocommerce-admin' ),
2018-11-15 18:01:22 +00:00
'type' => 'string' ,
'enum' => array (
'new' ,
'returning' ,
),
'validate_callback' => 'rest_validate_request_arg' ,
);
2018-12-20 11:35:45 +00:00
$params [ 'segmentby' ] = array (
2019-03-13 17:14:02 +00:00
'description' => __ ( 'Segment the response by additional constraint.' , 'woocommerce-admin' ),
2018-12-20 11:35:45 +00:00
'type' => 'string' ,
'enum' => array (
'product' ,
'category' ,
'variation' ,
'coupon' ,
'customer_type' , // new vs returning.
),
'validate_callback' => 'rest_validate_request_arg' ,
);
2018-09-17 14:32:03 +00:00
return $params ;
}
2018-11-27 15:39:11 +00:00
2018-09-17 14:32:03 +00:00
}