Skip to content
This repository has been archived by the owner on Jun 7, 2022. It is now read-only.

Commit

Permalink
Add label and generated report URL to the performance indicator respo…
Browse files Browse the repository at this point in the history
…nse.
  • Loading branch information
justinshreve committed Jan 17, 2019
1 parent 025cf81 commit dbdcbcb
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 47 deletions.
42 changes: 41 additions & 1 deletion includes/api/class-wc-admin-rest-reports-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public function get_items_permissions_check( $request ) {
return true;
}


/**
* Get all reports.
*
Expand Down Expand Up @@ -135,7 +136,36 @@ public function get_items( $request ) {
),
);

/**
* Filter the list of allowed reports, so that data can be loaded from third party extensions in addition to WooCommerce core.
* Array items should be in format of array( 'slug' => 'downloads/stats', 'description' => '',
* 'url' => '', and 'path' => '/wc-ext/v1/...'.
*
* @param array $endpoints The list of allowed reports..
*/
$reports = apply_filters( 'woocommerce_admin_reports', $reports );

foreach ( $reports as $report ) {
if ( empty( $report['slug'] ) ) {
continue;
}

if ( empty( $report['path'] ) ) {
$report['path'] = '/' . $this->namespace . '/reports/' . $report['slug'];
}

// Allows a different admin page to be loaded here,
// or allows an empty url if no report exists for a set of performance indicators.
if ( ! isset( $report['url'] ) ) {
if ( '/stats' === substr( $report['slug'], -6 ) ) {
$url_slug = substr( $report['slug'], 0, -6 );
} else {
$url_slug = $report['slug'];
}

$report['url'] = admin_url( 'admin.php?page=wc-admin#/' . $url_slug );
}

$item = $this->prepare_item_for_response( (object) $report, $request );
$data[] = $this->prepare_response_for_collection( $item );
}
Expand All @@ -154,6 +184,7 @@ public function prepare_item_for_response( $report, $request ) {
$data = array(
'slug' => $report->slug,
'description' => $report->description,
'path' => $report->path,
);

$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
Expand All @@ -165,7 +196,10 @@ public function prepare_item_for_response( $report, $request ) {
$response->add_links(
array(
'self' => array(
'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $report->slug ) ),
'href' => rest_url( $report->path ),
),
'report' => array(
'href' => $report->url,
),
'collection' => array(
'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
Expand Down Expand Up @@ -208,6 +242,12 @@ public function get_item_schema() {
'context' => array( 'view' ),
'readonly' => true,
),
'path' => array(
'description' => __( 'API path.', 'wc-admin' ),
'type' => 'string',
'context' => array( 'view' ),
'readonly' => true,
),
),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,34 @@ class WC_Admin_REST_Reports_Performance_Indicators_Controller extends WC_REST_Re
*/
protected $rest_base = 'reports/performance-indicators';

/**
* Contains a list of endpoints by report slug.
*
* @var array
*/
protected $endpoints = array();

/**
* Contains a list of allowed stats.
*
* @var array
*/
protected $allowed_stats = array();

/**
* Contains a list of stat labels.
*
* @var array
*/
protected $labels = array();

/**
* Contains a list of endpoints by url.
*
* @var array
*/
protected $urls = array();

/**
* Maps query arguments from the REST request.
*
Expand All @@ -46,44 +74,53 @@ protected function prepare_reports_query( $request ) {
}

/**
* Get all allowed stats that can be returned from this endpoint.
* Get information such as allowed stats, stat labels, and endpoint data from stats reports.
*
* @return array
* @return WP_Error|True
*/
public function get_allowed_stats() {
private function get_indicator_data() {
global $wp_rest_server;

// Data already retrieved.
if ( ! empty( $this->endpoints ) && ! empty( $this->labels ) && ! empty( $this->allowed_stats ) ) {
return true;
}

$request = new WP_REST_Request( 'GET', '/wc/v3/reports' );
$response = rest_do_request( $request );
$endpoints = $response->get_data();
$allowed_stats = array();

if ( 200 !== $response->get_status() ) {
return new WP_Error( 'woocommerce_reports_performance_indicators_result_failed', __( 'Sorry, fetching performance indicators failed.', 'wc-admin' ) );
}

foreach ( $endpoints as $endpoint ) {
if ( '/stats' === substr( $endpoint['slug'], -6 ) ) {
$request = new WP_REST_Request( 'OPTIONS', '/wc/v3/reports/' . $endpoint['slug'] );
$request = new WP_REST_Request( 'OPTIONS', $endpoint['path'] );
$response = rest_do_request( $request );
$data = $response->get_data();

$prefix = substr( $endpoint['slug'], 0, -6 );

if ( empty( $data['schema']['properties']['totals']['properties'] ) ) {
continue;
}

foreach ( $data['schema']['properties']['totals']['properties'] as $property_key => $schema_info ) {
$allowed_stats[] = $prefix . '/' . $property_key;
$stat = $prefix . '/' . $property_key;
$allowed_stats[] = $stat;

$this->labels[ $stat ] = $schema_info['description'];
}

$this->endpoints[ $prefix ] = $endpoint['path'];
$this->urls[ $prefix ] = $endpoint['_links']['report'][0]['href'];
}
}

/**
* Filter the list of allowed stats that can be returned via the performance indiciator endpoint.
*
* @param array $allowed_stats The list of allowed stats.
*/
return apply_filters( 'woocommerce_admin_performance_indicators_allowed_stats', $allowed_stats );
$this->allowed_stats = $allowed_stats;
return true;
}

/**
Expand All @@ -93,10 +130,9 @@ public function get_allowed_stats() {
* @return array|WP_Error
*/
public function get_items( $request ) {
$allowed_stats = $this->get_allowed_stats();

if ( is_wp_error( $allowed_stats ) ) {
return $allowed_stats;
$indicator_data = $this->get_indicator_data();
if ( is_wp_error( $indicator_data ) ) {
return $indicator_data;
}

$query_args = $this->prepare_reports_query( $request );
Expand All @@ -105,48 +141,40 @@ public function get_items( $request ) {
}

$stats = array();
foreach ( $query_args['stats'] as $stat_request ) {
foreach ( $query_args['stats'] as $stat ) {
$is_error = false;

$pieces = explode( '/', $stat_request );
$endpoint = $pieces[0];
$stat = $pieces[1];
$pieces = $this->get_stats_parts( $stat );
$report = $pieces[0];
$field = $pieces[1];

if ( ! in_array( $stat_request, $allowed_stats ) ) {
if ( ! in_array( $stat, $this->allowed_stats ) ) {
continue;
}

/**
* Filter the list of allowed endpoints, so that data can be loaded from extensions rather than core.
* These should be in the format of slug => path. Example: `bookings` => `/wc-bookings/v1/reports/bookings/stats`.
*
* @param array $endpoints The list of allowed endpoints.
*/
$stats_endpoints = apply_filters( 'woocommerce_admin_performance_indicators_stats_endpoints', array() );
if ( ! empty( $stats_endpoints [ $endpoint ] ) ) {
$request_url = $stats_endpoints [ $endpoint ];
} else {
$request_url = '/wc/v3/reports/' . $endpoint . '/stats';
}

$request = new WP_REST_Request( 'GET', $request_url );
$request_url = $this->endpoints[ $report ];
$request = new WP_REST_Request( 'GET', $request_url );
$request->set_param( 'before', $query_args['before'] );
$request->set_param( 'after', $query_args['after'] );

$response = rest_do_request( $request );

$data = $response->get_data();
$label = $this->labels[ $stat ];

if ( 200 !== $response->get_status() || empty( $data['totals'][ $stat ] ) ) {
if ( 200 !== $response->get_status() || ! isset( $data['totals'][ $field ] ) ) {
$stats[] = (object) array(
'stat' => $stat_request,
'value' => null,
'stat' => $stat,
'label' => $label,
'value' => null,
);
continue;
}

$stats[] = (object) array(
'stat' => $stat_request,
'value' => $data['totals'][ $stat ],
'stat' => $stat,
'label' => $label,
'value' => $data['totals'][ $field ],
);
}

Expand Down Expand Up @@ -201,25 +229,52 @@ public function prepare_item_for_response( $stat_data, $request ) {
* @return array
*/
protected function prepare_links( $object ) {
$pieces = explode( '/', $object->stat );
$pieces = $this->get_stats_parts( $object->stat );
$endpoint = $pieces[0];
$stat = $pieces[1];
$url = $this->urls[ $endpoint ];

$links = array(
'api' => array(
'href' => rest_url( $this->endpoints[ $endpoint ] ),
),
'report' => array(
'href' => rest_url( sprintf( '/%s/reports/%s/stats', $this->namespace, $endpoint ) ),
'href' => ! empty( $url ) ? $url . '?chart=' . $stat : '',
),
);

return $links;
}

/**
* Returns the endpoint part of a stat request (prefix) and the actual stat total we want.
* To allow extensions to namespace (example: fue/emails/sent), we break on the last forward slash.
*
* @param string $full_stat A stat request string like orders/avg_order_value or fue/emails/sent.
* @return array Containing the prefix (endpoint) and suffix (stat).
*/
private function get_stats_parts( $full_stat ) {
$endpoint = substr( $full_stat, 0, strrpos( $full_stat, '/' ) );
$stat = substr( $full_stat, ( strrpos( $full_stat, '/' ) + 1 ) );
return array(
$endpoint,
$stat,
);
}

/**
* Get the Report's schema, conforming to JSON Schema.
*
* @return array
*/
public function get_item_schema() {
$indicator_data = $this->get_indicator_data();
if ( is_wp_error( $indicator_data ) ) {
$allowed_stats = array();
} else {
$allowed_stats = $this->allowed_stats;
}

$schema = array(
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'report_performance_indicator',
Expand All @@ -230,6 +285,13 @@ public function get_item_schema() {
'type' => 'string',
'context' => array( 'view', 'edit' ),
'readonly' => true,
'enum' => $allowed_stats,
),
'label' => array(
'description' => __( 'Human readable label for the stat.', 'wc-admin' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'value' => array(
'description' => __( 'Value of the stat. Returns null if the stat does not exist or cannot be loaded.', 'wc-admin' ),
Expand All @@ -249,11 +311,11 @@ public function get_item_schema() {
* @return array
*/
public function get_collection_params() {
$allowed_stats = $this->get_allowed_stats();
if ( is_wp_error( $allowed_stats ) ) {
$indicator_data = $this->get_indicator_data();
if ( is_wp_error( $indicator_data ) ) {
$allowed_stats = __( 'There was an issue loading the report endpoints', 'wc-admin' );
} else {
$allowed_stats = implode( ', ', $allowed_stats );
$allowed_stats = implode( ', ', $this->allowed_stats );
}

$params = array();
Expand Down
8 changes: 6 additions & 2 deletions tests/api/reports-performance-indicators.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,17 @@ public function test_get_indicators() {
$reports = $response->get_data();

$this->assertEquals( 200, $response->get_status() );

$this->assertEquals( 2, count( $reports ) );

$this->assertEquals( 'orders/orders_count', $reports[0]['stat'] );
$this->assertEquals( 'Amount of orders', $reports[0]['label'] );
$this->assertEquals( 1, $reports[0]['value'] );
$this->assertEquals( 'http://example.org/wp-admin/admin.php?page=wc-admin#/orders?chart=orders_count', $response->data[0]['_links']['report'][0]['href'] );

$this->assertEquals( 'downloads/download_count', $reports[1]['stat'] );
$this->assertEquals( 'Number of downloads.', $reports[1]['label'] );
$this->assertEquals( 2, $reports[1]['value'] );
$this->assertEquals( 'http://example.org/wp-admin/admin.php?page=wc-admin#/downloads?chart=download_count', $response->data[1]['_links']['report'][0]['href'] );
}

/**
Expand Down Expand Up @@ -148,8 +151,9 @@ public function test_indicators_schema() {
$data = $response->get_data();
$properties = $data['schema']['properties'];

$this->assertEquals( 2, count( $properties ) );
$this->assertEquals( 3, count( $properties ) );
$this->assertArrayHasKey( 'stat', $properties );
$this->assertArrayHasKey( 'label', $properties );
$this->assertArrayHasKey( 'value', $properties );
}
}

0 comments on commit dbdcbcb

Please sign in to comment.