PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 16.2-a.1
Jetpack – WP Security, Backup, Speed, & Growth v16.2-a.1
16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / jetpack_vendor / automattic / jetpack-scan-page / src / class-jetpack-scan.php
jetpack / jetpack_vendor / automattic / jetpack-scan-page / src Last commit date
class-initial-state.php 3 months ago class-jetpack-scan.php 2 weeks ago class-package-version.php 2 days ago class-rest-controller.php 3 months ago
class-jetpack-scan.php
266 lines
1 <?php
2 /**
3 * Primary class for the Jetpack Scan package.
4 *
5 * @package automattic/jetpack-scan-page
6 */
7
8 namespace Automattic\Jetpack\Scan_Page;
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit( 0 );
12 }
13
14 use Automattic\Jetpack\Admin_UI\Admin_Menu;
15 use Automattic\Jetpack\Connection\Manager as Connection_Manager;
16 use Automattic\Jetpack\WP_Build_Polyfills\WP_Build_Polyfills;
17 use function add_action;
18 use function add_filter;
19 use function apply_filters;
20 use function call_user_func;
21 use function current_user_can;
22 use function did_action;
23 use function do_action;
24 use function function_exists;
25 use function is_admin;
26 use function is_multisite;
27 use function remove_action;
28 use function remove_all_actions;
29 use function sanitize_text_field;
30 use function wp_unslash;
31
32 /**
33 * Class Jetpack_Scan
34 *
35 * Registers the Scan admin page and its REST routes inside the main
36 * Jetpack plugin. The page bundle is built by `@wordpress/build`
37 * (mirroring Newsletter / Forms); this class wires the wp-admin menu
38 * + the bridges that route our user-facing slug to wp-build's
39 * auto-generated enqueue / render functions.
40 */
41 class Jetpack_Scan {
42
43 /**
44 * URL-facing menu slug.
45 *
46 * @var string
47 */
48 const PAGE_SLUG = 'jetpack-scan';
49
50 /**
51 * Internal slug emitted by `@wordpress/build` (`wpPlugin.pages[0]`
52 * plus the `-wp-admin` suffix the build template appends). Used to
53 * find the auto-generated render / enqueue functions.
54 *
55 * @var string
56 */
57 const WP_BUILD_SLUG = 'jetpack-scan-wp-admin';
58
59 /**
60 * Filter name that gates the wp-build–based Scan dashboard.
61 *
62 * When this filter returns true, the new wp-admin Scan page is
63 * registered and rendered. Default false during the modernization
64 * roll-out — the package registers no admin menu and changes
65 * nothing about the existing Jetpack UI when this filter is off.
66 *
67 * @var string
68 */
69 const MODERNIZATION_FILTER = 'rsm_jetpack_ui_modernization_scan';
70
71 /**
72 * Entry point. Idempotent: safe to call from multiple bootstraps.
73 */
74 public static function initialize() {
75 if ( did_action( 'jetpack_scan_page_initialized' ) ) {
76 return;
77 }
78
79 if ( ! (bool) apply_filters( self::MODERNIZATION_FILTER, false ) ) {
80 return;
81 }
82
83 self::load_wp_build();
84 self::bridge_wp_build_enqueue();
85
86 add_action( 'admin_menu', array( __CLASS__, 'add_wp_admin_submenu' ) );
87 add_action( 'rest_api_init', array( __CLASS__, 'register_rest_routes' ) );
88 add_filter( 'jetpack_package_versions', array( Package_Version::class, 'send_package_version_to_tracker' ) );
89
90 /**
91 * Fires once the Jetpack Scan package has wired its hooks.
92 *
93 * @since 0.1.0
94 */
95 do_action( 'jetpack_scan_page_initialized' );
96 }
97
98 /**
99 * Load wp-build generated registration files. Mirrors Newsletter / Forms.
100 */
101 public static function load_wp_build() {
102 // The polyfills force-replace core script handles (notably
103 // `wp-private-apis`, a stateful singleton shared by every @wordpress
104 // package on the page) during `wp_default_scripts`. Scope registration
105 // to the Scan admin page so it never runs on other admin pages such as
106 // the block editor. `$_GET['page']` is reliable this early — it's the
107 // raw query param, available well before `current_screen` exists.
108 if ( self::is_scan_admin_request() ) {
109 WP_Build_Polyfills::register(
110 'jetpack-scan',
111 array_merge( WP_Build_Polyfills::SCRIPT_HANDLES, WP_Build_Polyfills::MODULE_IDS )
112 );
113 }
114
115 $wp_build_index = dirname( __DIR__ ) . '/build/build.php';
116 if ( file_exists( $wp_build_index ) ) {
117 require_once $wp_build_index;
118 }
119
120 // `page.php` ships an `admin_init` interceptor that takes over our
121 // slug with a standalone (non-wp-admin) render. We want the
122 // wp-admin integrated experience, so unregister it as soon as it's
123 // loaded.
124 remove_action(
125 'admin_init',
126 'jetpack_scan_jetpack_scan_intercept_render'
127 );
128 }
129
130 /**
131 * Whether the current request targets the Scan admin page.
132 *
133 * Used to scope the wp-build polyfill registration (which force-replaces
134 * core script handles) to this one page, so it never affects other admin
135 * pages. Reads the menu page slug directly so it is cheap and safe to call
136 * at plugin-load time, before `current_screen` exists.
137 *
138 * @return bool True when serving the Scan page in wp-admin.
139 */
140 public static function is_scan_admin_request() {
141 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
142 if ( ! is_admin() || ! isset( $_GET['page'] ) ) {
143 return false;
144 }
145
146 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
147 return self::PAGE_SLUG === sanitize_text_field( wp_unslash( $_GET['page'] ) );
148 }
149
150 /**
151 * Bridge wp-build's auto-generated enqueue function — which checks for
152 * `?page=jetpack-scan-wp-admin` — to our user-facing slug
153 * `?page=jetpack-scan`. Hooked at priority 9 so the wp-build copy
154 * (registered at priority 10) sees the original `$_GET['page']` and
155 * skips its own enqueue.
156 */
157 public static function bridge_wp_build_enqueue() {
158 add_action(
159 'admin_enqueue_scripts',
160 static function ( $hook_suffix ) {
161 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
162 if ( ! isset( $_GET['page'] ) || self::PAGE_SLUG !== $_GET['page'] ) {
163 return;
164 }
165
166 $enqueue_fn = 'jetpack_scan_jetpack_scan_wp_admin_enqueue_scripts';
167 if ( ! function_exists( $enqueue_fn ) ) {
168 return;
169 }
170
171 // phpcs:disable WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
172 $original = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : null;
173 $_GET['page'] = self::WP_BUILD_SLUG;
174 // @phan-suppress-next-line PhanUndeclaredFunctionInCallable -- Function is generated by @wordpress/build into build/pages/jetpack-scan/page-wp-admin.php, which is outside Phan's analysis scope. The function_exists() guard above protects the call at runtime.
175 call_user_func( $enqueue_fn, $hook_suffix );
176 if ( null === $original ) {
177 unset( $_GET['page'] );
178 } else {
179 $_GET['page'] = $original;
180 }
181 // phpcs:enable WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
182 },
183 9
184 );
185 }
186
187 /**
188 * Register the Scan submenu under Jetpack.
189 *
190 * @return string|null The resulting page's hook suffix, if registered.
191 */
192 public static function add_wp_admin_submenu() {
193 if ( ! self::is_available() ) {
194 return null;
195 }
196
197 $render_fn = 'jetpack_scan_jetpack_scan_wp_admin_render_page';
198 $render = function_exists( $render_fn )
199 ? $render_fn
200 : array( __CLASS__, 'render_page_fallback' );
201
202 $page_suffix = Admin_Menu::add_menu(
203 /** "Scan" is a product name, do not translate. */
204 'Scan',
205 'Scan',
206 'manage_options',
207 self::PAGE_SLUG,
208 $render,
209 6
210 );
211
212 if ( $page_suffix ) {
213 add_action( 'load-' . $page_suffix, array( __CLASS__, 'admin_init' ) );
214 }
215
216 return $page_suffix;
217 }
218
219 /**
220 * Whether the Scan page should be shown to the current user.
221 *
222 * @return bool
223 */
224 public static function is_available() {
225 if ( is_multisite() ) {
226 return false;
227 }
228
229 if ( ! current_user_can( 'manage_options' ) ) {
230 return false;
231 }
232
233 return ( new Connection_Manager() )->is_user_connected();
234 }
235
236 /**
237 * Fires when the admin page is loaded.
238 *
239 * Silences the standard wp-admin notice channels so JITMs and
240 * plugin-update messages don't reflow the focused Scan layout
241 * mid-scan or while a fix modal is open.
242 */
243 public static function admin_init() {
244 remove_all_actions( 'admin_notices' );
245 remove_all_actions( 'all_admin_notices' );
246 }
247
248 /**
249 * Fallback render — used only if the wp-build registration file
250 * isn't loaded (e.g. the package wasn't built yet). Renders a bare
251 * mount node so the page doesn't 500 in dev.
252 */
253 public static function render_page_fallback() {
254 ?>
255 <div id="jetpack-scan-page-root"></div>
256 <?php
257 }
258
259 /**
260 * Register the REST routes backing the Scan UI.
261 */
262 public static function register_rest_routes() {
263 REST_Controller::register_rest_routes();
264 }
265 }
266