Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
REST_Purchases
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
3 / 3
6
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 permissions_callback
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
 get_site_current_purchases
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
3 * Sets up the Purchases REST API endpoints.
4 *
5 * @package automattic/my-jetpack
6 */
7
8namespace Automattic\Jetpack\My_Jetpack;
9
10use Automattic\Jetpack\Connection\Manager as Connection_Manager;
11use Automattic\Jetpack\Status\Host as Status_Host;
12use WP_Error;
13
14/**
15 * Registers the REST routes for Purchases.
16 *
17 * @phan-constructor-used-for-side-effects
18 */
19class REST_Purchases {
20    /**
21     * Constructor.
22     */
23    public function __construct() {
24        $route_args = array(
25            'methods'             => \WP_REST_Server::READABLE,
26            'callback'            => __CLASS__ . '::get_site_current_purchases',
27            'permission_callback' => __CLASS__ . '::permissions_callback',
28        );
29
30        /*
31         * The cross-platform route.
32         *
33         * `my-jetpack/v1` is not an available namespace on WordPress.com Simple, so the My Jetpack
34         * UI cannot call it everywhere. `wpcom/v2` is registered on Simple, Atomic and self-hosted
35         * Jetpack sites alike, which lets the UI request one path regardless of platform.
36         */
37        register_rest_route( 'wpcom/v2', 'my-jetpack/purchases', $route_args );
38
39        /*
40         * The original route, retained for backwards compatibility with any existing consumer.
41         * It is not available on Simple and the My Jetpack UI no longer calls it; both routes
42         * return the same data.
43         */
44        register_rest_route( 'my-jetpack/v1', '/site/purchases', $route_args );
45    }
46
47    /**
48     * Check user capability to access the endpoint.
49     *
50     * @access public
51     * @static
52     *
53     * @return true|WP_Error
54     */
55    public static function permissions_callback() {
56        // Simple sites hold this data locally and have no blog token to sign a request with, so
57        // the connection check would always fail there.
58        $is_wpcom_simple = ( new Status_Host() )->is_wpcom_simple();
59
60        if ( ! $is_wpcom_simple && ! ( new Connection_Manager() )->is_connected() ) {
61            return new WP_Error(
62                'not_connected',
63                __( 'Your site is not connected to Jetpack.', 'jetpack-my-jetpack' ),
64                array(
65                    'status' => 400,
66                )
67            );
68        }
69
70        return current_user_can( 'edit_posts' );
71    }
72
73    /**
74     * Site purchases endpoint.
75     *
76     * Delegates to Wpcom_Products so every caller shares one code path. That helper is what serves
77     * the data locally on WordPress.com Simple - where there is no blog token to sign a request to
78     * WordPress.com with - instead of fetching it.
79     *
80     * @return \WP_REST_Response|WP_Error of site purchases.
81     */
82    public static function get_site_current_purchases() {
83        $purchases = Wpcom_Products::get_site_current_purchases();
84
85        if ( is_wp_error( $purchases ) ) {
86            return new WP_Error( 'site_data_fetch_failed', 'Site data fetch failed', array( 'status' => 400 ) );
87        }
88
89        return rest_ensure_response( $purchases );
90    }
91}