PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.1
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.1
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 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 All 508 releases
← All changes | _inc/lib/admin-pages/class-jetpack-redux-state-helper.php +133 -141 12.1.3 → 16.3-a.1 View file →
@@ -5,12 +5,15 @@
5 5 *
6 6 * @package automattic/jetpack
7 7 */
8 8
9 +use Automattic\Jetpack\Blaze;
10 +use Automattic\Jetpack\Boost_Speed_Score\Speed_Score_History;
9 11 use Automattic\Jetpack\Connection\Manager as Connection_Manager;
10 12 use Automattic\Jetpack\Connection\Plugin_Storage as Connection_Plugin_Storage;
11 13 use Automattic\Jetpack\Connection\REST_Connector;
12 14 use Automattic\Jetpack\Constants;
15 +use Automattic\Jetpack\Current_Plan as Jetpack_Plan;
13 16 use Automattic\Jetpack\Device_Detection\User_Agent_Info;
14 17 use Automattic\Jetpack\Identity_Crisis;
15 18 use Automattic\Jetpack\IP\Utils as IP_Utils;
16 19 use Automattic\Jetpack\Licensing;
@@ -15,10 +18,12 @@
15 18 use Automattic\Jetpack\IP\Utils as IP_Utils;
16 19 use Automattic\Jetpack\Licensing;
17 20 use Automattic\Jetpack\Licensing\Endpoints as Licensing_Endpoints;
18 21 use Automattic\Jetpack\My_Jetpack\Initializer as My_Jetpack_Initializer;
22 +use Automattic\Jetpack\My_Jetpack\Jetpack_Manage;
19 23 use Automattic\Jetpack\Partner;
20 24 use Automattic\Jetpack\Partner_Coupon as Jetpack_Partner_Coupon;
25 +use Automattic\Jetpack\Publicize\Keyring_Helper;
21 26 use Automattic\Jetpack\Stats\Options as Stats_Options;
22 27 use Automattic\Jetpack\Status;
23 28 use Automattic\Jetpack\Status\Host;
24 29
@@ -32,14 +37,10 @@
32 37 * e.g. used by React Disconnect Dialog on plugins page where the full initial state is not needed
33 38 */
34 39 public static function get_minimal_state() {
35 40 return array(
36 - 'pluginBaseUrl' => plugins_url( '', JETPACK__PLUGIN_FILE ),
37 - /* This filter is documented in class.jetpack-connection-banner.php */
38 - 'preConnectionHelpers' => apply_filters( 'jetpack_pre_connection_prompt_helpers', false ),
39 - 'registrationNonce' => wp_create_nonce( 'jetpack-registration-nonce' ),
40 - 'WP_API_root' => esc_url_raw( rest_url() ),
41 - 'WP_API_nonce' => wp_create_nonce( 'wp_rest' ),
41 + 'WP_API_root' => esc_url_raw( rest_url() ),
42 + 'WP_API_nonce' => wp_create_nonce( 'wp_rest' ),
42 43 );
43 44 }
44 45
45 46 /**
@@ -68,8 +69,12 @@
68 69 // "mock" a block module in order to get it searchable in the settings.
69 70 $modules['blocks']['module'] = 'blocks';
70 71 $modules['blocks']['additional_search_queries'] = esc_html_x( 'blocks, block, gutenberg', 'Search terms', 'jetpack' );
71 72
73 + // "mock" an Earn module in order to get it searchable in the settings.
74 + $modules['earn']['module'] = 'earn';
75 + $modules['earn']['additional_search_queries'] = esc_html_x( 'earn, paypal, stripe, payments, pay', 'Search terms', 'jetpack' );
76 +
72 77 // Collecting roles that can view site stats.
73 78 $stats_roles = array();
74 79 $enabled_roles = Stats_Options::get_option( 'roles' );
75 80
@@ -121,31 +126,33 @@
121 126 );
122 127
123 128 $connection_status = array_merge( REST_Connector::connection_status( false ), $connection_status );
124 129
125 - $host = new Host();
130 + $speed_score_history = new Speed_Score_History( wp_parse_url( get_site_url(), PHP_URL_HOST ) );
126 131
132 + $block_availability = Jetpack_Gutenberg::get_cached_availability();
133 +
127 134 return array(
128 - 'WP_API_root' => esc_url_raw( rest_url() ),
129 - 'WP_API_nonce' => wp_create_nonce( 'wp_rest' ),
130 - 'registrationNonce' => wp_create_nonce( 'jetpack-registration-nonce' ),
131 - 'purchaseToken' => self::get_purchase_token(),
132 - 'partnerCoupon' => Jetpack_Partner_Coupon::get_coupon(),
133 - 'pluginBaseUrl' => plugins_url( '', JETPACK__PLUGIN_FILE ),
134 - 'connectionStatus' => $connection_status,
135 - 'connectedPlugins' => Connection_Plugin_Storage::get_all(),
136 - 'connectUrl' => false == $current_user_data['isConnected'] // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual
135 + 'WP_API_root' => esc_url_raw( rest_url() ),
136 + 'WP_API_nonce' => wp_create_nonce( 'wp_rest' ),
137 + 'registrationNonce' => '', // Not used, keeping it for compatibility reasons, see https://github.com/Automattic/jetpack/pull/42076
138 + 'purchaseToken' => self::get_purchase_token(),
139 + 'partnerCoupon' => Jetpack_Partner_Coupon::get_coupon(),
140 + 'pluginBaseUrl' => plugins_url( '', JETPACK__PLUGIN_FILE ),
141 + 'connectionStatus' => $connection_status,
142 + 'connectedPlugins' => Connection_Plugin_Storage::get_all(),
143 + 'connectUrl' => false == $current_user_data['isConnected'] // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual
137 144 ? Jetpack::init()->build_connect_url( true, false, false )
138 145 : '',
139 - 'dismissedNotices' => self::get_dismissed_jetpack_notices(),
140 - 'isDevVersion' => Jetpack::is_development_version(),
141 - 'currentVersion' => JETPACK__VERSION,
142 - 'is_gutenberg_available' => true,
143 - 'getModules' => $modules,
144 - 'rawUrl' => ( new Status() )->get_site_suffix(),
145 - 'adminUrl' => esc_url( admin_url() ),
146 - 'siteTitle' => (string) htmlspecialchars_decode( get_option( 'blogname' ), ENT_QUOTES ),
147 - 'stats' => array(
146 + 'dismissedNotices' => self::get_dismissed_jetpack_notices(),
147 + 'isDevVersion' => Jetpack::is_development_version(),
148 + 'currentVersion' => JETPACK__VERSION,
149 + 'is_gutenberg_available' => true,
150 + 'getModules' => $modules,
151 + 'rawUrl' => ( new Status() )->get_site_suffix(),
152 + 'adminUrl' => esc_url( admin_url() ),
153 + 'siteTitle' => htmlspecialchars_decode( get_option( 'blogname' ), ENT_QUOTES ),
154 + 'stats' => array(
148 155 // data is populated asynchronously on page load.
149 156 'data' => array(
150 157 'general' => false,
151 158 'day' => false,
@@ -153,19 +160,20 @@
153 160 'month' => false,
154 161 ),
155 162 'roles' => $stats_roles,
156 163 ),
157 - 'aff' => Partner::init()->get_partner_code( Partner::AFFILIATE_CODE ),
158 - 'partnerSubsidiaryId' => Partner::init()->get_partner_code( Partner::SUBSIDIARY_CODE ),
159 - 'settings' => self::get_flattened_settings( $modules ),
160 - 'userData' => array(
164 + 'aff' => Partner::init()->get_partner_code( Partner::AFFILIATE_CODE ),
165 + 'partnerSubsidiaryId' => Partner::init()->get_partner_code( Partner::SUBSIDIARY_CODE ),
166 + 'settings' => self::get_flattened_settings(),
167 + 'userData' => array(
161 168 'currentUser' => $current_user_data,
162 169 ),
163 - 'siteData' => array(
170 + 'siteData' => array(
164 171 'blog_id' => Jetpack_Options::get_option( 'id', 0 ),
165 172 'icon' => has_site_icon()
166 173 ? apply_filters( 'jetpack_photon_url', get_site_icon_url(), array( 'w' => 64 ) )
167 174 : '',
175 + 'representativeImage' => self::get_site_image(),
168 176 'siteVisibleToSearchEngines' => '1' == get_option( 'blog_public' ), // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual
169 177 /**
170 178 * Whether promotions are visible or not.
171 179 *
@@ -173,58 +181,85 @@
173 181 *
174 182 * @param bool $are_promotions_active Status of promotions visibility. True by default.
175 183 */
176 184 'showPromotions' => apply_filters( 'jetpack_show_promotions', true ),
177 - 'isAtomicSite' => $host->is_woa_site(),
178 - 'isWoASite' => $host->is_woa_site(),
179 - 'isAtomicPlatform' => $host->is_atomic_platform(),
180 185 'plan' => Jetpack_Plan::get(),
181 186 'showBackups' => Jetpack::show_backups_ui(),
187 + 'showScan' => Jetpack::show_scan_ui(),
182 188 'showRecommendations' => Jetpack_Recommendations::is_enabled(),
183 189 /** This filter is documented in my-jetpack/src/class-initializer.php */
184 190 'showMyJetpack' => My_Jetpack_Initializer::should_initialize(),
185 191 'isMultisite' => is_multisite(),
186 192 'dateFormat' => get_option( 'date_format' ),
193 + 'latestBoostSpeedScores' => $speed_score_history->latest(),
194 + 'isSharingBlockAvailable' => isset( $block_availability['sharing-buttons'] )
195 + && $block_availability['sharing-buttons']['available'],
196 + 'isLikeBlockAvailable' => isset( $block_availability['like'] )
197 + && $block_availability['like']['available'],
187 198 ),
188 - 'themeData' => array(
189 - 'name' => $current_theme->get( 'Name' ),
190 - 'hasUpdate' => (bool) get_theme_update_available( $current_theme ),
191 - 'support' => array(
199 + 'themeData' => array(
200 + 'name' => $current_theme->get( 'Name' ),
201 + 'stylesheet' => $current_theme->get_stylesheet(),
202 + 'hasUpdate' => (bool) get_theme_update_available( $current_theme ),
203 + 'isBlockTheme' => (bool) $current_theme->is_block_theme(),
204 + 'support' => array(
192 205 'infinite-scroll' => current_theme_supports( 'infinite-scroll' ) || in_array( $current_theme->get_stylesheet(), $inf_scr_support_themes, true ),
193 206 'widgets' => current_theme_supports( 'widgets' ),
194 - 'webfonts' => (
195 - // @todo Remove conditional once we drop support for WordPress 6.1
196 - function_exists( 'wp_theme_has_theme_json' ) ? wp_theme_has_theme_json() : WP_Theme_JSON_Resolver::theme_has_support()
197 - ) && function_exists( 'wp_register_webfont_provider' ) && function_exists( 'wp_register_webfonts' ),
207 + 'webfonts' => wp_theme_has_theme_json()
208 + && ( function_exists( 'wp_register_webfont_provider' ) || function_exists( 'wp_register_webfonts' ) ),
198 209 ),
199 210 ),
200 - 'jetpackStateNotices' => array(
211 + 'jetpackStateNotices' => array(
201 212 'messageCode' => Jetpack::state( 'message' ),
202 213 'errorCode' => Jetpack::state( 'error' ),
203 214 'errorDescription' => Jetpack::state( 'error_description' ),
204 - 'messageContent' => Jetpack::state( 'display_update_modal' ) ? self::get_update_modal_data() : null,
205 215 ),
206 - 'tracksUserData' => Jetpack_Tracks_Client::get_connected_user_tracks_identity(),
207 - 'currentIp' => IP_Utils::get_ip(),
208 - 'lastPostUrl' => esc_url( $last_post ),
209 - 'externalServicesConnectUrls' => self::get_external_services_connect_urls(),
210 - 'calypsoEnv' => Jetpack::get_calypso_env(),
211 - 'products' => Jetpack::get_products_for_purchase(),
212 - 'recommendationsStep' => Jetpack_Core_Json_Api_Endpoints::get_recommendations_step()['step'],
213 - 'isSafari' => $is_safari || User_Agent_Info::is_opera_desktop(), // @todo Rename isSafari everywhere.
214 - 'doNotUseConnectionIframe' => Constants::is_true( 'JETPACK_SHOULD_NOT_USE_CONNECTION_IFRAME' ),
215 - 'licensing' => array(
216 + 'tracksUserData' => Jetpack_Tracks_Client::get_connected_user_tracks_identity(),
217 + 'currentIp' => IP_Utils::get_ip(),
218 + 'lastPostUrl' => esc_url( $last_post ),
219 + 'externalServicesConnectUrls' => self::get_external_services_connect_urls(),
220 + 'calypsoEnv' => ( new Host() )->get_calypso_env(),
221 + 'products' => Jetpack::get_products_for_purchase(),
222 + 'recommendationsStep' => Jetpack_Core_Json_Api_Endpoints::get_recommendations_step()['step'],
223 + 'isSafari' => $is_safari || User_Agent_Info::is_opera_desktop(), // @todo Rename isSafari everywhere.
224 + 'doNotUseConnectionIframe' => Constants::is_true( 'JETPACK_SHOULD_NOT_USE_CONNECTION_IFRAME' ),
225 + 'licensing' => array(
216 226 'error' => Licensing::instance()->last_error(),
217 227 'showLicensingUi' => Licensing::instance()->is_licensing_input_enabled(),
218 228 'userCounts' => Licensing_Endpoints::get_user_license_counts(),
219 229 'activationNoticeDismiss' => Licensing::instance()->get_license_activation_notice_dismiss(),
220 230 ),
221 - 'hasSeenWCConnectionModal' => Jetpack_Options::get_option( 'has_seen_wc_connection_modal', false ),
222 - 'newRecommendations' => Jetpack_Recommendations::get_new_conditional_recommendations(),
231 + 'jetpackManage' => array(
232 + 'isEnabled' => Jetpack_Manage::could_use_jp_manage(),
233 + 'isAgencyAccount' => Jetpack_Manage::is_agency_account(),
234 + ),
235 + 'hasSeenWCConnectionModal' => Jetpack_Options::get_option( 'has_seen_wc_connection_modal', false ),
236 + 'newRecommendations' => Jetpack_Recommendations::get_new_conditional_recommendations(),
223 237 // Check if WooCommerce plugin is active (based on https://docs.woocommerce.com/document/create-a-plugin/).
224 - 'isWooCommerceActive' => in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', Jetpack::get_active_plugins() ), true ),
225 - 'useMyJetpackLicensingUI' => My_Jetpack_Initializer::is_licensing_ui_enabled(),
226 - 'isOdysseyStatsEnabled' => Stats_Options::get_option( 'enable_odyssey_stats' ),
238 + 'isWooCommerceActive' => in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', Jetpack::get_active_plugins() ), true ),
239 + 'useMyJetpackLicensingUI' => My_Jetpack_Initializer::is_licensing_ui_enabled(),
240 + 'isOdysseyStatsEnabled' => Stats_Options::get_option( 'enable_odyssey_stats' ),
241 + 'shouldInitializeBlaze' => Blaze::should_initialize(),
242 + 'isBlazeDashboardEnabled' => Blaze::is_dashboard_enabled(),
243 + // The composed AI gate chain (host, and the master where its rollout
244 + // is active) — what the editor enforces, for settings UI that must
245 + // not contradict it.
246 + 'isAiEnabled' => Jetpack_AI_Settings::is_ai_enabled(),
247 + // The AI SEO feature, gates folded in: controls that drive only its
248 + // automatic half must follow it too.
249 + 'isAiSeoEnabled' => Jetpack_AI_Settings::is_ai_seo_enabled(),
250 + 'isSubscriptionSiteEnabled' => apply_filters( 'jetpack_subscription_site_enabled', false ),
251 + 'newsletterDateExample' => gmdate( get_option( 'date_format' ), time() ),
252 + 'subscriptionSiteEditSupported' => $current_theme->is_block_theme(),
253 +
254 + /*
255 + * This filter is already documented in jetpack/modules/subscriptions.php.
256 + * Defaults on for every site; hosts can opt out with the filter.
257 + */
258 + 'isWpAdminSubscriberManagementEnabled' => apply_filters(
259 + 'jetpack_wp_admin_subscriber_management_enabled',
260 + true
261 + ),
227 262 );
228 263 }
229 264
230 265 /**
@@ -255,70 +290,33 @@
255 290 }
256 291
257 292 /**
258 293 * Returns the release post content and image data as an associative array.
259 - * This data is used to create the update modal.
294 + *
295 + * The update modal that consumed this data has been removed, so there is nothing to return.
296 + *
297 + * @deprecated 16.2
298 + *
299 + * @return null
260 300 */
261 301 public static function get_update_modal_data() {
262 - $post_data = self::get_release_post_data();
263 -
264 - if ( ! isset( $post_data['posts'][0] ) ) {
265 - return;
266 - }
267 -
268 - $post = $post_data['posts'][0];
269 -
270 - if ( empty( $post['content'] ) ) {
271 - return;
272 - }
273 -
274 - // This allows us to embed videopress videos into the release post.
275 - add_filter( 'wp_kses_allowed_html', array( __CLASS__, 'allow_post_embed_iframe' ), 10, 2 );
276 - $content = wp_kses_post( $post['content'] );
277 - remove_filter( 'wp_kses_allowed_html', array( __CLASS__, 'allow_post_embed_iframe' ), 10, 2 );
278 -
279 - $post_title = isset( $post['title'] ) ? $post['title'] : null;
280 - $title = wp_kses( $post_title, array() );
281 -
282 - $post_thumbnail = isset( $post['post_thumbnail'] ) ? $post['post_thumbnail'] : null;
283 - if ( ! empty( $post_thumbnail ) ) {
284 - require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.jetpack-photon-image.php';
285 - $photon_image = new Jetpack_Photon_Image(
286 - array(
287 - 'file' => jetpack_photon_url( $post_thumbnail['URL'] ),
288 - 'width' => $post_thumbnail['width'],
289 - 'height' => $post_thumbnail['height'],
290 - ),
291 - $post_thumbnail['mime_type']
292 - );
293 - $photon_image->resize(
294 - array(
295 - 'width' => 600,
296 - 'height' => null,
297 - 'crop' => false,
298 - )
299 - );
300 - $post_thumbnail_url = $photon_image->get_raw_filename();
301 - } else {
302 - $post_thumbnail_url = null;
303 - }
304 -
305 - $post_array = array(
306 - 'release_post_content' => $content,
307 - 'release_post_featured_image' => $post_thumbnail_url,
308 - 'release_post_title' => $title,
309 - );
310 -
311 - return $post_array;
302 + _deprecated_function( __METHOD__, 'jetpack-16.2' );
303 + return null;
312 304 }
313 305
314 306 /**
315 307 * Temporarily allow post content to contain iframes, e.g. for videopress.
316 308 *
309 + * Only ever used while sanitizing the release post for the removed update modal.
310 + *
311 + * @deprecated 16.2
312 + *
317 313 * @param string $tags The tags.
318 314 * @param string $context The context.
319 315 */
320 316 public static function allow_post_embed_iframe( $tags, $context ) {
317 + _deprecated_function( __METHOD__, 'jetpack-16.2' );
318 +
321 319 if ( 'post' === $context ) {
322 320 $tags['iframe'] = array(
323 321 'src' => true,
324 322 'height' => true,
@@ -331,38 +329,20 @@
331 329 return $tags;
332 330 }
333 331
334 332 /**
335 - * Obtains the release post from the Jetpack release post blog. A release post will be displayed in the
336 - * update modal when a post has a tag equal to the Jetpack version number.
333 + * Obtains the release post from the Jetpack release post blog.
337 334 *
338 - * The response parameters for the post array can be found here:
339 - * https://developer.wordpress.com/docs/api/1.1/get/sites/%24site/posts/%24post_ID/#apidoc-response
335 + * The release post blog has had no post tagged for a current Jetpack version since 2023, and the
336 + * update modal that consumed this has been removed, so this no longer makes a remote request.
340 337 *
341 - * @return array|null Returns an associative array containing the release post data at index ['posts'][0].
342 - * Returns null if the release post data is not available.
338 + * @deprecated 16.2
339 + *
340 + * @return null
343 341 */
344 342 public static function get_release_post_data() {
345 - if ( Constants::is_defined( 'TESTING_IN_JETPACK' ) && Constants::get_constant( 'TESTING_IN_JETPACK' ) ) {
346 - return null;
347 - }
348 -
349 - $release_post_src = add_query_arg(
350 - array(
351 - 'order_by' => 'date',
352 - 'tag' => JETPACK__VERSION,
353 - 'number' => '1',
354 - ),
355 - 'https://public-api.wordpress.com/rest/v1/sites/' . JETPACK__RELEASE_POST_BLOG_SLUG . '/posts'
356 - );
357 -
358 - $response = wp_remote_get( $release_post_src );
359 -
360 - if ( ! is_array( $response ) ) {
361 - return null;
362 - }
363 -
364 - return json_decode( wp_remote_retrieve_body( $response ), true );
343 + _deprecated_function( __METHOD__, 'jetpack-16.2' );
344 + return null;
365 345 }
366 346
367 347 /**
368 348 * Get external services connect URLs.
@@ -368,13 +348,10 @@
368 348 * Get external services connect URLs.
369 349 */
370 350 public static function get_external_services_connect_urls() {
371 351 $connect_urls = array();
372 - require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.jetpack-keyring-service-helper.php';
373 - // phpcs:disable
374 - foreach ( Jetpack_Keyring_Service_Helper::SERVICES as $service_name => $service_info ) {
375 - // phpcs:enable
376 - $connect_urls[ $service_name ] = Jetpack_Keyring_Service_Helper::connect_url( $service_name, $service_info['for'] );
352 + foreach ( Keyring_Helper::SERVICES as $service_name => $service_info ) {
353 + $connect_urls[ $service_name ] = Keyring_Helper::connect_url( $service_name, $service_info['for'] );
377 354 }
378 355 return $connect_urls;
379 356 }
380 357
@@ -408,8 +385,21 @@
408 385 */
409 386 public static function generate_purchase_token() {
410 387 return wp_generate_password( 12, false );
411 388 }
389 +
390 + /**
391 + * Get a representative image for the site.
392 + *
393 + * @since 15.0
394 + *
395 + * @return string
396 + */
397 + public static function get_site_image(): string {
398 + // Get the dynamic image generated for the Open Graph Meta tags.
399 + require_once JETPACK__PLUGIN_DIR . 'functions.opengraph.php';
400 + return jetpack_og_get_fallback_social_image( 200, 200 )['src'];
401 + }
412 402 }
413 403
414 404 // phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- TODO: Move these functions to some other file.
415 405
@@ -447,11 +437,13 @@
447 437 $current_user_data = array(
448 438 'isConnected' => $is_user_connected,
449 439 'isMaster' => $is_master_user,
450 440 'username' => $current_user->user_login,
441 + 'displayName' => $current_user->display_name,
442 + 'email' => $current_user->user_email,
451 443 'id' => $current_user->ID,
452 444 'wpcomUser' => $dotcom_data,
453 - 'gravatar' => get_avatar_url( $current_user->ID, 64, 'mm', '', array( 'force_display' => true ) ),
445 + 'gravatar' => get_avatar_url( $current_user->ID ),
454 446 'permissions' => array(
455 447 'admin_page' => current_user_can( 'jetpack_admin_page' ),
456 448 'connect' => current_user_can( 'jetpack_connect' ),
457 449 'connect_user' => current_user_can( 'jetpack_connect_user' ),