PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3
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 | jetpack_vendor/automattic/jetpack-my-jetpack/src/class-initializer.php +110 -25 16.3-a.3 → 16.3 View file →
@@ -24,8 +24,9 @@
24 24 use Automattic\Jetpack\Licensing;
25 25 use Automattic\Jetpack\Menu_Badges\Menu_Badges;
26 26 use Automattic\Jetpack\Menu_Badges\Notification_Counts;
27 27 use Automattic\Jetpack\Modules;
28 +use Automattic\Jetpack\Partner_Coupon;
28 29 use Automattic\Jetpack\Plugins_Installer;
29 30 use Automattic\Jetpack\Status;
30 31 use Automattic\Jetpack\Status\Host as Status_Host;
31 32 use Automattic\Jetpack\Sync\Functions as Sync_Functions;
@@ -31,8 +32,9 @@
31 32 use Automattic\Jetpack\Sync\Functions as Sync_Functions;
32 33 use Automattic\Jetpack\Terms_Of_Service;
33 34 use Automattic\Jetpack\Tracking;
34 35 use Automattic\Jetpack\WP_Build_Polyfills\WP_Build_Polyfills;
36 +use Automattic\Jetpack\WP_Build_Polyfills\WP_Build_Screen_Id;
35 37 use Jetpack;
36 38 use WP_Error;
37 39
38 40 /**
@@ -44,9 +46,9 @@
44 46 * My Jetpack package version
45 47 *
46 48 * @var string
47 49 */
48 - const PACKAGE_VERSION = '6.4.1';
50 + const PACKAGE_VERSION = '6.8.0';
49 51
50 52 /**
51 53 * Feature flag that swaps the My Jetpack Products tab for a Features tab.
52 54 */
@@ -82,8 +84,9 @@
82 84 'jetpack-protect',
83 85 'jetpack-social',
84 86 'jetpack-videopress',
85 87 'jetpack-search',
88 + 'jetpack-stats',
86 89 );
87 90
88 91 private const MY_JETPACK_SITE_INFO_TRANSIENT_KEY = 'my-jetpack-site-info';
89 92
@@ -204,17 +207,21 @@
204 207 *
205 208 * @return void
206 209 */
207 210 public static function add_my_jetpack_menu_item() {
211 + $position = defined( Admin_Menu::class . '::POSITION_FIRST' ) ? Admin_Menu::POSITION_FIRST : -10;
212 + $menu_slug = 'my-jetpack';
208 213 $page_suffix = Admin_Menu::add_menu(
209 214 __( 'My Jetpack', 'jetpack-my-jetpack' ),
210 215 __( 'My Jetpack', 'jetpack-my-jetpack' ),
211 216 'edit_posts',
212 - 'my-jetpack',
217 + $menu_slug,
213 218 array( __CLASS__, 'admin_page' ),
214 - Admin_Menu::POSITION_FIRST
219 + $position
215 220 );
216 221 add_action( 'load-' . $page_suffix, array( __CLASS__, 'admin_init' ) );
222 + // Users who can edit posts but have no Jetpack menu get an admin_page_ hook instead.
223 + add_action( 'load-admin_page_' . $menu_slug, array( __CLASS__, 'admin_init' ) );
217 224 }
218 225
219 226 /**
220 227 * Callback for the load my jetpack page hook.
@@ -226,20 +233,16 @@
226 233
227 234 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce needed for redirect flow control
228 235 $step = isset( $_GET['step'] ) ? sanitize_text_field( wp_unslash( $_GET['step'] ) ) : '';
229 236
230 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Checking for partner coupon redemption flow
231 - $show_coupon_redemption = isset( $_GET['showCouponRedemption'] );
237 + // Handle onboarding redirects based on connection status. Onboarding's only action is the
238 + // connect request, which answers a user without `jetpack_connect` with a 403.
239 + $redirect_args = self::get_onboarding_redirect_args(
240 + $step,
241 + $connection->is_connected(),
242 + self::is_onboarding_available() && current_user_can( 'jetpack_connect' )
243 + );
232 244
233 - // Redirect to Jetpack dashboard for partner coupon redemption
234 - if ( $show_coupon_redemption ) {
235 - wp_safe_redirect( admin_url( 'admin.php?page=jetpack&showCouponRedemption=1#/dashboard' ) );
236 - exit( 0 );
237 - }
238 -
239 - // Handle onboarding redirects based on connection status
240 - $redirect_args = self::get_onboarding_redirect_args( $step, $connection->is_connected(), self::is_onboarding_available() );
241 -
242 245 if ( null !== $redirect_args ) {
243 246 $admin_page = add_query_arg( $redirect_args, admin_url( 'admin.php' ) );
244 247 $location = wp_sanitize_redirect( $admin_page );
245 248
@@ -264,9 +267,9 @@
264 267 * Whether the My Jetpack onboarding flow is available on this site.
265 268 *
266 269 * WordPress.com Simple sites are connected by definition and don't manage their
267 270 * connection through My Jetpack, so the onboarding flow (which asks the user to
268 - * connect) never applies there.
271 + * connect) never applies there. A pending partner coupon brings its own connect screen.
269 272 *
270 273 * @internal Not part of the package's public API.
271 274 *
272 275 * @return bool
@@ -271,12 +274,46 @@
271 274 *
272 275 * @return bool
273 276 */
274 277 public static function is_onboarding_available() {
275 - return ! ( new Status_Host() )->is_wpcom_simple();
278 + return ! ( new Status_Host() )->is_wpcom_simple() && null === self::get_partner_coupon_screen();
276 279 }
277 280
278 281 /**
282 + * The partner coupon screen's data, when it should replace the dashboard.
283 + *
284 + * Coupons exist only with the Jetpack plugin, which supplies their products and images.
285 + *
286 + * @since 6.5.0
287 + *
288 + * @return array{coupon: array, assetBaseUrl: string}|null
289 + */
290 + public static function get_partner_coupon_screen() {
291 + if (
292 + ! self::should_initialize()
293 + || ! current_user_can( 'manage_options' )
294 + || ! Jetpack_Constants::is_defined( 'JETPACK__PLUGIN_FILE' )
295 + ) {
296 + return null;
297 + }
298 +
299 + $coupon = Partner_Coupon::get_coupon();
300 + if ( ! $coupon ) {
301 + return null;
302 + }
303 +
304 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Only picks which screen renders.
305 + if ( ! isset( $_GET['showCouponRedemption'] ) && ( new Connection_Manager() )->has_connected_owner() ) {
306 + return null;
307 + }
308 +
309 + return array(
310 + 'coupon' => $coupon,
311 + 'assetBaseUrl' => plugins_url( '', Jetpack_Constants::get_constant( 'JETPACK__PLUGIN_FILE' ) ),
312 + );
313 + }
314 +
315 + /**
279 316 * Decide whether the current My Jetpack request should redirect, and where to.
280 317 *
281 318 * @internal Not part of the package's public API.
282 319 *
@@ -336,9 +373,9 @@
336 373 public static function register_feature_flags() {
337 374 Feature_Flags::register(
338 375 self::FEATURES_TAB_FEATURE_FLAG,
339 376 array(
340 - 'default' => false,
377 + 'default' => true,
341 378 'description' => 'Replace the My Jetpack Products tab with a Features tab.',
342 379 'owner' => 'my-jetpack',
343 380 )
344 381 );
@@ -511,13 +548,9 @@
511 548 * @param string $build_index Path to the generated `build.php`.
512 549 * @return void
513 550 */
514 551 public static function load_wp_build( $build_index ) {
515 - // Hooked on either side of the require, so the alias holds only for the generated
516 - // enqueue check it registers at the same priority.
517 - add_action( 'admin_enqueue_scripts', array( __CLASS__, 'alias_screen_id_for_wp_build' ) );
518 - require_once $build_index;
519 - add_action( 'admin_enqueue_scripts', array( __CLASS__, 'restore_screen_id_after_wp_build' ) );
552 + self::require_wp_build_with_screen_alias( $build_index );
520 553
521 554 // wp-build hooks module registration to wp_default_scripts, which has
522 555 // already fired by admin_menu — call it directly or the init module
523 556 // never reaches the import map.
@@ -531,8 +564,33 @@
531 564 );
532 565 }
533 566
534 567 /**
568 + * Require the generated build file with the screen ID aliased across its enqueue check.
569 + *
570 + * @see WP_Build_Screen_Id::load_with_alias()
571 + * @param string $build_index Path to the generated `build.php`.
572 + * @return void
573 + */
574 + private static function require_wp_build_with_screen_alias( $build_index ) {
575 + // Fallback: an older wp-build-polyfills under the jetpack-autoloader may predate load_with_alias().
576 + if ( method_exists( WP_Build_Screen_Id::class, 'load_with_alias' ) ) {
577 + WP_Build_Screen_Id::load_with_alias(
578 + array( __CLASS__, 'alias_screen_id_for_wp_build' ),
579 + array( __CLASS__, 'restore_screen_id_after_wp_build' ),
580 + function () use ( $build_index ) {
581 + require_once $build_index;
582 + }
583 + );
584 + return;
585 + }
586 +
587 + add_action( 'admin_enqueue_scripts', array( __CLASS__, 'alias_screen_id_for_wp_build' ) );
588 + require_once $build_index;
589 + add_action( 'admin_enqueue_scripts', array( __CLASS__, 'restore_screen_id_after_wp_build' ) );
590 + }
591 +
592 + /**
535 593 * Enqueue admin page assets.
536 594 *
537 595 * @return void
538 596 */
@@ -584,8 +642,10 @@
584 642 $is_dev_version = Jetpack::is_development_version();
585 643 $sandboxed_domain = defined( 'JETPACK__SANDBOX_DOMAIN' ) ? JETPACK__SANDBOX_DOMAIN : '';
586 644 }
587 645
646 + $features_tab_enabled = self::is_features_tab_enabled();
647 +
588 648 wp_localize_script(
589 649 $data_handle,
590 650 'myJetpackInitialState',
591 651 array(
@@ -591,8 +651,10 @@
591 651 array(
592 652 'products' => array(
593 653 'items' => Products::get_products(),
594 654 ),
655 + 'mainFeatures' => $features_tab_enabled ? Main_Features::get_state() : null,
656 + 'featuresBanner' => $features_tab_enabled ? array( 'isDismissed' => REST_Main_Features::is_banner_dismissed() ) : null,
595 657 'plugins' => Plugins_Installer::get_plugins(),
596 658 'themes' => Sync_Functions::get_themes(),
597 659 'myJetpackUrl' => admin_url( 'admin.php?page=my-jetpack' ),
598 660 'myJetpackCheckoutUri' => admin_url( 'admin.php?page=my-jetpack' ),
@@ -622,8 +684,9 @@
622 684 'dismissed' => \Jetpack_Options::get_option( 'dismissed_recommendations', false ),
623 685 ),
624 686 'isStatsModuleActive' => $modules->is_active( 'stats' ),
625 687 'canUserViewStats' => current_user_can( 'manage_options' ) || current_user_can( 'view_stats' ),
688 + 'hiddenFeatures' => Feature_Visibility::get_hidden(),
626 689 'sandboxedDomain' => $sandboxed_domain,
627 690 'isDevVersion' => $is_dev_version,
628 691 'isAtomic' => ( new Status_Host() )->is_woa_site(),
629 692 'isJetpackPluginActive' => class_exists( 'Jetpack' ),
@@ -628,8 +691,9 @@
628 691 'isAtomic' => ( new Status_Host() )->is_woa_site(),
629 692 'isJetpackPluginActive' => class_exists( 'Jetpack' ),
630 693 'latestBoostSpeedScores' => $latest_score,
631 694 'seoOptIn' => self::get_seo_opt_in_state(),
695 + 'partnerCoupon' => self::get_partner_coupon_screen(),
632 696 )
633 697 );
634 698
635 699 wp_localize_script(
@@ -673,9 +737,9 @@
673 737 return $data;
674 738 }
675 739
676 740 /**
677 - * Add the package's image base URL and products tab to the admin script data.
741 + * Add My Jetpack availability, image base URL, and products tab to admin script data.
678 742 *
679 743 * Printed on every admin page by Script_Data, so the connection screen can resolve its
680 744 * illustrations and Jetpack footers can link to the products tab off the My Jetpack page.
681 745 *
@@ -684,8 +748,9 @@
684 748 * @param array $data Script data.
685 749 * @return array
686 750 */
687 751 public static function add_admin_script_data( $data ) {
752 + $data['myJetpack']['isAvailable'] = self::is_admin_page_available();
688 753 $data['myJetpack']['assetsUrl'] = self::get_assets_url();
689 754 $data['myJetpack']['productsSection'] = self::get_products_section();
690 755
691 756 return $data;
@@ -691,8 +756,25 @@
691 756 return $data;
692 757 }
693 758
694 759 /**
760 + * Whether My Jetpack's admin page is available to the current user.
761 + *
762 + * Meaningful only after admin_menu has registered the page.
763 + *
764 + * @since 6.5.0
765 + *
766 + * @return bool
767 + */
768 + public static function is_admin_page_available() {
769 + global $_registered_pages;
770 +
771 + return did_action( 'my_jetpack_init' ) > 0
772 + && isset( $_registered_pages[ get_plugin_page_hookname( 'my-jetpack', 'jetpack' ) ] )
773 + && current_user_can( 'edit_posts' );
774 + }
775 +
776 + /**
695 777 * Get the base URL of the package's built images, with a trailing slash.
696 778 *
697 779 * @since 6.3.0
698 780 *
@@ -792,9 +874,9 @@
792 874 */
793 875 public static function get_my_jetpack_flags() {
794 876 $flags = array(
795 877 'videoPressStats' => Jetpack_Constants::is_true( 'JETPACK_MY_JETPACK_VIDEOPRESS_STATS_ENABLED' ),
796 - 'showFullJetpackStatsCard' => class_exists( 'Jetpack' ),
878 + 'showFullJetpackStatsCard' => class_exists( 'Jetpack' ) || Products\Stats::is_standalone_plugin_active(),
797 879 // Only says which destination `manage_url` is: the legacy Stats page
798 880 // caches its report and wants a `force_refresh` hint the dashboard does not.
799 881 'premiumAnalyticsEnabled' => Products\Stats::is_premium_analytics_enabled(),
800 882 'showAiModuleToggle' => Products\Jetpack_Ai::is_feature_ui_enabled(),
@@ -868,11 +950,14 @@
868 950 */
869 951 public static function register_rest_endpoints() {
870 952 new REST_Products();
871 953 new REST_Purchases();
872 - new REST_Zendesk_Chat();
873 954 ( new REST_Jetpack_AI_JWT() )->register_rest_route();
874 955 new REST_Recommendations_Evaluation();
956 +
957 + if ( self::is_features_tab_enabled() ) {
958 + ( new REST_Main_Features() )->register_rest_routes();
959 + }
875 960
876 961 Products::register_product_endpoints();
877 962 Historically_Active_Modules::register_rest_endpoints();
878 963 Jetpack_Manage::register_rest_endpoints();