Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.10% covered (success)
90.10%
91 / 101
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%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
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%
9 / 9
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 script data.
106 *
107 * @param array $data Script data.
108 * @return array
109 */
110function inject_single_report_pages_script_data( array $data ): array {
111    if ( ! isset( $data['premium_analytics'] ) || ! is_array( $data['premium_analytics'] ) ) {
112        $data['premium_analytics'] = array();
113    }
114
115    $pages = get_available_single_report_page_records();
116
117    if ( null !== $pages ) {
118        $data['premium_analytics']['single_report_pages'] = $pages;
119    }
120
121    return $data;
122}
123
124/**
125 * Permission callback of the single-report pages route: the dashboard capability.
126 *
127 * @return bool
128 */
129function check_single_report_pages_permission() {
130    return Capabilities::current_user_can_view_analytics();
131}
132
133/**
134 * The REST schema of a page's or a section's date controls.
135 *
136 * @return array
137 */
138function get_single_report_page_controls_schema() {
139    return array(
140        'type'       => array( 'object', 'boolean', 'null' ),
141        'properties' => array(
142            'presets' => array(
143                'type'  => 'array',
144                'items' => array( 'type' => 'string' ),
145            ),
146        ),
147    );
148}
149
150/**
151 * The REST schema of a single-report page record.
152 *
153 * @return array
154 */
155function get_single_report_page_schema() {
156    return array(
157        '$schema'    => 'http://json-schema.org/draft-04/schema#',
158        'title'      => 'jetpack-premium-analytics-single-report-page',
159        'type'       => 'object',
160        'properties' => array(
161            'id'                => array( 'type' => 'string' ),
162            'path'              => array( 'type' => 'string' ),
163            'label'             => array( 'type' => 'string' ),
164            'dashboard_section' => array( 'type' => array( 'string', 'null' ) ),
165            'feature'           => array( 'type' => array( 'string', 'null' ) ),
166            'scope_param'       => array( 'type' => 'string' ),
167            'id_pattern'        => array( 'type' => 'string' ),
168            'icon'              => array( 'type' => array( 'string', 'null' ) ),
169            'controls'          => get_single_report_page_controls_schema(),
170            'reports_page'      => array( 'type' => array( 'string', 'null' ) ),
171            'preferences_scope' => array( 'type' => 'string' ),
172            'default_layout'    => array(
173                'type'  => 'array',
174                'items' => array( 'type' => 'object' ),
175            ),
176            'sections'          => array(
177                'type'  => 'array',
178                'items' => array(
179                    'type'       => 'object',
180                    'properties' => array(
181                        'slug'           => array( 'type' => 'string' ),
182                        'label'          => array( 'type' => 'string' ),
183                        'default_layout' => array(
184                            'type'  => 'array',
185                            'items' => array( 'type' => 'object' ),
186                        ),
187                        'controls'       => get_single_report_page_controls_schema(),
188                    ),
189                ),
190            ),
191        ),
192    );
193}
194
195/**
196 * The single-report pages available to the reader, for `GET â€¦/dashboards/{name}/single-report-pages`.
197 *
198 * @param \WP_REST_Request $request The request.
199 * @return \WP_REST_Response
200 */
201function get_single_report_pages_response( $request ) {
202    $pages = array_map(
203        static function ( Single_Report_Page $page ) {
204            return $page->to_array();
205        },
206        get_available_single_report_pages( $request['name'] )
207    );
208
209    return rest_ensure_response( $pages );
210}
211
212/**
213 * Registers the single-report pages route under the dashboard REST namespace.
214 */
215function register_single_report_pages_rest_routes() {
216    register_rest_route(
217        DASHBOARD_REST_NAMESPACE,
218        '/dashboards/(?P<name>' . get_dashboard_name_pattern() . ')/single-report-pages',
219        array(
220            array(
221                // @phan-suppress-next-line PhanPluginMixedKeyNoKey -- register_rest_route()'s own signature mixes a numerically keyed endpoint list with a route-level `schema` key.
222                'methods'             => \WP_REST_Server::READABLE,
223                'callback'            => __NAMESPACE__ . '\\get_single_report_pages_response',
224                'permission_callback' => __NAMESPACE__ . '\\check_single_report_pages_permission',
225                'args'                => array(
226                    'name' => array(
227                        'description' => __( 'Dashboard identifier as produced by the build pipeline.', 'jetpack-premium-analytics-pkg' ),
228                        'type'        => 'string',
229                    ),
230                ),
231            ),
232            'schema' => __NAMESPACE__ . '\\get_single_report_page_schema',
233        )
234    );
235}