PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 13.9.2
Jetpack – WP Security, Backup, Speed, & Growth v13.9.2
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 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 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 / class.jetpack-admin.php
jetpack Last commit date
3rd-party 1 year ago _inc 1 year ago css 1 year ago extensions 1 year ago images 1 year ago jetpack_vendor 1 day ago json-endpoints 1 year ago modules 1 year ago sal 1 year ago src 1 year ago vendor 1 year ago views 2 years ago CHANGELOG.md 1 year ago LICENSE.txt 5 years ago SECURITY.md 2 years ago class-jetpack-connection-status.php 2 years ago class-jetpack-gallery-settings.php 3 years ago class-jetpack-pre-connection-jitms.php 2 years ago class-jetpack-stats-dashboard-widget.php 2 years ago class-jetpack-xmlrpc-methods.php 1 year ago class.frame-nonce-preview.php 4 years ago class.jetpack-admin.php 1 year ago class.jetpack-affiliate.php 2 years ago class.jetpack-autoupdate.php 2 years ago class.jetpack-bbpress-json-api.compat.php 2 years ago class.jetpack-cli.php 1 year ago class.jetpack-client-server.php 2 years ago class.jetpack-gutenberg.php 1 year ago class.jetpack-heartbeat.php 2 years ago class.jetpack-modules-list-table.php 2 years ago class.jetpack-network-sites-list-table.php 2 years ago class.jetpack-network.php 2 years ago class.jetpack-plan.php 3 years ago class.jetpack-post-images.php 2 years ago class.jetpack-twitter-cards.php 2 years ago class.jetpack-user-agent.php 2 years ago class.jetpack.php 1 year ago class.json-api-endpoints.php 2 years ago class.json-api.php 2 years ago class.photon.php 3 years ago composer.json 1 year ago enhanced-open-graph.php 3 years ago functions.compat.php 2 years ago functions.cookies.php 2 years ago functions.global.php 2 years ago functions.is-mobile.php 2 years ago functions.opengraph.php 2 years ago functions.photon.php 2 years ago global.d.ts 2 years ago jetpack.php 1 day ago json-api-config.php 3 years ago json-endpoints.php 2 years ago load-jetpack.php 2 years ago locales.php 4 years ago readme.txt 1 day ago uninstall.php 2 years ago wpml-config.xml 4 years ago
class.jetpack-admin.php
585 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 /**
3 * Build the Jetpack admin menu as a whole.
4 *
5 * @package automattic/jetpack
6 */
7
8 use Automattic\Jetpack\Admin_UI\Admin_Menu;
9 use Automattic\Jetpack\Current_Plan as Jetpack_Plan;
10 use Automattic\Jetpack\Partner_Coupon as Jetpack_Partner_Coupon;
11 use Automattic\Jetpack\Status;
12 use Automattic\Jetpack\Status\Host;
13
14 /**
15 * Build the Jetpack admin menu as a whole.
16 */
17 class Jetpack_Admin {
18
19 /**
20 * Static instance.
21 *
22 * @var Jetpack_Admin
23 */
24 private static $instance = null;
25
26 /**
27 * Initialize and fetch the static instance.
28 *
29 * @return self
30 */
31 public static function init() {
32 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
33 if ( isset( $_GET['page'] ) && 'jetpack' === $_GET['page'] ) {
34 add_filter( 'nocache_headers', array( 'Jetpack_Admin', 'add_no_store_header' ), 100 );
35 }
36
37 if ( self::$instance === null ) {
38 self::$instance = new Jetpack_Admin();
39 }
40 return self::$instance;
41 }
42
43 /**
44 * Filter callback to add `no-store` to the `Cache-Control` header.
45 *
46 * @param array $headers Headers array.
47 * @return array Modified headers array.
48 */
49 public static function add_no_store_header( $headers ) {
50 $headers['Cache-Control'] .= ', no-store';
51 return $headers;
52 }
53
54 /** Constructor. */
55 private function __construct() {
56 require_once JETPACK__PLUGIN_DIR . '_inc/lib/admin-pages/class.jetpack-react-page.php';
57 $jetpack_react = new Jetpack_React_Page();
58
59 require_once JETPACK__PLUGIN_DIR . '_inc/lib/admin-pages/class.jetpack-settings-page.php';
60 $fallback_page = new Jetpack_Settings_Page();
61
62 require_once JETPACK__PLUGIN_DIR . '_inc/lib/admin-pages/class-jetpack-about-page.php';
63 $jetpack_about = new Jetpack_About_Page();
64
65 add_action( 'admin_init', array( $jetpack_react, 'react_redirects' ), 0 );
66 add_action( 'admin_menu', array( $jetpack_react, 'add_actions' ), 998 );
67 add_action( 'admin_menu', array( $jetpack_react, 'remove_jetpack_menu' ), 2000 );
68 add_action( 'jetpack_admin_menu', array( $jetpack_react, 'jetpack_add_dashboard_sub_nav_item' ) );
69 add_action( 'jetpack_admin_menu', array( $jetpack_react, 'jetpack_add_settings_sub_nav_item' ) );
70 add_action( 'jetpack_admin_menu', array( $this, 'admin_menu_debugger' ) );
71 add_action( 'jetpack_admin_menu', array( $fallback_page, 'add_actions' ) );
72 add_action( 'jetpack_admin_menu', array( $jetpack_about, 'add_actions' ) );
73
74 // Add redirect to current page for activation/deactivation of modules.
75 add_action( 'jetpack_pre_activate_module', array( $this, 'fix_redirect' ), 10, 2 );
76 add_action( 'jetpack_pre_deactivate_module', array( $this, 'fix_redirect' ), 10, 2 );
77
78 // Add module bulk actions handler.
79 add_action( 'jetpack_unrecognized_action', array( $this, 'handle_unrecognized_action' ) );
80
81 if ( class_exists( 'Akismet_Admin' ) ) {
82 // If the site has Jetpack Anti-spam, change the Akismet menu label and logo accordingly.
83 $site_products = array_column( Jetpack_Plan::get_products(), 'product_slug' );
84 $has_anti_spam_product = count( array_intersect( array( 'jetpack_anti_spam', 'jetpack_anti_spam_monthly' ), $site_products ) ) > 0;
85
86 if ( Jetpack_Plan::supports( 'akismet' ) || Jetpack_Plan::supports( 'antispam' ) || $has_anti_spam_product ) {
87 // Prevent Akismet from adding a menu item.
88 add_action(
89 'admin_menu',
90 function () {
91 remove_action( 'admin_menu', array( 'Akismet_Admin', 'admin_menu' ), 5 );
92 },
93 4
94 );
95
96 // Add an Anti-spam menu item for Jetpack. This is handled automatically by the Admin_Menu as long as it has been initialized.
97 Admin_Menu::init();
98 }
99 }
100
101 // Ensure an Additional CSS menu item is added to the Appearance menu whenever Jetpack is connected.
102 add_action( 'admin_menu', array( $this, 'additional_css_menu' ) );
103
104 add_filter( 'jetpack_display_jitms_on_screen', array( $this, 'should_display_jitms_on_screen' ), 10, 2 );
105
106 // Register Jetpack partner coupon hooks.
107 Jetpack_Partner_Coupon::register_coupon_admin_hooks( 'jetpack', Jetpack::admin_url() );
108 }
109
110 /**
111 * Handle our Additional CSS menu item and legacy page declaration.
112 *
113 * @since 11.0 . Prior to that, this function was located in custom-css-4.7.php (now custom-css.php).
114 */
115 public static function additional_css_menu() {
116 /*
117 * Custom CSS for the Customizer is deprecated for block themes as of WP 6.1, so we only expose it with a menu
118 * if the site already has existing CSS code.
119 */
120 if ( wp_is_block_theme() ) {
121 $styles = wp_get_custom_css();
122 if ( ! $styles ) {
123 return;
124 }
125 }
126
127 // If the site is a WoA site and the custom-css feature is not available, return.
128 // See https://github.com/Automattic/jetpack/pull/19965 for more on how this menu item is dealt with on WoA sites.
129 if ( ( new Host() )->is_woa_site() && ! ( in_array( 'custom-css', Jetpack::get_available_modules(), true ) ) ) {
130 return;
131 } elseif (
132 class_exists( 'Jetpack' ) && (
133 Jetpack::is_module_active( 'custom-css' ) || // If the Custom CSS module is enabled, add the Additional CSS menu item and link to the Customizer.
134 ( wp_is_block_theme() && ! empty( wp_get_custom_css() ) ) // Do the same if the theme is block-based but has existing custom CSS.
135 )
136 ) {
137 // Add in our legacy page to support old bookmarks and such.
138 add_submenu_page( '', __( 'CSS', 'jetpack' ), __( 'Additional CSS', 'jetpack' ), 'edit_theme_options', 'editcss', array( __CLASS__, 'customizer_redirect' ) );
139
140 // Add in our new page slug that will redirect to the customizer.
141 $hook = add_theme_page( __( 'CSS', 'jetpack' ), __( 'Additional CSS', 'jetpack' ), 'edit_theme_options', 'editcss-customizer-redirect', array( __CLASS__, 'customizer_redirect' ) );
142 add_action( "load-{$hook}", array( __CLASS__, 'customizer_redirect' ) );
143 }
144 }
145
146 /**
147 * Handle the redirect for the customizer. This is necessary because
148 * we can't directly add customizer links to the admin menu.
149 *
150 * @since 11.0 . Prior to that, this function was located in custom-css-4.7.php (now custom-css.php).
151 *
152 * There is a core patch in trac that would make this unnecessary.
153 *
154 * @link https://core.trac.wordpress.org/ticket/39050
155 *
156 * @return never
157 */
158 public static function customizer_redirect() {
159 wp_safe_redirect(
160 self::customizer_link(
161 array(
162 'return_url' => wp_get_referer(),
163 )
164 )
165 );
166 exit;
167 }
168
169 /**
170 * Build the URL to deep link to the Customizer.
171 *
172 * You can modify the return url via $args.
173 *
174 * @since 11.0 in this file. This method is also located in custom-css-4.7.php to cover legacy scenarios.
175 *
176 * @param array $args Array of parameters.
177 * @return string
178 */
179 public static function customizer_link( $args = array() ) {
180 if ( isset( $_SERVER['REQUEST_URI'] ) ) {
181 $args = wp_parse_args(
182 $args,
183 array(
184 'return_url' => rawurlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
185 )
186 );
187 }
188
189 return add_query_arg(
190 array(
191 array(
192 'autofocus' => array(
193 'section' => 'custom_css',
194 ),
195 ),
196 'return' => $args['return_url'],
197 ),
198 admin_url( 'customize.php' )
199 );
200 }
201
202 /**
203 * Sort callback to put modules with `requires_connection` last.
204 *
205 * @param array $module1 Module data.
206 * @param array $module2 Module data.
207 * @return int Indicating the relative ordering of module1 and module2.
208 */
209 public static function sort_requires_connection_last( $module1, $module2 ) {
210 return ( (bool) $module1['requires_connection'] ) <=> ( (bool) $module2['requires_connection'] );
211 }
212
213 /**
214 * Produce JS understandable objects of modules containing information for
215 * presentation like description, name, configuration url, etc.
216 */
217 public function get_modules() {
218 include_once JETPACK__PLUGIN_DIR . 'modules/module-info.php';
219 $available_modules = Jetpack::get_available_modules();
220 $active_modules = Jetpack::get_active_modules();
221 $modules = array();
222 $jetpack_active = Jetpack::is_connection_ready() || ( new Status() )->is_offline_mode();
223 $overrides = Jetpack_Modules_Overrides::instance();
224 foreach ( $available_modules as $module ) {
225 $module_array = Jetpack::get_module( $module );
226 if ( $module_array ) {
227 /**
228 * Filters each module's short description.
229 *
230 * @since 3.0.0
231 *
232 * @param string $module_array['description'] Module description.
233 * @param string $module Module slug.
234 */
235 $short_desc = apply_filters( 'jetpack_short_module_description', $module_array['description'], $module );
236 // Fix: correct multibyte strings truncate with checking for mbstring extension.
237 $short_desc_trunc = ( function_exists( 'mb_strlen' ) )
238 ? ( ( mb_strlen( $short_desc ) > 143 )
239 ? mb_substr( $short_desc, 0, 140 ) . '...'
240 : $short_desc )
241 : ( ( strlen( $short_desc ) > 143 )
242 ? substr( $short_desc, 0, 140 ) . '...'
243 : $short_desc );
244
245 $module_array['module'] = $module;
246
247 $is_available = self::is_module_available( $module_array );
248
249 $module_array['activated'] = ( $jetpack_active ? in_array( $module, $active_modules, true ) : false );
250 $module_array['deactivate_nonce'] = wp_create_nonce( 'jetpack_deactivate-' . $module );
251 $module_array['activate_nonce'] = wp_create_nonce( 'jetpack_activate-' . $module );
252 $module_array['available'] = $is_available;
253 $module_array['unavailable_reason'] = $is_available ? false : self::get_module_unavailable_reason( $module_array );
254 $module_array['short_description'] = $short_desc_trunc;
255 $module_array['configure_url'] = Jetpack::module_configuration_url( $module );
256 $module_array['override'] = $overrides->get_module_override( $module );
257 $module_array['disabled'] = $is_available ? '' : 'disabled="disabled"';
258
259 ob_start();
260 /**
261 * Allow the display of a "Learn More" button.
262 * The dynamic part of the action, $module, is the module slug.
263 *
264 * @since 3.0.0
265 */
266 do_action( 'jetpack_learn_more_button_' . $module );
267 $module_array['learn_more_button'] = ob_get_clean();
268
269 ob_start();
270 /**
271 * Allow the display of information text when Jetpack is connected to WordPress.com.
272 * The dynamic part of the action, $module, is the module slug.
273 *
274 * @since 3.0.0
275 */
276 do_action( 'jetpack_module_more_info_' . $module );
277
278 /**
279 * Filter the long description of a module.
280 *
281 * @since 3.5.0
282 *
283 * @param string ob_get_clean() The module long description.
284 * @param string $module The module name.
285 */
286 $module_array['long_description'] = apply_filters( 'jetpack_long_module_description', ob_get_clean(), $module );
287
288 ob_start();
289 /**
290 * Filter the search terms for a module
291 *
292 * Search terms are typically added to the module headers, under "Additional Search Queries".
293 *
294 * Use syntax:
295 * function jetpack_$module_search_terms( $terms ) {
296 * $terms = _x( 'term 1, term 2', 'search terms', 'jetpack' );
297 * return $terms;
298 * }
299 * add_filter( 'jetpack_search_terms_$module', 'jetpack_$module_search_terms' );
300 *
301 * @since 3.5.0
302 *
303 * @param string The search terms (comma separated).
304 */
305 echo apply_filters( 'jetpack_search_terms_' . $module, $module_array['additional_search_queries'] ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
306 $module_array['search_terms'] = ob_get_clean();
307
308 $module_array['configurable'] = false;
309 if (
310 current_user_can( 'manage_options' ) &&
311 /**
312 * Allow the display of a configuration link in the Jetpack Settings screen.
313 *
314 * @since 3.0.0
315 *
316 * @param string $module Module name.
317 * @param bool false Should the Configure module link be displayed? Default to false.
318 */
319 apply_filters( 'jetpack_module_configurable_' . $module, false )
320 ) {
321 $module_array['configurable'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $module_array['configure_url'] ), __( 'Configure', 'jetpack' ) );
322 }
323
324 $modules[ $module ] = $module_array;
325 }
326 }
327
328 uasort( $modules, array( 'Jetpack', 'sort_modules' ) );
329
330 if ( ! Jetpack::is_connection_ready() ) {
331 uasort( $modules, array( __CLASS__, 'sort_requires_connection_last' ) );
332 }
333
334 return $modules;
335 }
336
337 /**
338 * Check if a module is available.
339 *
340 * @param array $module Module data.
341 */
342 public static function is_module_available( $module ) {
343 if ( ! is_array( $module ) || empty( $module ) ) {
344 return false;
345 }
346
347 /**
348 * We never want to show VaultPress as activatable through Jetpack.
349 */
350 if ( 'vaultpress' === $module['module'] ) {
351 return false;
352 }
353
354 /*
355 * WooCommerce Analytics should only be available
356 * when running WooCommerce 3+
357 */
358 if (
359 'woocommerce-analytics' === $module['module']
360 && (
361 ! class_exists( 'WooCommerce' )
362 || version_compare( WC_VERSION, '3.0', '<' )
363 )
364 ) {
365 return false;
366 }
367
368 /*
369 * In Offline mode, modules that require a site or user
370 * level connection should be unavailable.
371 */
372 if ( ( new Status() )->is_offline_mode() ) {
373 return ! ( $module['requires_connection'] || $module['requires_user_connection'] );
374 }
375
376 /*
377 * Jetpack not connected.
378 */
379 if ( ! Jetpack::is_connection_ready() ) {
380 return false;
381 }
382
383 /*
384 * Jetpack connected at a site level only. Make sure to make
385 * modules that require a user connection unavailable.
386 */
387 if ( ! Jetpack::connection()->has_connected_owner() && $module['requires_user_connection'] ) {
388 return false;
389 }
390
391 return Jetpack_Plan::supports( $module['module'] );
392 }
393
394 /**
395 * Returns why a module is unavailable.
396 *
397 * @param array $module The module.
398 * @return string|false A string stating why the module is not available or false if the module is available.
399 */
400 public static function get_module_unavailable_reason( $module ) {
401 if ( ! is_array( $module ) || empty( $module ) ) {
402 return false;
403 }
404
405 if ( self::is_module_available( $module ) ) {
406 return false;
407 }
408
409 /**
410 * We never want to show VaultPress as activatable through Jetpack so return an empty string.
411 */
412 if ( 'vaultpress' === $module['module'] ) {
413 return '';
414 }
415
416 /*
417 * WooCommerce Analytics should only be available
418 * when running WooCommerce 3+
419 */
420 if (
421 'woocommerce-analytics' === $module['module']
422 && (
423 ! class_exists( 'WooCommerce' )
424 || version_compare( WC_VERSION, '3.0', '<' )
425 )
426 ) {
427 return __( 'Requires WooCommerce 3+ plugin', 'jetpack' );
428 }
429
430 /*
431 * In Offline mode, modules that require a site or user
432 * level connection should be unavailable.
433 */
434 if ( ( new Status() )->is_offline_mode() ) {
435 if ( $module['requires_connection'] || $module['requires_user_connection'] ) {
436 return __( 'Offline mode', 'jetpack' );
437 }
438 }
439
440 /*
441 * Jetpack not connected.
442 */
443 if ( ! Jetpack::is_connection_ready() ) {
444 return __( 'Jetpack is not connected', 'jetpack' );
445 }
446
447 /*
448 * Jetpack connected at a site level only and module requires a user connection.
449 */
450 if ( ! Jetpack::connection()->has_connected_owner() && $module['requires_user_connection'] ) {
451 return __( 'Requires a connected WordPress.com account', 'jetpack' );
452 }
453
454 /*
455 * Plan restrictions.
456 */
457 if ( ! Jetpack_Plan::supports( $module['module'] ) ) {
458 return __( 'Not supported by current plan', 'jetpack' );
459 }
460
461 return '';
462 }
463
464 /**
465 * Handle an unrecognized action.
466 *
467 * @param string $action Action.
468 */
469 public function handle_unrecognized_action( $action ) {
470 switch ( $action ) {
471 case 'bulk-activate':
472 check_admin_referer( 'bulk-jetpack_page_jetpack_modules' );
473 if ( ! current_user_can( 'jetpack_activate_modules' ) ) {
474 break;
475 }
476
477 $modules = isset( $_GET['modules'] ) ? array_map( 'sanitize_key', wp_unslash( (array) $_GET['modules'] ) ) : array();
478 foreach ( $modules as $module ) {
479 Jetpack::log( 'activate', $module );
480 Jetpack::activate_module( $module, false );
481 }
482 // The following two lines will rarely happen, as Jetpack::activate_module normally exits at the end.
483 wp_safe_redirect( wp_get_referer() );
484 exit;
485 case 'bulk-deactivate':
486 check_admin_referer( 'bulk-jetpack_page_jetpack_modules' );
487 if ( ! current_user_can( 'jetpack_deactivate_modules' ) ) {
488 break;
489 }
490
491 $modules = isset( $_GET['modules'] ) ? array_map( 'sanitize_key', wp_unslash( (array) $_GET['modules'] ) ) : array();
492 foreach ( $modules as $module ) {
493 Jetpack::log( 'deactivate', $module );
494 Jetpack::deactivate_module( $module );
495 Jetpack::state( 'message', 'module_deactivated' );
496 }
497 Jetpack::state( 'module', $modules );
498 wp_safe_redirect( wp_get_referer() );
499 exit;
500 default:
501 return;
502 }
503 }
504
505 /**
506 * Fix redirect.
507 *
508 * Apparently we redirect to the referrer instead of whatever WordPress
509 * wants to redirect to when activating and deactivating modules.
510 *
511 * @param string $module Module slug.
512 * @param bool $redirect Should we exit after the module has been activated. Default to true.
513 */
514 public function fix_redirect( $module, $redirect = true ) {
515 if ( ! $redirect ) {
516 return;
517 }
518 if ( wp_get_referer() ) {
519 add_filter( 'wp_redirect', 'wp_get_referer' );
520 }
521 }
522
523 /**
524 * Add debugger admin menu.
525 */
526 public function admin_menu_debugger() {
527 require_once JETPACK__PLUGIN_DIR . '_inc/lib/debugger.php';
528 Jetpack_Debugger::disconnect_and_redirect();
529 $debugger_hook = add_submenu_page(
530 '',
531 __( 'Debugging Center', 'jetpack' ),
532 '',
533 'manage_options',
534 'jetpack-debugger',
535 array( $this, 'wrap_debugger_page' )
536 );
537 add_action( "admin_head-$debugger_hook", array( 'Jetpack_Debugger', 'jetpack_debug_admin_head' ) );
538 }
539
540 /**
541 * Wrap debugger page.
542 */
543 public function wrap_debugger_page() {
544 nocache_headers();
545 if ( ! current_user_can( 'manage_options' ) ) {
546 die( '-1' );
547 }
548 Jetpack_Admin_Page::wrap_ui( array( $this, 'debugger_page' ), array( 'is-wide' => true ) );
549 }
550
551 /**
552 * Display debugger page.
553 */
554 public function debugger_page() {
555 require_once JETPACK__PLUGIN_DIR . '_inc/lib/debugger.php';
556 Jetpack_Debugger::jetpack_debug_display_handler();
557 }
558
559 /**
560 * Determines if JITMs should display on a particular screen.
561 *
562 * @param bool $value The default value of the filter.
563 * @param string $screen_id The ID of the screen being tested for JITM display.
564 *
565 * @return bool True if JITMs should display, false otherwise.
566 */
567 public function should_display_jitms_on_screen( $value, $screen_id ) {
568 // Disable all JITMs on these pages.
569 if (
570 in_array(
571 $screen_id,
572 array(
573 'jetpack_page_akismet-key-config',
574 'admin_page_jetpack_modules',
575 ),
576 true
577 ) ) {
578 return false;
579 }
580
581 return $value;
582 }
583 }
584 Jetpack_Admin::init();
585