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 | class.jetpack.php +218 -103 16.3 → 16.3-a.1 View file →
@@ -6,8 +6,9 @@
6 6 *
7 7 * @package automattic/jetpack
8 8 */
9 9
10 +use Automattic\Jetpack\Activity_Log\Jetpack_Activity_Log as Activity_Log_Init;
10 11 use Automattic\Jetpack\Assets;
11 12 use Automattic\Jetpack\Boost_Speed_Score\Speed_Score;
12 13 use Automattic\Jetpack\Config;
13 14 use Automattic\Jetpack\Connection\Authorize_Json_Api;
@@ -21,9 +22,8 @@
21 22 use Automattic\Jetpack\CookieState;
22 23 use Automattic\Jetpack\Current_Plan as Jetpack_Plan;
23 24 use Automattic\Jetpack\Device_Detection\User_Agent_Info;
24 25 use Automattic\Jetpack\Errors;
25 -use Automattic\Jetpack\Feature_Policy;
26 26 use Automattic\Jetpack\Files;
27 27 use Automattic\Jetpack\Heartbeat;
28 28 use Automattic\Jetpack\Identity_Crisis;
29 29 use Automattic\Jetpack\Import\Main as Import_Main;
@@ -80,8 +80,20 @@
80 80 * The Jetpack class.
81 81 */
82 82 class Jetpack {
83 83 /**
84 + * Marks that the durable Jetpack SEO module-state options have been reconciled against
85 + * the site's module configuration, so the repair runs at most once.
86 + *
87 + * {@see self::reconcile_seo_module_state_options()}
88 + *
89 + * @since 16.1
90 + *
91 + * @var string
92 + */
93 + const SEO_MODULE_STATE_RECONCILED_OPTION = 'jetpack_seo_module_state_reconciled';
94 +
95 + /**
84 96 * XMLRPC server instance.
85 97 *
86 98 * @var null|Jetpack_XMLRPC_Server XMLRPC server used by Jetpack.
87 99 */
@@ -544,11 +556,8 @@
544 556 if ( false === get_option( 'wpcom_newsletter_send_default' ) ) {
545 557 add_option( 'wpcom_newsletter_send_default', 1 );
546 558 }
547 559
548 - // Its handler went with the Recommendations assistant.
549 - wp_clear_scheduled_hook( 'jetpack_recommend_videopress' );
550 -
551 560 if ( did_action( 'wp_loaded' ) ) {
552 561 self::upgrade_on_load();
553 562 } else {
554 563 add_action(
@@ -776,8 +785,11 @@
776 785
777 786 // Register product descriptions for partner coupon usage.
778 787 add_filter( 'jetpack_partner_coupon_products', array( $this, 'get_partner_coupon_product_descriptions' ) );
779 788
789 + // Actions for conditional recommendations.
790 + add_action( 'plugins_loaded', array( 'Jetpack_Recommendations', 'init_conditional_recommendation_actions' ) );
791 +
780 792 // Add 5-star
781 793 add_filter( 'plugin_row_meta', array( $this, 'add_5_star_review_link' ), 10, 2 );
782 794 add_action( 'init', array( Deprecate::class, 'instance' ) );
783 795
@@ -839,50 +851,8 @@
839 851 }
840 852 }
841 853
842 854 /**
843 - * Enable the bundled Backup dashboard.
844 - *
845 - * The standalone plugin initializes the package first, so with both active this is a no-op.
846 - *
847 - * @return void
848 - */
849 - public static function configure_backup_package() {
850 - // Not offered on multisite, which the Backup package does not support, or without a
851 - // connected owner, since buying and managing backups needs a linked account.
852 - if ( is_multisite() || ! self::is_connection_ready() || ! self::connection()->has_connected_owner() ) {
853 - return;
854 - }
855 -
856 - if ( ! self::is_module_active( 'backup' ) ) {
857 - return;
858 - }
859 -
860 - /**
861 - * Filters whether the Jetpack plugin offers its bundled Backup dashboard.
862 - *
863 - * Resolved at the earliest `plugins_loaded` priority, so hook it from a mu-plugin.
864 - *
865 - * @since 16.3
866 - *
867 - * @param bool $enabled Whether to initialize the bundled Backup dashboard. Default true.
868 - */
869 - if ( ! apply_filters( 'jetpack_backup_dashboard_enabled', true ) ) {
870 - return;
871 - }
872 -
873 - $backup = 'Automattic\\Jetpack\\Backup\\V0005\\Jetpack_Backup';
874 -
875 - // An older package would take over the connection (see Jetpack_Backup::DEFAULT_INIT_OPTIONS);
876 - // only the standalone plugin ships one that old, and it draws its own menu.
877 - if ( ! class_exists( $backup ) || ! defined( $backup . '::DEFAULT_INIT_OPTIONS' ) ) {
878 - return;
879 - }
880 -
881 - $backup::initialize( array( 'manage_connection' => false ) );
882 - }
883 -
884 - /**
885 855 * Whether the bundled Stats v2 dashboard is enabled.
886 856 *
887 857 * Stats v2 (formerly "Premium Analytics") ships with the plugin behind this
888 858 * flag while it rolls out (WOOA7S-1595). When enabled it adds its own admin
@@ -976,15 +946,8 @@
976 946 // only renders when the VideoPress module is active (Status::is_active()); when it
977 947 // is not, the menu item links to the My Jetpack interstitial to activate it.
978 948 $config->ensure( 'videopress', array( 'admin_ui' => true ) );
979 949
980 - // The Backup dashboard is only an admin menu and REST routes, so it is deferred like Import below.
981 - if ( self::should_eager_load_packages() ) {
982 - self::configure_backup_package();
983 - } else {
984 - add_action( 'rest_api_init', array( __CLASS__, 'configure_backup_package' ), 0 );
985 - }
986 -
987 950 /*
988 951 * The Import package only registers `jetpack/v4/import` REST routes — it
989 952 * does nothing when rendering a front-end page — so gate its `ensure()`
990 953 * to keep its PHP out of opcache on the front-end GET hot path. It still
@@ -1180,8 +1143,9 @@
1180 1143 } else {
1181 1144 add_action( 'rest_api_init', array( My_Jetpack_Initializer::class, 'init' ), 0 );
1182 1145 }
1183 1146
1147 + Activity_Log_Init::initialize();
1184 1148 Scan_Page_Init::initialize();
1185 1149 Jetpack_SEO_Initializer::init();
1186 1150
1187 1151 if ( ( new Modules() )->is_active( 'podcast' ) ) {
@@ -1323,9 +1287,8 @@
1323 1287 $jetpack_callables = array(
1324 1288 'single_user_site' => array( 'Jetpack', 'is_single_user_site' ),
1325 1289 'updates' => array( 'Jetpack', 'get_updates' ),
1326 1290 'available_jetpack_blocks' => array( 'Jetpack_Gutenberg', 'get_availability' ), // Includes both Gutenberg blocks *and* plugins.
1327 - 'theme_styles' => array( 'Automattic\\Jetpack\\Plugin\\Theme_Styles_Sync', 'get_theme_styles' ),
1328 1291 );
1329 1292 return array_merge( $callables, $jetpack_callables );
1330 1293 }
1331 1294
@@ -2080,13 +2043,9 @@
2080 2043 *
2081 2044 * @todo Store the result in core's object cache maybe?
2082 2045 */
2083 2046 public static function get_active_plugins() {
2084 - // Older Connection copies can load first and lack this method.
2085 - if ( ! method_exists( Heartbeat::class, 'get_active_plugins' ) ) {
2086 - return array();
2087 - }
2088 -
2047 + // Delegates to the canonical implementation in the Connection package.
2089 2048 return Heartbeat::get_active_plugins();
2090 2049 }
2091 2050
2092 2051 /**
@@ -2380,12 +2339,8 @@
2380 2339 default:
2381 2340 break;
2382 2341 }
2383 2342 }
2384 - if ( method_exists( Feature_Policy::class, 'ensure_hooks' ) ) {
2385 - Feature_Policy::ensure_hooks();
2386 - }
2387 -
2388 2343 /**
2389 2344 * Filters the array of default modules.
2390 2345 *
2391 2346 * @since 2.5.0
@@ -2545,30 +2500,23 @@
2545 2500
2546 2501 /**
2547 2502 * Return module name translation. Uses matching string created in modules/module-headings.php.
2548 2503 *
2549 - * The module list is globbed from `modules/` at runtime, so a module can be listed with no
2550 - * entry in that generated file. Fall back to the untranslated header rather than overwriting
2551 - * it with the null `jetpack_get_module_i18n()` returns for an unknown slug.
2552 - *
2553 2504 * @since 3.9.2
2554 2505 *
2555 2506 * @param array $modules Array of Jetpack modules.
2556 2507 *
2557 - * @return array
2508 + * @return string|void
2558 2509 */
2559 2510 public static function get_translated_modules( $modules ) {
2560 2511 foreach ( $modules as $index => $module ) {
2561 2512 $i18n_module = jetpack_get_module_i18n( $module['module'] );
2562 - $name = $i18n_module['name'] ?? null;
2563 - $description = $i18n_module['description'] ?? null;
2564 -
2565 - if ( null !== $name && isset( $module['name'] ) ) {
2566 - $modules[ $index ]['name'] = $name;
2513 + if ( isset( $module['name'] ) ) {
2514 + $modules[ $index ]['name'] = $i18n_module['name'];
2567 2515 }
2568 - if ( null !== $description && isset( $module['description'] ) ) {
2569 - $modules[ $index ]['description'] = $description;
2570 - $modules[ $index ]['short_description'] = $description;
2516 + if ( isset( $module['description'] ) ) {
2517 + $modules[ $index ]['description'] = $i18n_module['description'];
2518 + $modules[ $index ]['short_description'] = $i18n_module['description'];
2571 2519 }
2572 2520 if ( isset( $module['module_tags'] ) ) {
2573 2521 $modules[ $index ]['module_tags'] = array_map( 'jetpack_get_module_i18n_tag', $module['module_tags'] );
2574 2522 }
@@ -2881,9 +2829,9 @@
2881 2829 * @return string $url module configuration URL.
2882 2830 */
2883 2831 public static function module_configuration_url( $module ) {
2884 2832 $module = self::get_module_slug( $module );
2885 - $default_url = self::admin_url( array( 'page' => 'jetpack-settings' ) ) . "#/settings?term=$module";
2833 + $default_url = self::admin_url() . "#/settings?term=$module";
2886 2834 /**
2887 2835 * Allows to modify configure_url of specific module to be able to redirect to some custom location.
2888 2836 *
2889 2837 * @since 6.9.0
@@ -3159,19 +3107,199 @@
3159 3107 update_option( self::AI_MASTER_OPTOUT_MIGRATED_OPTION, true );
3160 3108 }
3161 3109
3162 3110 /**
3163 - * Deletes obsolete SEO module-state options without changing module activation.
3111 + * Whether a module should be recorded as active in its durable Jetpack SEO option.
3164 3112 *
3165 - * @since 16.3
3113 + * Permanent module overrides are part of the site's configuration, so the normal
3114 + * filtered module state is authoritative. The exception is wpcomsh's private-site
3115 + * callback, which temporarily suppresses `sitemaps` on Atomic sites without changing
3116 + * the site's configured state. Evaluate the module state with only that callback
3117 + * disabled.
3118 + *
3119 + * The hook is cloned before removing the callback so its ordering remains unchanged for
3120 + * the rest of the request. `$available_only` is false because these migrations can run
3121 + * after the standalone module file has been removed.
3122 + *
3123 + * WordPress.com Simple keeps module state outside this site's options table, so its
3124 + * normal filtered read remains authoritative.
3125 + *
3126 + * @since 16.1
3127 + *
3128 + * @param string $module Module slug.
3129 + * @return bool Whether the module should be recorded as active.
3166 3130 */
3167 - public static function cleanup_seo_module_state_options() {
3168 - delete_option( 'jetpack_seo_sitemap_enabled' );
3169 - delete_option( 'jetpack_seo_canonical_urls_enabled' );
3170 - delete_option( 'jetpack_seo_module_state_reconciled' );
3131 + private static function is_module_active_for_seo_option( $module ) {
3132 + $modules = new Modules();
3133 +
3134 + if ( ( new Host() )->is_wpcom_simple() ) {
3135 + return $modules->is_active( $module, false );
3136 + }
3137 +
3138 + global $wp_filter;
3139 +
3140 + $hook_name = 'jetpack_active_modules';
3141 + $private_site_callback = '\Private_Site\filter_jetpack_active_modules';
3142 + $callback_priority = has_filter( $hook_name, $private_site_callback );
3143 +
3144 + if ( false === $callback_priority ) {
3145 + return $modules->is_active( $module, false );
3146 + }
3147 +
3148 + $original_hook = $wp_filter[ $hook_name ];
3149 + // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Use an isolated hook copy without changing callback order.
3150 + $wp_filter[ $hook_name ] = clone $original_hook;
3151 + remove_filter( $hook_name, $private_site_callback, $callback_priority );
3152 +
3153 + try {
3154 + return $modules->is_active( $module, false );
3155 + } finally {
3156 + // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Restore the untouched original hook.
3157 + $wp_filter[ $hook_name ] = $original_hook;
3158 + }
3171 3159 }
3172 3160
3173 3161 /**
3162 + * Records whether the standalone Sitemaps module is active so the setting survives
3163 + * the module's removal.
3164 + *
3165 + * The Jetpack SEO product reads the {@see Jetpack_SEO_Initializer::SITEMAP_ENABLED_OPTION}
3166 + * option instead of the `sitemaps` module's active state. Module-active state is
3167 + * filtered against the modules present on disk, so once the standalone module is
3168 + * removed it would read as inactive even for sites that had it on. This one-time
3169 + * migration captures the configured module state — which persists regardless of
3170 + * whether the module file is present — into the durable option.
3171 + *
3172 + * Deliberately non-destructive: it never touches generated sitemap data
3173 + * (`jp_sitemap*` posts), the `jetpack-sitemap-state` option, sitemap settings, or the
3174 + * `jp_sitemap_cron_hook` cron, so no regeneration is triggered. `add_option()` only
3175 + * seeds when the option is absent, so it is safe to run on every version bump and
3176 + * never reverts a value the user has since set.
3177 + *
3178 + * Hooked on `updating_jetpack_version`; the version arguments are not needed because
3179 + * `add_option()` provides the run-once guard.
3180 + */
3181 + public static function migrate_sitemaps_module_to_seo_option() {
3182 + // Ignore wpcomsh's temporary private-site suppression while preserving permanent
3183 + // module overrides. {@see self::is_module_active_for_seo_option()}.
3184 + $sitemaps_active = self::is_module_active_for_seo_option( 'sitemaps' );
3185 +
3186 + add_option( Jetpack_SEO_Initializer::SITEMAP_ENABLED_OPTION, $sitemaps_active );
3187 + }
3188 +
3189 + /**
3190 + * Keeps the Jetpack SEO sitemap option in sync with the legacy `sitemaps` module
3191 + * while both still exist.
3192 + *
3193 + * Hooked to the module's activate/deactivate actions, so toggling sitemaps from any
3194 + * surface (the legacy Traffic settings, the SEO Settings tab, or WP-CLI) keeps the
3195 + * durable {@see Jetpack_SEO_Initializer::SITEMAP_ENABLED_OPTION} option current. The
3196 + * actions fire after `active_modules` is updated, so the configured state already
3197 + * reflects the new choice. Ignore temporary private-site suppression without bypassing
3198 + * permanent module overrides. Removed alongside the module itself.
3199 + */
3200 + public static function sync_seo_sitemap_option() {
3201 + update_option( Jetpack_SEO_Initializer::SITEMAP_ENABLED_OPTION, self::is_module_active_for_seo_option( 'sitemaps' ) );
3202 + }
3203 +
3204 + /**
3205 + * Records whether the standalone Canonical URLs module is active so the setting survives
3206 + * the module's removal.
3207 + *
3208 + * The Jetpack SEO product reads the {@see Jetpack_SEO_Initializer::CANONICAL_ENABLED_OPTION}
3209 + * option instead of the `canonical-urls` module's active state. Module-active state is
3210 + * filtered against the modules present on disk, so once the standalone module is
3211 + * removed it would read as inactive even for sites that had it on. This one-time
3212 + * migration captures the configured module state — which persists regardless of
3213 + * whether the module file is present — into the durable option.
3214 + *
3215 + * Deliberately non-destructive: `add_option()` only seeds when the option is absent, so
3216 + * it is safe to run on every version bump and never reverts a value the user has since
3217 + * set.
3218 + *
3219 + * Hooked on `updating_jetpack_version`; the version arguments are not needed because
3220 + * `add_option()` provides the run-once guard.
3221 + */
3222 + public static function migrate_canonical_urls_module_to_seo_option() {
3223 + $canonical_active = self::is_module_active_for_seo_option( 'canonical-urls' );
3224 +
3225 + add_option( Jetpack_SEO_Initializer::CANONICAL_ENABLED_OPTION, $canonical_active );
3226 + }
3227 +
3228 + /**
3229 + * Keeps the Jetpack SEO canonical-urls option in sync with the legacy `canonical-urls`
3230 + * module while both still exist.
3231 + *
3232 + * Hooked to the module's activate/deactivate actions, so toggling canonical URLs from any
3233 + * surface (the legacy Traffic settings, the SEO Settings tab, or WP-CLI) keeps the
3234 + * durable {@see Jetpack_SEO_Initializer::CANONICAL_ENABLED_OPTION} option current. The
3235 + * actions fire after `active_modules` is updated, so the configured state already
3236 + * reflects the new choice. Permanent module overrides remain authoritative. Removed
3237 + * alongside the module itself.
3238 + */
3239 + public static function sync_seo_canonical_urls_option() {
3240 + update_option( Jetpack_SEO_Initializer::CANONICAL_ENABLED_OPTION, self::is_module_active_for_seo_option( 'canonical-urls' ) );
3241 + }
3242 +
3243 + /**
3244 + * Repairs durable SEO module-state options that the first pass of the migration seeded
3245 + * from a filtered read.
3246 + *
3247 + * Jetpack 16.0 seeded {@see Jetpack_SEO_Initializer::SITEMAP_ENABLED_OPTION} and
3248 + * {@see Jetpack_SEO_Initializer::CANONICAL_ENABLED_OPTION} through
3249 + * {@see Modules::is_active()}, which passes the `jetpack_active_modules` filter. A site
3250 + * that was private at the time therefore recorded `sitemaps` as off even though the user
3251 + * had it on, and because the migration seeds with `add_option()` the value was never
3252 + * revisited — making the site public again did not restore the setting.
3253 + *
3254 + * This runs once and rewrites both options from the site's configured module state,
3255 + * including permanent module overrides. That is safe against a choice the user has made
3256 + * since: every surface that toggles these settings (the legacy Traffic page, the SEO
3257 + * Settings tab, WP-CLI) goes through {@see Modules::activate()}/{@see Modules::deactivate()},
3258 + * so the module state and durable option are already in agreement wherever the original
3259 + * migration got it right.
3260 + *
3261 + * Idempotent: the marker is written with `add_option()`, so reruns on later version bumps
3262 + * are no-ops. Like the migrations it seeds from, it touches no sitemap data or cron state.
3263 + *
3264 + * @since 16.1
3265 + */
3266 + public static function reconcile_seo_module_state_options() {
3267 + if ( get_option( self::SEO_MODULE_STATE_RECONCILED_OPTION ) ) {
3268 + return;
3269 + }
3270 +
3271 + update_option( Jetpack_SEO_Initializer::SITEMAP_ENABLED_OPTION, self::is_module_active_for_seo_option( 'sitemaps' ) );
3272 + update_option( Jetpack_SEO_Initializer::CANONICAL_ENABLED_OPTION, self::is_module_active_for_seo_option( 'canonical-urls' ) );
3273 +
3274 + add_option( self::SEO_MODULE_STATE_RECONCILED_OPTION, true );
3275 + }
3276 +
3277 + /**
3278 + * Wires up the migration + sync hooks that keep the durable Jetpack SEO module-state
3279 + * options ({@see Jetpack_SEO_Initializer::SITEMAP_ENABLED_OPTION} /
3280 + * {@see Jetpack_SEO_Initializer::CANONICAL_ENABLED_OPTION}) seeded and in sync with their
3281 + * legacy modules. Called once from `load-jetpack.php`.
3282 + *
3283 + * Extracted from file scope so the wiring is unit-testable (file-scope `add_action()`
3284 + * calls run during bootstrap and can't be exercised by a test). Removed alongside the
3285 + * modules in the deferred post-convergence follow-up that absorbs them into Jetpack SEO.
3286 + */
3287 + public static function register_seo_module_migration_hooks() {
3288 + add_action( 'updating_jetpack_version', array( 'Jetpack', 'migrate_sitemaps_module_to_seo_option' ) );
3289 + add_action( 'jetpack_activate_module_sitemaps', array( 'Jetpack', 'sync_seo_sitemap_option' ) );
3290 + add_action( 'jetpack_deactivate_module_sitemaps', array( 'Jetpack', 'sync_seo_sitemap_option' ) );
3291 +
3292 + add_action( 'updating_jetpack_version', array( 'Jetpack', 'migrate_canonical_urls_module_to_seo_option' ) );
3293 + add_action( 'jetpack_activate_module_canonical-urls', array( 'Jetpack', 'sync_seo_canonical_urls_option' ) );
3294 + add_action( 'jetpack_deactivate_module_canonical-urls', array( 'Jetpack', 'sync_seo_canonical_urls_option' ) );
3295 +
3296 + // Runs after both migrations above (default priority, registered last) so a freshly
3297 + // seeded site is already correct and the reconciliation is a no-op there.
3298 + add_action( 'updating_jetpack_version', array( 'Jetpack', 'reconcile_seo_module_state_options' ) );
3299 + }
3300 +
3301 + /**
3174 3302 * Seeds the Jetpack SEO discoverability cohort once, so the new SEO surface is
3175 3303 * auto-discoverable on fresh installs but opt-in on existing ones (JETPACK-1700).
3176 3304 *
3177 3305 * Hooked on `updating_jetpack_version`, which fires on every install including the
@@ -3537,12 +3665,10 @@
3537 3665 */
3538 3666 public static function get_stat_data( $encode = true, $extended = true ) {
3539 3667 _deprecated_function( __METHOD__, 'jetpack-16.2', 'Automattic\\Jetpack\\Heartbeat::generate_stats_array' );
3540 3668
3541 - $env_stats = method_exists( Heartbeat::class, 'get_environment_stats' )
3542 - ? Heartbeat::get_environment_stats()
3543 - : array();
3544 - $data = array_merge( Jetpack_Heartbeat::generate_stats_array(), $env_stats );
3669 + // Site environment stats now live in the Connection package; merge them with the Jetpack-specific stats.
3670 + $data = array_merge( Jetpack_Heartbeat::generate_stats_array(), Heartbeat::get_environment_stats() );
3545 3671
3546 3672 if ( $extended ) {
3547 3673 $additional_data = self::get_additional_stat_data();
3548 3674 $data = array_merge( $data, $additional_data );
@@ -4003,9 +4129,9 @@
4003 4129 */
4004 4130 public function plugin_action_links( $actions ) {
4005 4131 if ( current_user_can( 'jetpack_manage_modules' ) && ( self::is_connection_ready() || ( new Status() )->is_offline_mode() ) ) {
4006 4132 return array_merge(
4007 - array( 'settings' => sprintf( '<a href="%s">%s</a>', esc_url( self::admin_url( 'page=jetpack-settings#/settings' ) ), __( 'Settings', 'jetpack' ) ) ),
4133 + array( 'settings' => sprintf( '<a href="%s">%s</a>', esc_url( self::admin_url( 'page=jetpack#/settings' ) ), __( 'Settings', 'jetpack' ) ) ),
4008 4134 $actions
4009 4135 );
4010 4136 }
4011 4137
@@ -4041,9 +4167,9 @@
4041 4167 Assets::enqueue_script( 'jetpack-plugins-page-js' );
4042 4168
4043 4169 // Add objects to be passed to the initial state of the app.
4044 4170 // Use wp_add_inline_script instead of wp_localize_script, see https://core.trac.wordpress.org/ticket/25280.
4045 - wp_add_inline_script( 'jetpack-plugins-page-js', 'var Initial_State=' . wp_json_encode( Jetpack_Redux_State_Helper::get_plugins_page_state(), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ) . ';', 'before' );
4171 + wp_add_inline_script( 'jetpack-plugins-page-js', 'var Initial_State=' . wp_json_encode( Jetpack_Redux_State_Helper::get_minimal_state(), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ) . ';', 'before' );
4046 4172
4047 4173 add_action( 'admin_footer', array( $this, 'jetpack_plugin_portal_containers' ) );
4048 4174 }
4049 4175 }
@@ -5085,13 +5211,9 @@
5085 5211 * @return boolean
5086 5212 * @since 2.3.3
5087 5213 */
5088 5214 public static function permit_ssl( $force_recheck = false ) {
5089 - if ( ! method_exists( Heartbeat::class, 'permit_ssl' ) ) {
5090 - // Skip the SSL-fail notice when the check cannot run.
5091 - return true;
5092 - }
5093 -
5215 + // Delegates to the canonical SSL check in the Connection package.
5094 5216 return Heartbeat::permit_ssl( $force_recheck );
5095 5217 }
5096 5218
5097 5219 /**
@@ -5104,12 +5226,8 @@
5104 5226 *
5105 5227 * @return string The localized message, or an empty string when there is no failure.
5106 5228 */
5107 5229 public static function get_ssl_test_message() {
5108 - if ( ! method_exists( Heartbeat::class, 'get_ssl_test_error' ) ) {
5109 - return '';
5110 - }
5111 -
5112 5230 $error = Heartbeat::get_ssl_test_error();
5113 5231
5114 5232 switch ( $error['code'] ) {
5115 5233 case 'no_ssl_support':
@@ -6078,14 +6196,11 @@
6078 6196 * callback. We rebuild the stat here rather than running that filter: the filter's callbacks have side
6079 6197 * effects (Connection\Manager::add_stats_to_heartbeat() consumes and deletes the `xmlrpc_errors` option)
6080 6198 * and return non-scalar values, neither of which is appropriate for this read-only diagnostic.
6081 6199 */
6082 - $env_stats = method_exists( Heartbeat::class, 'get_environment_stats' )
6083 - ? Heartbeat::get_environment_stats()
6084 - : array();
6085 - $raw_data = array_merge(
6200 + $raw_data = array_merge(
6086 6201 Jetpack_Heartbeat::generate_stats_array(),
6087 - $env_stats,
6202 + Heartbeat::get_environment_stats(),
6088 6203 array( 'identitycrisis' => Identity_Crisis::check_identity_crisis() ? 'yes' : 'no' )
6089 6204 );
6090 6205
6091 6206 $good = array();