Adds Jetpack stats to performance indicator endpoints (https://github.com/woocommerce/woocommerce-admin/pull/4291)
* Move allowed report analytics data to separate function * Add function to retrieve allowed Jetpack module endpoints * Fix API urls * Add number format as default for jetpack modules * Add module permissions and format to array * Add filter for returned data from performance indicators API * Filter jetpack stats by queried dates * Fix empty date query filtering * Mock the Jetpack API response * Add tests for Jetpack stats in allowed endpoints * Add tests for filtering Jetpack stats based on time * Add tests for default args
This commit is contained in:
parent
44d5a79346
commit
6fd251bfe4
|
@ -9,6 +9,8 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\API\Reports\PerformanceIndicators;
|
||||
|
||||
use \Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
|
@ -68,6 +70,13 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
*/
|
||||
protected $stats_data = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_filter( 'woocommerce_rest_performance_indicators_data_value', array( $this, 'format_data_value' ), 10, 5 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the routes for reports.
|
||||
*/
|
||||
|
@ -116,16 +125,9 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get information such as allowed stats, stat labels, and endpoint data from stats reports.
|
||||
*
|
||||
* @return WP_Error|True
|
||||
* Get analytics report data and endpoints.
|
||||
*/
|
||||
private function get_indicator_data() {
|
||||
// Data already retrieved.
|
||||
if ( ! empty( $this->endpoints ) && ! empty( $this->labels ) && ! empty( $this->allowed_stats ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_analytics_report_data() {
|
||||
$request = new \WP_REST_Request( 'GET', '/wc-analytics/reports' );
|
||||
$response = rest_do_request( $request );
|
||||
|
||||
|
@ -137,8 +139,7 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
return new \WP_Error( 'woocommerce_analytics_performance_indicators_result_failed', __( 'Sorry, fetching performance indicators failed.', 'woocommerce-admin' ) );
|
||||
}
|
||||
|
||||
$endpoints = $response->get_data();
|
||||
$allowed_stats = array();
|
||||
$endpoints = $response->get_data();
|
||||
|
||||
foreach ( $endpoints as $endpoint ) {
|
||||
if ( '/stats' === substr( $endpoint['slug'], -6 ) ) {
|
||||
|
@ -162,9 +163,9 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
continue;
|
||||
}
|
||||
|
||||
$stat = $prefix . '/' . $property_key;
|
||||
$allowed_stats[] = $stat;
|
||||
$stat_label = empty( $schema_info['title'] ) ? $schema_info['description'] : $schema_info['title'];
|
||||
$stat = $prefix . '/' . $property_key;
|
||||
$this->allowed_stats[] = $stat;
|
||||
$stat_label = empty( $schema_info['title'] ) ? $schema_info['description'] : $schema_info['title'];
|
||||
|
||||
$this->labels[ $stat ] = trim( preg_replace( '/\W+/', ' ', $stat_label ) );
|
||||
$this->formats[ $stat ] = isset( $schema_info['format'] ) ? $schema_info['format'] : 'number';
|
||||
|
@ -174,8 +175,78 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
$this->urls[ $prefix ] = $endpoint['_links']['report'][0]['href'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get active Jetpack modules and endpoints.
|
||||
*/
|
||||
public function get_jetpack_modules_data() {
|
||||
if ( ! class_exists( '\Jetpack_Core_Json_Api_Endpoints' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$request = new \WP_REST_Request( 'GET', '/jetpack/v4/module/all' );
|
||||
$response = rest_do_request( $request );
|
||||
$items = apply_filters(
|
||||
'woocommerce_rest_performance_indicators_jetpack_items',
|
||||
array(
|
||||
'stats/visitors' => array(
|
||||
'label' => __( 'Visitors', 'woocommerce-admin' ),
|
||||
'permission' => 'view_stats',
|
||||
'format' => 'number',
|
||||
'module' => 'stats',
|
||||
),
|
||||
'stats/views' => array(
|
||||
'label' => __( 'Views', 'woocommerce-admin' ),
|
||||
'permission' => 'view_stats',
|
||||
'format' => 'number',
|
||||
'module' => 'stats',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
if ( 200 !== $response->get_status() || empty( $items ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $response->get_data();
|
||||
|
||||
foreach ( $items as $item_key => $item ) {
|
||||
if ( ! $data[ $item['module'] ] || ! $data[ $item['module'] ]['activated'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $item['permission'] && ! current_user_can( $item['permission'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$stat = 'jetpack/' . $item_key;
|
||||
$endpoint = 'jetpack/' . $item['module'];
|
||||
$this->allowed_stats[] = $stat;
|
||||
$this->labels[ $stat ] = $item['label'];
|
||||
$this->endpoints[ $endpoint ] = '/jetpack/v4/module/' . $item['module'] . '/data';
|
||||
$this->formats[ $stat ] = $item['format'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information such as allowed stats, stat labels, and endpoint data from stats reports.
|
||||
*
|
||||
* @return WP_Error|True
|
||||
*/
|
||||
private function get_indicator_data() {
|
||||
// Data already retrieved.
|
||||
if ( ! empty( $this->endpoints ) && ! empty( $this->labels ) && ! empty( $this->allowed_stats ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->get_analytics_report_data();
|
||||
$this->get_jetpack_modules_data();
|
||||
|
||||
$this->allowed_stats = $allowed_stats;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -254,8 +325,8 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
)
|
||||
);
|
||||
|
||||
$a = array_search( $a->stat, $stat_order );
|
||||
$b = array_search( $b->stat, $stat_order );
|
||||
$a = array_search( $a->stat, $stat_order, true );
|
||||
$b = array_search( $b->stat, $stat_order, true );
|
||||
|
||||
if ( false === $a && false === $b ) {
|
||||
return 0;
|
||||
|
@ -320,7 +391,7 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
$report = $pieces[0];
|
||||
$chart = $pieces[1];
|
||||
|
||||
if ( ! in_array( $stat, $this->allowed_stats ) ) {
|
||||
if ( ! in_array( $stat, $this->allowed_stats, true ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -334,7 +405,7 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
$format = $this->formats[ $stat ];
|
||||
$label = $this->labels[ $stat ];
|
||||
|
||||
if ( 200 !== $response->get_status() || ! isset( $data['totals'][ $chart ] ) ) {
|
||||
if ( 200 !== $response->get_status() ) {
|
||||
$stats[] = (object) array(
|
||||
'stat' => $stat,
|
||||
'chart' => $chart,
|
||||
|
@ -350,7 +421,7 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
'chart' => $chart,
|
||||
'label' => $label,
|
||||
'format' => $format,
|
||||
'value' => $data['totals'][ $chart ],
|
||||
'value' => apply_filters( 'woocommerce_rest_performance_indicators_data_value', $data, $stat, $report, $chart, $query_args ),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -410,14 +481,14 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
$pieces = $this->get_stats_parts( $object->stat );
|
||||
$endpoint = $pieces[0];
|
||||
$stat = $pieces[1];
|
||||
$url = $this->urls[ $endpoint ];
|
||||
$url = isset( $this->urls[ $endpoint ] ) ? $this->urls[ $endpoint ] : '';
|
||||
|
||||
$links = array(
|
||||
'api' => array(
|
||||
'href' => rest_url( $this->endpoints[ $endpoint ] ),
|
||||
),
|
||||
'report' => array(
|
||||
'href' => ! empty( $url ) ? $url : '',
|
||||
'href' => $url,
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -440,6 +511,45 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the data returned from the API for given stats.
|
||||
*
|
||||
* @param array $data Data from external endpoint.
|
||||
* @param string $stat Name of the stat.
|
||||
* @param string $report Name of the report.
|
||||
* @param string $chart Name of the chart.
|
||||
* @param array $query_args Query args.
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_data_value( $data, $stat, $report, $chart, $query_args ) {
|
||||
if ( 'jetpack/stats' === $report ) {
|
||||
// Get the index of the field to tally.
|
||||
$index = array_search( $chart, $data['general']->visits->fields, true );
|
||||
if ( ! $index ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Loop over provided data and filter by the queried date.
|
||||
// Note that this is currently limited to 30 days via the Jetpack API
|
||||
// but the WordPress.com endpoint allows up to 90 days.
|
||||
$total = 0;
|
||||
$before = gmdate( 'Y-m-d', strtotime( isset( $query_args['before'] ) ? $query_args['before'] : TimeInterval::default_before() ) );
|
||||
$after = gmdate( 'Y-m-d', strtotime( isset( $query_args['after'] ) ? $query_args['after'] : TimeInterval::default_after() ) );
|
||||
foreach ( $data['general']->visits->data as $datum ) {
|
||||
if ( $datum[0] >= $after && $datum[0] <= $before ) {
|
||||
$total += $datum[ $index ];
|
||||
}
|
||||
}
|
||||
return $total;
|
||||
}
|
||||
|
||||
if ( isset( $data['totals'] ) && isset( $data['totals'][ $chart ] ) ) {
|
||||
return $data['totals'][ $chart ];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Report's schema, conforming to JSON Schema.
|
||||
*
|
||||
|
|
|
@ -28,6 +28,12 @@ class WC_Tests_API_Reports_Performance_Indicators extends WC_REST_Unit_Test_Case
|
|||
'role' => 'administrator',
|
||||
)
|
||||
);
|
||||
|
||||
// Mock the Jetpack endpoints and permissions.
|
||||
$wp_user = get_userdata( $this->user );
|
||||
$wp_user->add_cap( 'view_stats' );
|
||||
$this->getMockBuilder( 'Jetpack_Core_Json_Api_Endpoints' )->getMock();
|
||||
add_filter( 'rest_post_dispatch', array( $this, 'mock_rest_responses' ), 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -44,7 +50,6 @@ class WC_Tests_API_Reports_Performance_Indicators extends WC_REST_Unit_Test_Case
|
|||
* Test getting indicators.
|
||||
*/
|
||||
public function test_get_indicators() {
|
||||
global $wpdb;
|
||||
wp_set_current_user( $this->user );
|
||||
WC_Helper_Reports::reset_stats_dbs();
|
||||
|
||||
|
@ -90,16 +95,16 @@ class WC_Tests_API_Reports_Performance_Indicators extends WC_REST_Unit_Test_Case
|
|||
$request = new WP_REST_Request( 'GET', $this->endpoint );
|
||||
$request->set_query_params(
|
||||
array(
|
||||
'before' => date( 'Y-m-d 23:59:59', $time ),
|
||||
'after' => date( 'Y-m-d H:00:00', $time - ( 7 * DAY_IN_SECONDS ) ),
|
||||
'stats' => 'orders/orders_count,downloads/download_count,test/bogus_stat',
|
||||
'before' => gmdate( 'Y-m-d 23:59:59', $time ),
|
||||
'after' => gmdate( 'Y-m-d H:00:00', $time - ( 7 * DAY_IN_SECONDS ) ),
|
||||
'stats' => 'orders/orders_count,downloads/download_count,test/bogus_stat,jetpack/stats/views',
|
||||
)
|
||||
);
|
||||
$response = $this->server->dispatch( $request );
|
||||
$reports = $response->get_data();
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
$this->assertEquals( 2, count( $reports ) );
|
||||
$this->assertEquals( 3, count( $reports ) );
|
||||
|
||||
$this->assertEquals( 'orders/orders_count', $reports[0]['stat'] );
|
||||
$this->assertEquals( 'Orders', $reports[0]['label'] );
|
||||
|
@ -112,13 +117,18 @@ class WC_Tests_API_Reports_Performance_Indicators extends WC_REST_Unit_Test_Case
|
|||
$this->assertEquals( 2, $reports[1]['value'] );
|
||||
$this->assertEquals( 'download_count', $reports[1]['chart'] );
|
||||
$this->assertEquals( '/analytics/downloads', $response->data[1]['_links']['report'][0]['href'] );
|
||||
|
||||
$this->assertEquals( 'jetpack/stats/views', $reports[2]['stat'] );
|
||||
$this->assertEquals( 'Views', $reports[2]['label'] );
|
||||
$this->assertEquals( 10, $reports[2]['value'] );
|
||||
$this->assertEquals( 'views', $reports[2]['chart'] );
|
||||
$this->assertEquals( get_rest_url( null, '/jetpack/v4/module/stats/data' ), $response->data[2]['_links']['api'][0]['href'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting indicators with an empty request.
|
||||
*/
|
||||
public function test_get_indicators_empty_request() {
|
||||
global $wpdb;
|
||||
wp_set_current_user( $this->user );
|
||||
WC_Helper_Reports::reset_stats_dbs();
|
||||
|
||||
|
@ -126,8 +136,8 @@ class WC_Tests_API_Reports_Performance_Indicators extends WC_REST_Unit_Test_Case
|
|||
$request = new WP_REST_Request( 'GET', $this->endpoint );
|
||||
$request->set_query_params(
|
||||
array(
|
||||
'before' => date( 'Y-m-d 23:59:59', $time ),
|
||||
'after' => date( 'Y-m-d H:00:00', $time - ( 7 * DAY_IN_SECONDS ) ),
|
||||
'before' => gmdate( 'Y-m-d 23:59:59', $time ),
|
||||
'after' => gmdate( 'Y-m-d H:00:00', $time - ( 7 * DAY_IN_SECONDS ) ),
|
||||
)
|
||||
);
|
||||
$response = $this->server->dispatch( $request );
|
||||
|
@ -180,4 +190,146 @@ class WC_Tests_API_Reports_Performance_Indicators extends WC_REST_Unit_Test_Case
|
|||
$this->assertArrayHasKey( 'chart', $properties );
|
||||
$this->assertArrayHasKey( 'label', $properties );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the ability to aggregate Jetpack stats based on before and after dates.
|
||||
*/
|
||||
public function test_jetpack_stats_query_args() {
|
||||
wp_set_current_user( $this->user );
|
||||
|
||||
$request = new WP_REST_Request( 'GET', $this->endpoint );
|
||||
$request->set_query_params(
|
||||
array(
|
||||
'before' => '2020-01-05 23:59:59',
|
||||
'after' => '2020-01-01 00:00:00',
|
||||
'stats' => 'jetpack/stats/views',
|
||||
)
|
||||
);
|
||||
$response = $this->server->dispatch( $request );
|
||||
$reports = $response->get_data();
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
$this->assertEquals( 1, count( $reports ) );
|
||||
|
||||
$this->assertEquals( 'jetpack/stats/views', $reports[0]['stat'] );
|
||||
$this->assertEquals( 'Views', $reports[0]['label'] );
|
||||
$this->assertEquals( 18, $reports[0]['value'] );
|
||||
$this->assertEquals( 'views', $reports[0]['chart'] );
|
||||
$this->assertEquals( get_rest_url( null, '/jetpack/v4/module/stats/data' ), $response->data[0]['_links']['api'][0]['href'] );
|
||||
|
||||
$request = new WP_REST_Request( 'GET', $this->endpoint );
|
||||
$request->set_query_params(
|
||||
array(
|
||||
'before' => '2020-01-02 23:59:59',
|
||||
'after' => '2020-01-01 00:00:00',
|
||||
'stats' => 'jetpack/stats/views',
|
||||
)
|
||||
);
|
||||
$response = $this->server->dispatch( $request );
|
||||
$reports = $response->get_data();
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
$this->assertEquals( 1, count( $reports ) );
|
||||
|
||||
$this->assertEquals( 'jetpack/stats/views', $reports[0]['stat'] );
|
||||
$this->assertEquals( 'Views', $reports[0]['label'] );
|
||||
$this->assertEquals( 4, $reports[0]['value'] );
|
||||
$this->assertEquals( 'views', $reports[0]['chart'] );
|
||||
$this->assertEquals( get_rest_url( null, '/jetpack/v4/module/stats/data' ), $response->data[0]['_links']['api'][0]['href'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the ability to aggregate Jetpack stats based on default arguments.
|
||||
*/
|
||||
public function test_jetpack_stats_default_query_args() {
|
||||
wp_set_current_user( $this->user );
|
||||
|
||||
$request = new WP_REST_Request( 'GET', $this->endpoint );
|
||||
$request->set_query_params(
|
||||
array(
|
||||
'stats' => 'jetpack/stats/views',
|
||||
)
|
||||
);
|
||||
$response = $this->server->dispatch( $request );
|
||||
$reports = $response->get_data();
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
$this->assertEquals( 1, count( $reports ) );
|
||||
|
||||
$this->assertEquals( 'jetpack/stats/views', $reports[0]['stat'] );
|
||||
$this->assertEquals( 'Views', $reports[0]['label'] );
|
||||
$this->assertEquals( 10, $reports[0]['value'] );
|
||||
$this->assertEquals( 'views', $reports[0]['chart'] );
|
||||
$this->assertEquals( get_rest_url( null, '/jetpack/v4/module/stats/data' ), $response->data[0]['_links']['api'][0]['href'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock the Jetpack REST API responses since we're not really connected.
|
||||
*
|
||||
* @param WP_Rest_Response $response Response from the server.
|
||||
* @param WP_Rest_Server $rest_server WP Rest Server.
|
||||
* @param WP_REST_Request $request Request made to the server.
|
||||
*
|
||||
* @return WP_Rest_Response
|
||||
*/
|
||||
public function mock_rest_responses( $response, $rest_server, $request ) {
|
||||
if ( 'GET' === $request->get_method() && '/jetpack/v4/module/all' === $request->get_route() ) {
|
||||
$response->set_status( 200 );
|
||||
$response->set_data(
|
||||
array(
|
||||
'stats' => array(
|
||||
'activated' => 1,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( 'GET' === $request->get_method() && '/jetpack/v4/module/stats/data' === $request->get_route() ) {
|
||||
$general = new \stdClass();
|
||||
$general->visits = new \stdClass();
|
||||
$general->visits->fields = array(
|
||||
'date',
|
||||
'views',
|
||||
'visits',
|
||||
);
|
||||
$general->visits->data = array(
|
||||
array(
|
||||
'2020-01-01',
|
||||
1,
|
||||
0,
|
||||
),
|
||||
array(
|
||||
'2020-01-02',
|
||||
3,
|
||||
0,
|
||||
),
|
||||
array(
|
||||
'2020-01-03',
|
||||
1,
|
||||
0,
|
||||
),
|
||||
array(
|
||||
'2020-01-04',
|
||||
8,
|
||||
0,
|
||||
),
|
||||
array(
|
||||
'2020-01-05',
|
||||
5,
|
||||
0,
|
||||
),
|
||||
array(
|
||||
gmdate( 'Y-m-d' ),
|
||||
10,
|
||||
0,
|
||||
),
|
||||
);
|
||||
$response->set_status( 200 );
|
||||
$response->set_data(
|
||||
array( 'general' => $general )
|
||||
);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue