PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.1
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.1
16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 All 504 releases
jetpack / jetpack_vendor / automattic / jetpack-premium-analytics / src / widget-availability.php

widget-availability.php in Jetpack – WP Security, Backup, Speed, & Growth 16.3-a.1, at jetpack_vendor/automattic/jetpack-premium-analytics/src/widget-availability.php

201 lines 7.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Widget availability policy (consumer layer): hides developer-only, Simple-only, and
4 * plugin-gated widget types at registry time — a hard hide, so every consumer of the
5 * registry sees the same set, over the neutral hooks in widget-types.php.
6 *
7 * @package automattic/jetpack-premium-analytics
8 */
9
10 namespace Automattic\Jetpack\PremiumAnalytics;
11
12 require_once __DIR__ . '/widget-types.php';
13 require_once __DIR__ . '/widget-type-support.php';
14
15 /**
16 * Widget categories that are only meaningful with WooCommerce active.
17 */
18 const WOOCOMMERCE_WIDGET_CATEGORIES = array( 'store', 'orders', 'coupons' );
19
20 /**
21 * Widget categories that are only meaningful with WooCommerce Bookings active.
22 *
23 * Checked independently of WOOCOMMERCE_WIDGET_CATEGORIES: the Bookings
24 * extension cannot run without WooCommerce, so its presence implies both.
25 */
26 const WOOCOMMERCE_BOOKINGS_WIDGET_CATEGORIES = array( 'bookings' );
27
28 /**
29 * Widget categories whose data counts as a store report — by data source, not subject
30 * matter: each reaches WPCOM via the proxy's `analytics` prefix (gated on
31 * `view_woocommerce_reports`), including `visitors`, which reads `sessions/…` from it.
32 */
33 const STORE_REPORT_WIDGET_CATEGORIES = array( 'store', 'orders', 'coupons', 'bookings', 'visitors' );
34
35 /**
36 * Removes developer-only candidates in production.
37 *
38 * Split from the hook callback so both branches are testable without touching
39 * the global environment.
40 *
41 * @param array $widget_candidates Manifest candidates, each with a `name` and `category`.
42 * @param string $environment Site environment type.
43 * @return array The candidates, minus developer-only types in production.
44 */
45 function remove_dev_only_widget_types( $widget_candidates, $environment ) {
46 if ( 'production' !== $environment ) {
47 return $widget_candidates;
48 }
49
50 return array_values(
51 array_filter(
52 $widget_candidates,
53 static function ( $widget ) {
54 return 'developer' !== ( $widget['category'] ?? '' );
55 }
56 )
57 );
58 }
59
60 /**
61 * Registry-time callback: hides developer-only types in production.
62 *
63 * Defaults to `production`; a site opts in via `WP_ENVIRONMENT_TYPE`
64 * (`local`, `development`, `staging`).
65 *
66 * @param array $widget_candidates Manifest candidates.
67 * @return array The candidates, minus developer-only types in production.
68 */
69 function filter_registrable_widget_types_by_environment( $widget_candidates ) {
70 return remove_dev_only_widget_types( $widget_candidates, wp_get_environment_type() );
71 }
72
73 add_filter( REGISTRABLE_WIDGET_TYPES_FILTER, __NAMESPACE__ . '\\filter_registrable_widget_types_by_environment' );
74
75 /**
76 * Applies shared type-level availability at registry time.
77 *
78 * @param array $widget_candidates Manifest candidates.
79 * @return array Filtered candidates.
80 */
81 function filter_registrable_widget_types_by_availability( $widget_candidates ) {
82 return remove_unsupported_widget_items(
83 $widget_candidates,
84 'name',
85 get_widget_support_context()
86 );
87 }
88
89 add_filter( REGISTRABLE_WIDGET_TYPES_FILTER, __NAMESPACE__ . '\\filter_registrable_widget_types_by_availability' );
90
91 /**
92 * Removes candidates whose commerce category lacks its backing plugin.
93 *
94 * Split from the hook callback so the branches are testable without touching
95 * global plugin state.
96 *
97 * @param array $widget_candidates Manifest candidates, each with a `category`.
98 * @param bool $woocommerce_available Whether WooCommerce is available.
99 * @param bool $bookings_available Whether WooCommerce Bookings is available.
100 * @return array The candidates, minus commerce categories missing their plugin.
101 */
102 function remove_plugin_gated_widget_types( $widget_candidates, $woocommerce_available, $bookings_available ) {
103 return array_values(
104 array_filter(
105 $widget_candidates,
106 static function ( $widget ) use ( $woocommerce_available, $bookings_available ) {
107 $category = $widget['category'] ?? '';
108
109 if ( ! $woocommerce_available && in_array( $category, WOOCOMMERCE_WIDGET_CATEGORIES, true ) ) {
110 return false;
111 }
112
113 if ( ! $bookings_available && in_array( $category, WOOCOMMERCE_BOOKINGS_WIDGET_CATEGORIES, true ) ) {
114 return false;
115 }
116
117 return true;
118 }
119 )
120 );
121 }
122
123 /**
124 * Whether the WooCommerce Bookings extension is active.
125 *
126 * Mirrors the detection in woocommerce-analytics' Bookings sync module;
127 * `is_plugin_active()` only exists in admin contexts, hence the guard.
128 *
129 * @return bool Whether WooCommerce Bookings was detected in the current request.
130 */
131 function is_bookings_plugin_active() {
132 return class_exists( 'WC_Bookings' )
133 || ( function_exists( 'is_plugin_active' ) && \is_plugin_active( 'woocommerce-bookings/woocommerce-bookings.php' ) );
134 }
135
136 /**
137 * Registry-time callback: hides commerce categories without their plugin, reading
138 * WooCommerce availability through the store section's signal so section and widgets
139 * agree; both entry points load dashboard-sections.php before the registry hydrates.
140 *
141 * @param array $widget_candidates Manifest candidates.
142 * @return array The candidates, minus commerce categories missing their plugin.
143 */
144 function filter_registrable_widget_types_by_plugin( $widget_candidates ) {
145 return remove_plugin_gated_widget_types(
146 $widget_candidates,
147 is_woocommerce_dashboard_section_available(),
148 is_bookings_plugin_active()
149 );
150 }
151
152 add_filter( REGISTRABLE_WIDGET_TYPES_FILTER, __NAMESPACE__ . '\\filter_registrable_widget_types_by_plugin' );
153
154 // Subscriber widgets stay registered even when their section is hidden: their data
155 // doesn't depend on the local module, and unregistering would break instances placed elsewhere.
156
157 /**
158 * Removes candidates the reader could not load data for anyway.
159 *
160 * Split from the hook callback so both branches are testable without a user.
161 *
162 * @since 0.1.0
163 *
164 * @param array $widget_candidates Manifest candidates, each with a `category`.
165 * @param bool $can_view_store_reports Whether the reader may see the store reports.
166 * @return array The candidates, minus the store-report categories for readers who can't.
167 */
168 function remove_capability_gated_widget_types( $widget_candidates, $can_view_store_reports ) {
169 if ( $can_view_store_reports ) {
170 return $widget_candidates;
171 }
172
173 return array_values(
174 array_filter(
175 $widget_candidates,
176 static function ( $widget ) {
177 return ! in_array( $widget['category'] ?? '', STORE_REPORT_WIDGET_CATEGORIES, true );
178 }
179 )
180 );
181 }
182
183 /**
184 * Registry-time callback: hides widgets whose data the reader cannot fetch — a
185 * `view_stats` reader would only collect 403s from the proxy's `analytics` prefix.
186 * The registry is request-scoped, so filtering on the current user is safe here.
187 *
188 * @since 0.1.0
189 *
190 * @param array $widget_candidates Manifest candidates.
191 * @return array The candidates, minus the store-report categories for readers who can't see them.
192 */
193 function filter_registrable_widget_types_by_capability( $widget_candidates ) {
194 return remove_capability_gated_widget_types(
195 $widget_candidates,
196 Capabilities::current_user_can_view_store_reports()
197 );
198 }
199
200 add_filter( REGISTRABLE_WIDGET_TYPES_FILTER, __NAMESPACE__ . '\\filter_registrable_widget_types_by_capability' );
201