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