Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.92% covered (success)
92.92%
105 / 113
100.00% covered (success)
100.00%
11 / 11
CRAP
n/a
0 / 0
Automattic\Jetpack\PremiumAnalytics\register_single_report_page
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
Automattic\Jetpack\PremiumAnalytics\get_registered_single_report_page
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
Automattic\Jetpack\PremiumAnalytics\get_available_single_report_pages
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
Automattic\Jetpack\PremiumAnalytics\get_available_single_report_page_records
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
Automattic\Jetpack\PremiumAnalytics\configure_single_report_pages_script_data
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
Automattic\Jetpack\PremiumAnalytics\inject_single_report_pages_script_data
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
5
Automattic\Jetpack\PremiumAnalytics\check_single_report_pages_permission
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
Automattic\Jetpack\PremiumAnalytics\get_single_report_page_controls_schema
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
1
Automattic\Jetpack\PremiumAnalytics\get_single_report_page_schema
100.00% covered (success)
100.00%
37 / 37
100.00% covered (success)
100.00%
1 / 1
1
Automattic\Jetpack\PremiumAnalytics\get_single_report_pages_response
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
Automattic\Jetpack\PremiumAnalytics\register_single_report_pages_rest_routes
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * Single-report page API: registry helpers, the default-layout filter and the script data.
4 *
5 * The package's own pages register through this API from default-single-report-pages.php,
6 * the way other plugins do.
7 *
8 * @package automattic/jetpack-premium-analytics
9 */
10
11namespace Automattic\Jetpack\PremiumAnalytics;
12
13require_once __DIR__ . '/dashboard-grammar.php';
14require_once __DIR__ . '/class-single-report-page.php';
15require_once __DIR__ . '/class-single-report-page-registry.php';
16require_once __DIR__ . '/dashboard-layout.php';
17// A page icon is a widget icon: the same registered-name grammar, the same sanitizer.
18require_once __DIR__ . '/widget-types.php';
19require_once __DIR__ . '/rest-namespace.php';
20
21/**
22 * Filter run over a single-report page's default layout, with the page id, the inner section slug and the page.
23 */
24const SINGLE_REPORT_PAGE_DEFAULT_LAYOUT_FILTER = 'jetpack_premium_analytics_single_report_page_default_layout';
25
26// The same policies a section's default layout gets: former names resolved, then unsupported types dropped.
27add_filter( SINGLE_REPORT_PAGE_DEFAULT_LAYOUT_FILTER, __NAMESPACE__ . '\\resolve_former_widget_types_in_default_layout', 99 );
28add_filter( SINGLE_REPORT_PAGE_DEFAULT_LAYOUT_FILTER, __NAMESPACE__ . '\\remove_unsupported_default_layout_items', 100 );
29
30/**
31 * Registers a single-report page.
32 *
33 * @since 0.16.0
34 *
35 * @param string $dashboard_name Dashboard identifier.
36 * @param string $id             Page identifier, namespaced.
37 * @param array  $args           Optional. Page arguments.
38 * @return Single_Report_Page|false The registered page on success, or false on failure.
39 */
40function register_single_report_page( $dashboard_name, $id, $args = array() ) {
41    return Single_Report_Page_Registry::get_instance()->register( $dashboard_name, $id, $args );
42}
43
44/**
45 * A registered single-report page.
46 *
47 * @since 0.16.0
48 *
49 * @param string $dashboard_name Dashboard identifier.
50 * @param string $id             Page identifier.
51 * @return Single_Report_Page|null
52 */
53function get_registered_single_report_page( $dashboard_name, $id ) {
54    return Single_Report_Page_Registry::get_instance()->get_registered( $dashboard_name, $id );
55}
56
57/**
58 * The single-report pages available to the current reader.
59 *
60 * @since 0.16.0
61 *
62 * @param string $dashboard_name Dashboard identifier.
63 * @return Single_Report_Page[]
64 */
65function get_available_single_report_pages( $dashboard_name ) {
66    return Single_Report_Page_Registry::get_instance()->get_available_pages( $dashboard_name );
67}
68
69/**
70 * The records of the available pages of the dashboard, or null while nothing is registered.
71 *
72 * @return array[]|null
73 */
74function get_available_single_report_page_records() {
75    $registry = Single_Report_Page_Registry::get_instance();
76
77    if ( empty( $registry->get_all_registered( DASHBOARD_NAME ) ) ) {
78        return null;
79    }
80
81    return array_map(
82        static function ( Single_Report_Page $page ) {
83            return $page->to_array();
84        },
85        $registry->get_available_pages( DASHBOARD_NAME )
86    );
87}
88
89/**
90 * Publishes the available pages to the client.
91 */
92function configure_single_report_pages_script_data() {
93    add_filter( 'jetpack_admin_js_script_data', __NAMESPACE__ . '\\inject_single_report_pages_script_data', 20 );
94}
95
96/**
97 * Adds `premium_analytics.single_report_pages` to the dashboard's script data; other admin screens get nothing.
98 *
99 * @param array $data Script data.
100 * @return array
101 */
102function inject_single_report_pages_script_data( array $data ): array {
103    if ( ! Analytics::is_dashboard_request() ) {
104        return $data;
105    }
106
107    if ( ! isset( $data['premium_analytics'] ) || ! is_array( $data['premium_analytics'] ) ) {
108        $data['premium_analytics'] = array();
109    }
110
111    $pages = get_available_single_report_page_records();
112
113    if ( null !== $pages ) {
114        $data['premium_analytics']['single_report_pages'] = $pages;
115    }
116
117    return $data;
118}
119
120/**
121 * Permission callback of the single-report pages route: the dashboard capability.
122 *
123 * @return bool
124 */
125function check_single_report_pages_permission() {
126    return Capabilities::current_user_can_view_analytics();
127}
128
129/**
130 * The REST schema of a page's or a section's controls: DataViews field declarations.
131 *
132 * @return array
133 */
134function get_single_report_page_controls_schema() {
135    return array(
136        'type'  => array( 'array', 'null' ),
137        'items' => array(
138            'type'       => 'object',
139            'properties' => array(
140                'id'       => array( 'type' => 'string' ),
141                'type'     => array( 'type' => 'string' ),
142                'label'    => array( 'type' => 'string' ),
143                'elements' => array(
144                    'type'  => 'array',
145                    'items' => array(
146                        'type'       => 'object',
147                        'properties' => array(
148                            'value' => array( 'type' => array( 'string', 'number', 'boolean', 'null' ) ),
149                            'label' => array( 'type' => 'string' ),
150                        ),
151                    ),
152                ),
153            ),
154        ),
155    );
156}
157
158/**
159 * The REST schema of a single-report page record.
160 *
161 * @return array
162 */
163function get_single_report_page_schema() {
164    return array(
165        '$schema'    => 'http://json-schema.org/draft-04/schema#',
166        'title'      => 'jetpack-premium-analytics-single-report-page',
167        'type'       => 'object',
168        'properties' => array(
169            'id'                => array( 'type' => 'string' ),
170            'path'              => array( 'type' => 'string' ),
171            'label'             => array( 'type' => 'string' ),
172            'dashboard_section' => array( 'type' => array( 'string', 'null' ) ),
173            'feature'           => array( 'type' => array( 'string', 'null' ) ),
174            'scope_param'       => array( 'type' => 'string' ),
175            'id_pattern'        => array( 'type' => 'string' ),
176            'icon'              => array( 'type' => array( 'string', 'null' ) ),
177            'controls'          => get_single_report_page_controls_schema(),
178            'reports_page'      => array( 'type' => array( 'string', 'null' ) ),
179            'preferences_scope' => array( 'type' => 'string' ),
180            'default_layout'    => array(
181                'type'  => 'array',
182                'items' => array( 'type' => 'object' ),
183            ),
184            'sections'          => array(
185                'type'  => 'array',
186                'items' => array(
187                    'type'       => 'object',
188                    'properties' => array(
189                        'slug'           => array( 'type' => 'string' ),
190                        'label'          => array( 'type' => 'string' ),
191                        'default_layout' => array(
192                            'type'  => 'array',
193                            'items' => array( 'type' => 'object' ),
194                        ),
195                        'controls'       => get_single_report_page_controls_schema(),
196                    ),
197                ),
198            ),
199        ),
200    );
201}
202
203/**
204 * The single-report pages available to the reader, for `GET â€¦/dashboards/{name}/single-report-pages`.
205 *
206 * @param \WP_REST_Request $request The request.
207 * @return \WP_REST_Response
208 */
209function get_single_report_pages_response( $request ) {
210    $pages = array_map(
211        static function ( Single_Report_Page $page ) {
212            return $page->to_array();
213        },
214        get_available_single_report_pages( $request['name'] )
215    );
216
217    return rest_ensure_response( $pages );
218}
219
220/**
221 * Registers the single-report pages route under the dashboard REST namespace.
222 */
223function register_single_report_pages_rest_routes() {
224    register_rest_route(
225        DASHBOARD_REST_NAMESPACE,
226        '/dashboards/(?P<name>' . get_dashboard_name_pattern() . ')/single-report-pages',
227        array(
228            array(
229                // @phan-suppress-next-line PhanPluginMixedKeyNoKey -- register_rest_route()'s own signature mixes a numerically keyed endpoint list with a route-level `schema` key.
230                'methods'             => \WP_REST_Server::READABLE,
231                'callback'            => __NAMESPACE__ . '\\get_single_report_pages_response',
232                'permission_callback' => __NAMESPACE__ . '\\check_single_report_pages_permission',
233                'args'                => array(
234                    'name' => array(
235                        'description' => __( 'Dashboard identifier as produced by the build pipeline.', 'jetpack-premium-analytics-pkg' ),
236                        'type'        => 'string',
237                    ),
238                ),
239            ),
240            'schema' => __NAMESPACE__ . '\\get_single_report_page_schema',
241        )
242    );
243}