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