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