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