| @@ -6,20 +6,19 @@ | ||
| 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 | -use Automattic\Jetpack\Assets\Logo as Jetpack_Logo; | |
| 12 | 12 | use Automattic\Jetpack\Boost_Speed_Score\Speed_Score; |
| 13 | 13 | use Automattic\Jetpack\Config; |
| 14 | +use Automattic\Jetpack\Connection\Authorize_Json_Api; | |
| 14 | 15 | use Automattic\Jetpack\Connection\Client; |
| 15 | -use Automattic\Jetpack\Connection\Initial_State as Connection_Initial_State; | |
| 16 | 16 | use Automattic\Jetpack\Connection\Manager as Connection_Manager; |
| 17 | -use Automattic\Jetpack\Connection\Nonce_Handler; | |
| 18 | 17 | use Automattic\Jetpack\Connection\Rest_Authentication as Connection_Rest_Authentication; |
| 19 | 18 | use Automattic\Jetpack\Connection\Secrets; |
| 20 | 19 | use Automattic\Jetpack\Connection\Tokens; |
| 21 | -use Automattic\Jetpack\Connection\Utils as Connection_Utils; | |
| 20 | +use Automattic\Jetpack\Connection\Webhooks\Authorize_Redirect; | |
| 22 | 21 | use Automattic\Jetpack\Constants; |
| 23 | 22 | use Automattic\Jetpack\CookieState; |
| 24 | 23 | use Automattic\Jetpack\Current_Plan as Jetpack_Plan; |
| 25 | 24 | use Automattic\Jetpack\Device_Detection\User_Agent_Info; |
| @@ -24,16 +23,22 @@ | ||
| 24 | 23 | use Automattic\Jetpack\Current_Plan as Jetpack_Plan; |
| 25 | 24 | use Automattic\Jetpack\Device_Detection\User_Agent_Info; |
| 26 | 25 | use Automattic\Jetpack\Errors; |
| 27 | 26 | use Automattic\Jetpack\Files; |
| 27 | +use Automattic\Jetpack\Heartbeat; | |
| 28 | 28 | use Automattic\Jetpack\Identity_Crisis; |
| 29 | +use Automattic\Jetpack\Import\Main as Import_Main; | |
| 29 | 30 | use Automattic\Jetpack\Licensing; |
| 30 | 31 | use Automattic\Jetpack\Modules; |
| 31 | 32 | use Automattic\Jetpack\My_Jetpack\Initializer as My_Jetpack_Initializer; |
| 32 | -use Automattic\Jetpack\Partner; | |
| 33 | +use Automattic\Jetpack\Newsletter\Reader_Link; | |
| 33 | 34 | use Automattic\Jetpack\Paths; |
| 35 | +use Automattic\Jetpack\Plugin\Deprecate; | |
| 34 | 36 | use Automattic\Jetpack\Plugin\Tracking as Plugin_Tracking; |
| 37 | +use Automattic\Jetpack\Podcast\Podcast; | |
| 35 | 38 | use Automattic\Jetpack\Redirect; |
| 39 | +use Automattic\Jetpack\Scan_Page\Jetpack_Scan as Scan_Page_Init; | |
| 40 | +use Automattic\Jetpack\SEO\Initializer as Jetpack_SEO_Initializer; | |
| 36 | 41 | use Automattic\Jetpack\Status; |
| 37 | 42 | use Automattic\Jetpack\Status\Host; |
| 38 | 43 | use Automattic\Jetpack\Status\Visitor; |
| 39 | 44 | use Automattic\Jetpack\Sync\Actions as Sync_Actions; |
| @@ -40,9 +45,14 @@ | ||
| 40 | 45 | use Automattic\Jetpack\Sync\Health; |
| 41 | 46 | use Automattic\Jetpack\Sync\Sender; |
| 42 | 47 | use Automattic\Jetpack\Terms_Of_Service; |
| 43 | 48 | use Automattic\Jetpack\Tracking; |
| 49 | +use Automattic\Woocommerce_Analytics; | |
| 44 | 50 | |
| 51 | +if ( ! defined( 'ABSPATH' ) ) { | |
| 52 | + exit( 0 ); | |
| 53 | +} | |
| 54 | + | |
| 45 | 55 | /* |
| 46 | 56 | Options: |
| 47 | 57 | jetpack_options (array) |
| 48 | 58 | An array of options. |
| @@ -70,54 +80,25 @@ | ||
| 70 | 80 | * The Jetpack class. |
| 71 | 81 | */ |
| 72 | 82 | class Jetpack { |
| 73 | 83 | /** |
| 74 | - * XMLRPC server instance. | |
| 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. | |
| 75 | 86 | * |
| 76 | - * @var null|Jetpack_XMLRPC_Server XMLRPC server used by Jetpack. | |
| 87 | + * {@see self::reconcile_seo_module_state_options()} | |
| 88 | + * | |
| 89 | + * @since 16.1 | |
| 90 | + * | |
| 91 | + * @var string | |
| 77 | 92 | */ |
| 78 | - public $xmlrpc_server = null; | |
| 93 | + const SEO_MODULE_STATE_RECONCILED_OPTION = 'jetpack_seo_module_state_reconciled'; | |
| 79 | 94 | |
| 80 | 95 | /** |
| 81 | - * The handles of styles that are concatenated into jetpack.css. | |
| 96 | + * XMLRPC server instance. | |
| 82 | 97 | * |
| 83 | - * When making changes to that list, you must also update concat_list in tools/webpack.config.css.js. | |
| 84 | - * | |
| 85 | - * @var array The handles of styles that are concatenated into jetpack.css. | |
| 98 | + * @var null|Jetpack_XMLRPC_Server XMLRPC server used by Jetpack. | |
| 86 | 99 | */ |
| 87 | - public $concatenated_style_handles = array( | |
| 88 | - 'jetpack-carousel-swiper-css', | |
| 89 | - 'jetpack-carousel', | |
| 90 | - 'grunion.css', | |
| 91 | - 'the-neverending-homepage', | |
| 92 | - 'jetpack_likes', | |
| 93 | - 'jetpack_related-posts', | |
| 94 | - 'sharedaddy', | |
| 95 | - 'jetpack-slideshow', | |
| 96 | - 'presentations', | |
| 97 | - 'quiz', | |
| 98 | - 'jetpack-subscriptions', | |
| 99 | - 'jetpack-responsive-videos', | |
| 100 | - 'jetpack-social-menu', | |
| 101 | - 'tiled-gallery', | |
| 102 | - 'jetpack_display_posts_widget', | |
| 103 | - 'gravatar-profile-widget', | |
| 104 | - 'goodreads-widget', | |
| 105 | - 'jetpack_social_media_icons_widget', | |
| 106 | - 'jetpack-top-posts-widget', | |
| 107 | - 'jetpack_image_widget', | |
| 108 | - 'jetpack-my-community-widget', | |
| 109 | - 'jetpack-authors-widget', | |
| 110 | - 'wordads', | |
| 111 | - 'eu-cookie-law-style', | |
| 112 | - 'flickr-widget-style', | |
| 113 | - 'jetpack-search-widget', | |
| 114 | - 'jetpack-simple-payments-widget-style', | |
| 115 | - 'jetpack-widget-social-icons-styles', | |
| 116 | - 'wpcom_instagram_widget', | |
| 117 | - 'milestone-widget', | |
| 118 | - 'subscribe-modal-css', | |
| 119 | - ); | |
| 100 | + public $xmlrpc_server = null; | |
| 120 | 101 | |
| 121 | 102 | /** |
| 122 | 103 | * Contains all assets that have had their URL rewritten to minified versions. |
| 123 | 104 | * |
| @@ -134,11 +115,8 @@ | ||
| 134 | 115 | 'contact-form' => array( |
| 135 | 116 | array( 'grunion-contact-form/grunion-contact-form.php', 'Grunion Contact Form' ), |
| 136 | 117 | array( 'mullet/mullet-contact-form.php', 'Mullet Contact Form' ), |
| 137 | 118 | ), |
| 138 | - 'custom-css' => array( | |
| 139 | - array( 'safecss/safecss.php', 'WordPress.com Custom CSS' ), | |
| 140 | - ), | |
| 141 | 119 | 'gravatar-hovercards' => array( |
| 142 | 120 | array( 'jetpack-gravatar-hovercards/gravatar-hovercards.php', 'Jetpack Gravatar Hovercards' ), |
| 143 | 121 | ), |
| 144 | 122 | 'latex' => array( |
| @@ -299,13 +277,8 @@ | ||
| 299 | 277 | 'MSM Sitemaps' => 'msm-sitemap/msm-sitemap.php', |
| 300 | 278 | 'Rank Math' => 'seo-by-rank-math/rank-math.php', |
| 301 | 279 | 'Slim SEO' => 'slim-seo/slim-seo.php', |
| 302 | 280 | ), |
| 303 | - 'lazy-images' => array( | |
| 304 | - 'Lazy Load' => 'lazy-load/lazy-load.php', | |
| 305 | - 'BJ Lazy Load' => 'bj-lazy-load/bj-lazy-load.php', | |
| 306 | - 'Lazy Load by WP Rocket' => 'rocket-lazy-load/rocket-lazy-load.php', | |
| 307 | - ), | |
| 308 | 281 | ); |
| 309 | 282 | |
| 310 | 283 | /** |
| 311 | 284 | * Plugins for which we turn off our Facebook OG Tags implementation. |
| @@ -314,9 +287,8 @@ | ||
| 314 | 287 | * Graph tags via filter when their Social Meta modules are active: |
| 315 | 288 | * |
| 316 | 289 | * - All in One SEO Pack, All in one SEO Pack Pro |
| 317 | 290 | * - WordPress SEO by Yoast, WordPress SEO Premium by Yoast |
| 318 | - * - SEOPress, SEOPress Pro | |
| 319 | 291 | * |
| 320 | 292 | * Plugin authors: If you'd like to prevent Jetpack's Open Graph tag generation in your plugin, you can do so via this filter: |
| 321 | 293 | * add_filter( 'jetpack_enable_open_graph', '__return_false' ); |
| 322 | 294 | * |
| @@ -359,8 +331,10 @@ | ||
| 359 | 331 | 'wp-caregiver/wp-caregiver.php', // WP Caregiver. |
| 360 | 332 | 'wp-facebook-like-send-open-graph-meta/wp-facebook-like-send-open-graph-meta.php', // WP Facebook Like Send & Open Graph Meta. |
| 361 | 333 | 'wp-facebook-open-graph-protocol/wp-facebook-ogp.php', // WP Facebook Open Graph protocol. |
| 362 | 334 | 'wp-ogp/wp-ogp.php', // WP-OGP. |
| 335 | + 'wp-seopress/seopress.php', // SEOPress. | |
| 336 | + 'wp-seopress-pro/seopress-pro.php', // SEOPress Pro. | |
| 363 | 337 | 'zoltonorg-social-plugin/zosp.php', // Zolton.org Social Plugin. |
| 364 | 338 | 'wp-fb-share-like-button/wp_fb_share-like_widget.php', // WP Facebook Like Button. |
| 365 | 339 | 'open-graph-metabox/open-graph-metabox.php', // Open Graph Metabox. |
| 366 | 340 | 'seo-by-rank-math/rank-math.php', // Rank Math. |
| @@ -427,8 +401,10 @@ | ||
| 427 | 401 | |
| 428 | 402 | /** |
| 429 | 403 | * Verified data for JSON authorization request |
| 430 | 404 | * |
| 405 | + * @deprecated 13.4 | |
| 406 | + * | |
| 431 | 407 | * @var array |
| 432 | 408 | */ |
| 433 | 409 | public $json_api_authorization_request = array(); |
| 434 | 410 | |
| @@ -469,8 +445,16 @@ | ||
| 469 | 445 | */ |
| 470 | 446 | public static $instance = false; |
| 471 | 447 | |
| 472 | 448 | /** |
| 449 | + * Resolved answer for `is_premium_analytics_enabled()`, or null before the first call. | |
| 450 | + * | |
| 451 | + * @since 16.1 | |
| 452 | + * @var bool|null | |
| 453 | + */ | |
| 454 | + private static $premium_analytics_enabled = null; | |
| 455 | + | |
| 456 | + /** | |
| 473 | 457 | * Singleton |
| 474 | 458 | * |
| 475 | 459 | * @static |
| 476 | 460 | */ |
| @@ -510,9 +494,9 @@ | ||
| 510 | 494 | if ( array_diff( $unfiltered_modules, $modules ) ) { |
| 511 | 495 | self::update_active_modules( $modules ); |
| 512 | 496 | } |
| 513 | 497 | |
| 514 | - add_action( 'init', array( __CLASS__, 'activate_new_modules' ) ); | |
| 498 | + self::register_upgrade_init_hooks(); | |
| 515 | 499 | |
| 516 | 500 | // Upgrade to 4.3.0. |
| 517 | 501 | if ( Jetpack_Options::get_option( 'identity_crisis_whitelist' ) ) { |
| 518 | 502 | Jetpack_Options::delete_option( 'identity_crisis_whitelist' ); |
| @@ -567,8 +551,13 @@ | ||
| 567 | 551 | Jetpack_Options::delete_option( 'autoupdate_plugins' ); |
| 568 | 552 | } // Should we have some type of fallback if something fails here? |
| 569 | 553 | } |
| 570 | 554 | |
| 555 | + // Set the newsletter send default option for existing sites. | |
| 556 | + if ( false === get_option( 'wpcom_newsletter_send_default' ) ) { | |
| 557 | + add_option( 'wpcom_newsletter_send_default', 1 ); | |
| 558 | + } | |
| 559 | + | |
| 571 | 560 | if ( did_action( 'wp_loaded' ) ) { |
| 572 | 561 | self::upgrade_on_load(); |
| 573 | 562 | } else { |
| 574 | 563 | add_action( |
| @@ -602,9 +591,8 @@ | ||
| 602 | 591 | } |
| 603 | 592 | |
| 604 | 593 | if ( |
| 605 | 594 | class_exists( 'Jetpack_Sitemap_Manager' ) |
| 606 | - && version_compare( JETPACK__VERSION, '5.3', '>=' ) | |
| 607 | 595 | ) { |
| 608 | 596 | do_action( 'jetpack_sitemaps_purge_data' ); |
| 609 | 597 | } |
| 610 | 598 | |
| @@ -619,9 +607,9 @@ | ||
| 619 | 607 | * Also fires Action hooks for each newly activated and deactivated module. |
| 620 | 608 | * |
| 621 | 609 | * @param array $modules Array of active modules to be saved in options. |
| 622 | 610 | * |
| 623 | - * @return $success bool true for success, false for failure. | |
| 611 | + * @return bool $success true for success, false for failure. | |
| 624 | 612 | */ |
| 625 | 613 | public static function update_active_modules( $modules ) { |
| 626 | 614 | return ( new Modules() )->update_active( $modules ); |
| 627 | 615 | } |
| @@ -651,10 +639,10 @@ | ||
| 651 | 639 | sort( $taken_priorities ); |
| 652 | 640 | |
| 653 | 641 | $first_priority = array_shift( $taken_priorities ); |
| 654 | 642 | |
| 655 | - if ( defined( 'PHP_INT_MAX' ) && $first_priority <= - PHP_INT_MAX ) { | |
| 656 | - $new_priority = - PHP_INT_MAX; | |
| 643 | + if ( $first_priority <= PHP_INT_MIN ) { | |
| 644 | + $new_priority = PHP_INT_MIN; | |
| 657 | 645 | } else { |
| 658 | 646 | $new_priority = $first_priority - 1; |
| 659 | 647 | } |
| 660 | 648 | |
| @@ -675,32 +663,17 @@ | ||
| 675 | 663 | add_action( 'network_plugin_loaded', array( $this, 'add_configure_hook' ), 90 ); |
| 676 | 664 | add_action( 'mu_plugin_loaded', array( $this, 'add_configure_hook' ), 90 ); |
| 677 | 665 | add_action( 'plugins_loaded', array( $this, 'late_initialization' ), 90 ); |
| 678 | 666 | |
| 679 | - add_action( 'jetpack_verify_signature_error', array( $this, 'track_xmlrpc_error' ) ); | |
| 680 | - | |
| 681 | - add_filter( | |
| 682 | - 'jetpack_signature_check_token', | |
| 683 | - array( __CLASS__, 'verify_onboarding_token' ), | |
| 684 | - 10, | |
| 685 | - 3 | |
| 686 | - ); | |
| 687 | - | |
| 688 | 667 | /** |
| 689 | 668 | * Prepare Gutenberg Editor functionality |
| 669 | + * | |
| 670 | + * The hooks previously here have been moved to modules/blocks.php but leaving this here pending | |
| 671 | + * a longer investigation to see if code is expecting the Gutenberg class to always be available. | |
| 690 | 672 | */ |
| 691 | 673 | require_once JETPACK__PLUGIN_DIR . 'class.jetpack-gutenberg.php'; |
| 692 | - add_action( 'plugins_loaded', array( 'Jetpack_Gutenberg', 'load_independent_blocks' ) ); | |
| 693 | - add_action( 'plugins_loaded', array( 'Jetpack_Gutenberg', 'load_block_editor_extensions' ), 9 ); | |
| 694 | - add_action( 'enqueue_block_editor_assets', array( 'Jetpack_Gutenberg', 'enqueue_block_editor_assets' ) ); | |
| 695 | - add_filter( 'render_block', array( 'Jetpack_Gutenberg', 'display_deprecated_block_message' ), 10, 2 ); | |
| 696 | - | |
| 697 | 674 | add_action( 'set_user_role', array( $this, 'maybe_clear_other_linked_admins_transient' ), 10, 3 ); |
| 698 | 675 | |
| 699 | - // Unlink user before deleting the user from WP.com. | |
| 700 | - add_action( 'deleted_user', array( $this, 'disconnect_user' ), 10, 1 ); | |
| 701 | - add_action( 'remove_user_from_blog', array( $this, 'disconnect_user' ), 10, 1 ); | |
| 702 | - | |
| 703 | 676 | add_action( 'jetpack_event_log', array( 'Jetpack', 'log' ), 10, 2 ); |
| 704 | 677 | |
| 705 | 678 | add_filter( 'login_url', array( $this, 'login_url' ), 10, 2 ); |
| 706 | 679 | add_action( 'login_init', array( $this, 'login_init' ) ); |
| @@ -707,8 +680,13 @@ | ||
| 707 | 680 | |
| 708 | 681 | // Set up the REST authentication hooks. |
| 709 | 682 | Connection_Rest_Authentication::init(); |
| 710 | 683 | |
| 684 | + // Register Jetpack-specific connection tests (sync health, etc.) with the connection | |
| 685 | + // package's health test suite. This runs on all requests (not just admin), because | |
| 686 | + // the connection/test REST endpoint can be called outside admin context. | |
| 687 | + add_action( 'jetpack_connection_tests_loaded', array( $this, 'register_jetpack_connection_tests' ) ); | |
| 688 | + | |
| 711 | 689 | add_action( 'admin_init', array( $this, 'admin_init' ) ); |
| 712 | 690 | add_action( 'admin_init', array( $this, 'dismiss_jetpack_notice' ) ); |
| 713 | 691 | |
| 714 | 692 | add_filter( 'admin_body_class', array( $this, 'admin_body_class' ), 20 ); |
| @@ -722,12 +700,8 @@ | ||
| 722 | 700 | |
| 723 | 701 | // Returns HTTPS support status. |
| 724 | 702 | add_action( 'wp_ajax_jetpack-recheck-ssl', array( $this, 'ajax_recheck_ssl' ) ); |
| 725 | 703 | |
| 726 | - add_action( 'wp_ajax_jetpack_connection_banner', array( $this, 'jetpack_connection_banner_callback' ) ); | |
| 727 | - | |
| 728 | - add_action( 'wp_ajax_jetpack_recommendations_banner', array( 'Jetpack_Recommendations_Banner', 'ajax_callback' ) ); | |
| 729 | - | |
| 730 | 704 | add_action( 'wp_loaded', array( $this, 'register_assets' ) ); |
| 731 | 705 | |
| 732 | 706 | /** |
| 733 | 707 | * These actions run checks to load additional files. |
| @@ -745,29 +719,8 @@ | ||
| 745 | 719 | |
| 746 | 720 | add_filter( 'jetpack_get_default_modules', array( $this, 'filter_default_modules' ) ); |
| 747 | 721 | add_filter( 'jetpack_get_default_modules', array( $this, 'handle_deprecated_modules' ), 99 ); |
| 748 | 722 | |
| 749 | - require_once JETPACK__PLUGIN_DIR . 'class-jetpack-pre-connection-jitms.php'; | |
| 750 | - $jetpack_jitm_messages = ( new Jetpack_Pre_Connection_JITMs() ); | |
| 751 | - add_filter( 'jetpack_pre_connection_jitms', array( $jetpack_jitm_messages, 'add_pre_connection_jitms' ) ); | |
| 752 | - | |
| 753 | - /* | |
| 754 | - * If enabled, point edit post, page, and comment links to Calypso instead of WP-Admin. | |
| 755 | - * We should make sure to only do this for front end links. | |
| 756 | - */ | |
| 757 | - if ( self::get_option( 'edit_links_calypso_redirect' ) && ! is_admin() ) { | |
| 758 | - add_filter( 'get_edit_post_link', array( $this, 'point_edit_post_links_to_calypso' ), 1, 2 ); | |
| 759 | - add_filter( 'get_edit_comment_link', array( $this, 'point_edit_comment_links_to_calypso' ), 1 ); | |
| 760 | - | |
| 761 | - /* | |
| 762 | - * We'll shortcircuit wp_notify_postauthor and wp_notify_moderator pluggable functions | |
| 763 | - * so they point moderation links on emails to Calypso. | |
| 764 | - */ | |
| 765 | - require_once JETPACK__PLUGIN_DIR . '_inc/lib/functions.wp-notify.php'; | |
| 766 | - add_filter( 'comment_notification_recipients', 'jetpack_notify_postauthor', 1, 2 ); | |
| 767 | - add_filter( 'notify_moderator', 'jetpack_notify_moderator', 1, 2 ); | |
| 768 | - } | |
| 769 | - | |
| 770 | 723 | add_action( |
| 771 | 724 | 'plugins_loaded', |
| 772 | 725 | function () { |
| 773 | 726 | if ( User_Agent_Info::is_mobile_app() ) { |
| @@ -778,18 +731,10 @@ | ||
| 778 | 731 | |
| 779 | 732 | // Update the site's Jetpack plan and products from API on heartbeats. |
| 780 | 733 | add_action( 'jetpack_heartbeat', array( Jetpack_Plan::class, 'refresh_from_wpcom' ) ); |
| 781 | 734 | |
| 782 | - /** | |
| 783 | - * This is the hack to concatenate all css files into one. | |
| 784 | - * For description and reasoning see the implode_frontend_css method. | |
| 785 | - * | |
| 786 | - * Super late priority so we catch all the registered styles. | |
| 787 | - */ | |
| 788 | - if ( ! is_admin() ) { | |
| 789 | - add_action( 'wp_print_styles', array( $this, 'implode_frontend_css' ), -1 ); // Run first. | |
| 790 | - add_action( 'wp_print_footer_scripts', array( $this, 'implode_frontend_css' ), -1 ); // Run first to trigger before `print_late_styles`. | |
| 791 | - } | |
| 735 | + // The Connection package fetches the site record for `jetpack/v4/site`; reuse it to refresh the plan. | |
| 736 | + add_action( 'jetpack_site_data_fetched', array( Jetpack_Plan::class, 'update_from_site_record' ) ); | |
| 792 | 737 | |
| 793 | 738 | // Actually push the stats on shutdown. |
| 794 | 739 | if ( ! has_action( 'shutdown', array( $this, 'push_stats' ) ) ) { |
| 795 | 740 | add_action( 'shutdown', array( $this, 'push_stats' ) ); |
| @@ -797,8 +742,10 @@ | ||
| 797 | 742 | |
| 798 | 743 | // After a successful connection. |
| 799 | 744 | add_action( 'jetpack_site_registered', array( $this, 'activate_default_modules_on_site_register' ) ); |
| 800 | 745 | add_action( 'jetpack_site_registered', array( $this, 'handle_unique_registrations_stats' ) ); |
| 746 | + add_action( 'jetpack_site_registered', array( Reader_Link::class, 'activate_on_connection' ), 9 ); | |
| 747 | + add_action( 'jetpack_site_registered', array( \Automattic\Jetpack\Reprint_Export\Reprint_Exporter::class, 'discard_credentials' ) ); | |
| 801 | 748 | |
| 802 | 749 | // Actions for Manager::authorize(). |
| 803 | 750 | add_action( 'jetpack_authorize_starting', array( $this, 'authorize_starting' ) ); |
| 804 | 751 | add_action( 'jetpack_authorize_ending_linked', array( $this, 'authorize_ending_linked' ) ); |
| @@ -803,8 +750,9 @@ | ||
| 803 | 750 | add_action( 'jetpack_authorize_starting', array( $this, 'authorize_starting' ) ); |
| 804 | 751 | add_action( 'jetpack_authorize_ending_linked', array( $this, 'authorize_ending_linked' ) ); |
| 805 | 752 | add_action( 'jetpack_authorize_ending_authorized', array( $this, 'authorize_ending_authorized' ) ); |
| 806 | 753 | |
| 754 | + Jetpack_Client_Server::init(); | |
| 807 | 755 | add_action( 'jetpack_client_authorize_error', array( Jetpack_Client_Server::class, 'client_authorize_error' ) ); |
| 808 | 756 | add_filter( 'jetpack_client_authorize_already_authorized_url', array( Jetpack_Client_Server::class, 'client_authorize_already_authorized_url' ) ); |
| 809 | 757 | add_action( 'jetpack_client_authorize_processing', array( Jetpack_Client_Server::class, 'client_authorize_processing' ) ); |
| 810 | 758 | add_filter( 'jetpack_client_authorize_fallback_url', array( Jetpack_Client_Server::class, 'client_authorize_fallback_url' ) ); |
| @@ -809,9 +757,9 @@ | ||
| 809 | 757 | add_action( 'jetpack_client_authorize_processing', array( Jetpack_Client_Server::class, 'client_authorize_processing' ) ); |
| 810 | 758 | add_filter( 'jetpack_client_authorize_fallback_url', array( Jetpack_Client_Server::class, 'client_authorize_fallback_url' ) ); |
| 811 | 759 | |
| 812 | 760 | // Filters for the Manager::get_token() urls and request body. |
| 813 | - add_filter( 'jetpack_token_redirect_url', array( __CLASS__, 'filter_connect_redirect_url' ) ); | |
| 761 | + add_filter( 'jetpack_token_redirect_url', array( Authorize_Redirect::class, 'filter_connect_redirect_url' ) ); | |
| 814 | 762 | add_filter( 'jetpack_token_request_body', array( __CLASS__, 'filter_token_request_body' ) ); |
| 815 | 763 | |
| 816 | 764 | // Filter for the `jetpack/v4/connection/data` API response. |
| 817 | 765 | add_filter( 'jetpack_current_user_connection_data', array( __CLASS__, 'filter_jetpack_current_user_connection_data' ) ); |
| @@ -832,9 +780,9 @@ | ||
| 832 | 780 | // Make resources use static domain when possible. |
| 833 | 781 | add_filter( 'jetpack_static_url', array( 'Automattic\\Jetpack\\Assets', 'staticize_subdomain' ) ); |
| 834 | 782 | |
| 835 | 783 | // Validate the domain names in Jetpack development versions. |
| 836 | - add_action( 'jetpack_pre_register', array( get_called_class(), 'registration_check_domains' ) ); | |
| 784 | + add_action( 'jetpack_pre_register', array( static::class, 'registration_check_domains' ) ); | |
| 837 | 785 | |
| 838 | 786 | // Register product descriptions for partner coupon usage. |
| 839 | 787 | add_filter( 'jetpack_partner_coupon_products', array( $this, 'get_partner_coupon_product_descriptions' ) ); |
| 840 | 788 | |
| @@ -839,11 +787,143 @@ | ||
| 839 | 787 | add_filter( 'jetpack_partner_coupon_products', array( $this, 'get_partner_coupon_product_descriptions' ) ); |
| 840 | 788 | |
| 841 | 789 | // Actions for conditional recommendations. |
| 842 | 790 | add_action( 'plugins_loaded', array( 'Jetpack_Recommendations', 'init_conditional_recommendation_actions' ) ); |
| 791 | + | |
| 792 | + // Add 5-star | |
| 793 | + add_filter( 'plugin_row_meta', array( $this, 'add_5_star_review_link' ), 10, 2 ); | |
| 794 | + add_action( 'init', array( Deprecate::class, 'instance' ) ); | |
| 795 | + | |
| 796 | + // Register Jetpack module management abilities (WordPress Abilities API, WP 6.9+). | |
| 797 | + \Automattic\Jetpack\Plugin\Abilities\Modules_Abilities::init(); | |
| 798 | + | |
| 799 | + // Register Connection abilities (WordPress Abilities API, WP 6.9+). Scoped to the | |
| 800 | + // Jetpack plugin for now: the Connection package no longer auto-wires these, so | |
| 801 | + // connection-only consumers (Boost, Protect, Search, etc.) do not register them yet. | |
| 802 | + \Automattic\Jetpack\Connection\Abilities\Connection_Abilities::init(); | |
| 843 | 803 | } |
| 844 | 804 | |
| 845 | 805 | /** |
| 806 | + * Whether the current request should eagerly initialize the admin/REST-only | |
| 807 | + * packages (the Import package and My Jetpack) now, at `plugins_loaded` time. | |
| 808 | + * | |
| 809 | + * Returns true for admin, cron, POST, and WP-CLI requests — the contexts, | |
| 810 | + * knowable this early, where those packages have work to do. Returns false | |
| 811 | + * for a plain front-end GET *and* for a REST request: the two can't be told | |
| 812 | + * apart yet (this runs before `rest_api_init`), so callers defer the REST | |
| 813 | + * case by initializing the package on `rest_api_init` instead, while a plain | |
| 814 | + * page view never fires that hook and so loads nothing. This keeps | |
| 815 | + * admin/REST-only PHP out of opcache on the front-end GET hot path. | |
| 816 | + * | |
| 817 | + * No in-repo code depends on the deferral. The one externally observable | |
| 818 | + * change is timing: the packages' documented init hooks | |
| 819 | + * (`jetpack_import_initialized`, `jetpack_feature_import_enabled`, and | |
| 820 | + * `my_jetpack_init`) no longer fire on a plain front-end GET — they fire on | |
| 821 | + * the admin, cron, POST, WP-CLI, and REST requests where the packages load. | |
| 822 | + * | |
| 823 | + * @return bool | |
| 824 | + */ | |
| 825 | + private static function should_eager_load_packages() { | |
| 826 | + $is_post_request = isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' === strtoupper( sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) ); | |
| 827 | + $is_wp_cli = Constants::is_true( 'WP_CLI' ); | |
| 828 | + | |
| 829 | + return is_admin() || wp_doing_cron() || $is_post_request || $is_wp_cli; | |
| 830 | + } | |
| 831 | + | |
| 832 | + /** | |
| 833 | + * Configure the Import package from a deferred hook. | |
| 834 | + * | |
| 835 | + * The eager path uses Config::ensure( 'import' ), but the deferred REST path | |
| 836 | + * runs after Config::on_plugins_loaded() has already processed its feature | |
| 837 | + * flags, so it needs a hookable bootstrap callback. Preserve Config's | |
| 838 | + * feature-enabled action for hook consumers. | |
| 839 | + * | |
| 840 | + * @since 16.0 | |
| 841 | + * | |
| 842 | + * @return void | |
| 843 | + */ | |
| 844 | + public static function configure_import_package() { | |
| 845 | + if ( class_exists( Import_Main::class ) ) { | |
| 846 | + Import_Main::configure(); | |
| 847 | + | |
| 848 | + if ( ! did_action( 'jetpack_feature_import_enabled' ) ) { | |
| 849 | + do_action( 'jetpack_feature_import_enabled' ); | |
| 850 | + } | |
| 851 | + } | |
| 852 | + } | |
| 853 | + | |
| 854 | + /** | |
| 855 | + * Whether the bundled Stats v2 dashboard is enabled. | |
| 856 | + * | |
| 857 | + * Stats v2 (formerly "Premium Analytics") ships with the plugin behind this | |
| 858 | + * flag while it rolls out (WOOA7S-1595). When enabled it adds its own admin | |
| 859 | + * menu alongside the existing Stats UI; it never replaces or hides the | |
| 860 | + * legacy Stats menu, admin-bar entries, post-list column, or WP dashboard | |
| 861 | + * widget. The Stats module's tracking is unaffected either way, and Stats v2 | |
| 862 | + * reads what that module collects, so while the module is off the plugin | |
| 863 | + * answers false here before even reading the flag. | |
| 864 | + * | |
| 865 | + * The package has to be loadable for this to be true, so a site with the | |
| 866 | + * flag on but a missing package answers false here and never adds the | |
| 867 | + * Stats v2 menu (a warning is logged instead). | |
| 868 | + * | |
| 869 | + * @since 16.1 | |
| 870 | + * | |
| 871 | + * @return bool | |
| 872 | + */ | |
| 873 | + public static function is_premium_analytics_enabled() { | |
| 874 | + if ( null !== self::$premium_analytics_enabled ) { | |
| 875 | + return self::$premium_analytics_enabled; | |
| 876 | + } | |
| 877 | + | |
| 878 | + if ( ! self::is_module_active( 'stats' ) ) { | |
| 879 | + self::$premium_analytics_enabled = false; | |
| 880 | + return false; | |
| 881 | + } | |
| 882 | + | |
| 883 | + /** | |
| 884 | + * Filters whether the bundled Premium Analytics dashboard is enabled. | |
| 885 | + * | |
| 886 | + * Resolved once, from `Jetpack::configure()` on `plugins_loaded`, and only | |
| 887 | + * while the Stats module is active. Register this from a mu-plugin or a | |
| 888 | + * plugin's main file — a callback added on `plugins_loaded` or later runs | |
| 889 | + * too late to be seen. | |
| 890 | + * | |
| 891 | + * @since 16.1 | |
| 892 | + * | |
| 893 | + * @param bool $enabled Defaults to the `jetpack_premium_analytics_enabled` option (false). | |
| 894 | + */ | |
| 895 | + $flag = (bool) apply_filters( 'jetpack_premium_analytics_enabled', (bool) get_option( 'jetpack_premium_analytics_enabled' ) ); | |
| 896 | + | |
| 897 | + self::$premium_analytics_enabled = $flag && class_exists( 'Automattic\Jetpack\PremiumAnalytics\Analytics' ); | |
| 898 | + | |
| 899 | + if ( $flag && ! self::$premium_analytics_enabled ) { | |
| 900 | + wp_trigger_error( | |
| 901 | + __METHOD__, | |
| 902 | + 'The jetpack_premium_analytics_enabled flag is on but the Premium Analytics package is not loadable; keeping the Stats UI in place.' | |
| 903 | + ); | |
| 904 | + } | |
| 905 | + | |
| 906 | + return self::$premium_analytics_enabled; | |
| 907 | + } | |
| 908 | + | |
| 909 | + /** | |
| 910 | + * Expose the setting that turns the Premium Analytics dashboard on and off. | |
| 911 | + * | |
| 912 | + * Deliberately not behind is_premium_analytics_enabled(): this is the setting that flips that | |
| 913 | + * check, so it has to answer while the dashboard is still off. | |
| 914 | + * | |
| 915 | + * @since 16.2 | |
| 916 | + * | |
| 917 | + * @return void | |
| 918 | + */ | |
| 919 | + public static function register_premium_analytics_enablement_setting() { | |
| 920 | + if ( class_exists( 'Automattic\Jetpack\PremiumAnalytics\Enablement_Setting' ) ) { | |
| 921 | + \Automattic\Jetpack\PremiumAnalytics\Enablement_Setting::register(); | |
| 922 | + } | |
| 923 | + } | |
| 924 | + | |
| 925 | + /** | |
| 846 | 926 | * Before everything else starts getting initalized, we need to initialize Jetpack using the |
| 847 | 927 | * Config object. |
| 848 | 928 | */ |
| 849 | 929 | public function configure() { |
| @@ -852,13 +932,10 @@ | ||
| 852 | 932 | foreach ( |
| 853 | 933 | array( |
| 854 | 934 | 'jitm', |
| 855 | 935 | 'sync', |
| 936 | + 'account_protection', | |
| 856 | 937 | 'waf', |
| 857 | - 'videopress', | |
| 858 | - 'stats', | |
| 859 | - 'stats_admin', | |
| 860 | - 'import', | |
| 861 | 938 | ) |
| 862 | 939 | as $feature |
| 863 | 940 | ) { |
| 864 | 941 | $config->ensure( $feature ); |
| @@ -863,8 +940,103 @@ | ||
| 863 | 940 | ) { |
| 864 | 941 | $config->ensure( $feature ); |
| 865 | 942 | } |
| 866 | 943 | |
| 944 | + // Enable the VideoPress admin UI (the "Jetpack > VideoPress" dashboard) inside the | |
| 945 | + // Jetpack plugin, mirroring the standalone Jetpack VideoPress plugin. The dashboard | |
| 946 | + // only renders when the VideoPress module is active (Status::is_active()); when it | |
| 947 | + // is not, the menu item links to the My Jetpack interstitial to activate it. | |
| 948 | + $config->ensure( 'videopress', array( 'admin_ui' => true ) ); | |
| 949 | + | |
| 950 | + /* | |
| 951 | + * The Import package only registers `jetpack/v4/import` REST routes — it | |
| 952 | + * does nothing when rendering a front-end page — so gate its `ensure()` | |
| 953 | + * to keep its PHP out of opcache on the front-end GET hot path. It still | |
| 954 | + * loads on admin, cron, POST, and WP-CLI requests, and on `rest_api_init` | |
| 955 | + * for REST: a REST request can't be identified yet at `plugins_loaded` | |
| 956 | + * (this runs before `Config::on_plugins_loaded`, and `rest_api_init` | |
| 957 | + * fires later), so it is initialized directly when that hook fires, while | |
| 958 | + * a plain page view never fires it and so loads nothing. | |
| 959 | + * | |
| 960 | + * JITM stays eager (above): unlike Import, its `register()` adds a | |
| 961 | + * `jetpack_sync_before_send_updated_option` filter that records the | |
| 962 | + * `jetpack_last_plugin_sync` transient, and a Jetpack Sync send can fire | |
| 963 | + * on a plain front-end GET — including the dedicated-sync `spawn-sync` | |
| 964 | + * GET, which runs on `init` and exits before `rest_api_init`. Deferring | |
| 965 | + * JITM would skip that bookkeeping and leave its message cache stale after | |
| 966 | + * a plugin change, so it loads on every request as before. | |
| 967 | + */ | |
| 968 | + if ( self::should_eager_load_packages() ) { | |
| 969 | + $config->ensure( 'import' ); | |
| 970 | + } else { | |
| 971 | + add_action( | |
| 972 | + 'rest_api_init', | |
| 973 | + array( __CLASS__, 'configure_import_package' ), | |
| 974 | + 0 | |
| 975 | + ); | |
| 976 | + } | |
| 977 | + | |
| 978 | + /* | |
| 979 | + * The Stats and Stats Admin packages only do work when the Stats module | |
| 980 | + * is active (the front-end tracking pixel) or on wp-admin, REST, cron, | |
| 981 | + * POST, and WP-CLI requests: the Stats dashboard page, the stats / | |
| 982 | + * stats-app REST endpoints (which the block editor also calls for | |
| 983 | + * email-open rates), the transient-cleanup cron, the connection | |
| 984 | + * package's package-version tracker (which runs on POSTs and reads the | |
| 985 | + * `jetpack_package_versions` filter that Stats registers), and CLI | |
| 986 | + * introspection such as the heartbeat inspector. On a plain front-end | |
| 987 | + * GET page view with the module off they are inert: the pixel | |
| 988 | + * short-circuits on `Stats\Main::should_track()` and every other entry | |
| 989 | + * point only hooks rest_api_init, admin, cron, the POST-only tracker, or | |
| 990 | + * is reached through WP-CLI. | |
| 991 | + * Skip loading them — and eagerly constructing the Stats Admin REST | |
| 992 | + * controller — on that hot path to keep their PHP out of opcache, but | |
| 993 | + * keep loading them everywhere else exactly as before so the stats REST | |
| 994 | + * permission mapping (view_stats, registered by Stats\Main), the | |
| 995 | + * editor's stats-app calls, the cleanup cron, and the package-version | |
| 996 | + * tracker are all unchanged. | |
| 997 | + * | |
| 998 | + * REST requests are not yet identifiable here (REST_REQUEST is defined | |
| 999 | + * after plugins_loaded), so defer those to rest_api_init. Call the | |
| 1000 | + * package initializers directly rather than `$config->ensure()`: ensure() | |
| 1001 | + * only flags a feature for `Config::on_plugins_loaded()` (plugins_loaded | |
| 1002 | + * priority 2), which has already run by the time rest_api_init fires. | |
| 1003 | + * Priority 0 runs before each package's own priority-10 route | |
| 1004 | + * registration, so their routes still register within the same dispatch. | |
| 1005 | + * A plain page view never fires rest_api_init, so the packages stay | |
| 1006 | + * unloaded there. See JETPACK-1747. | |
| 1007 | + */ | |
| 1008 | + $is_post_request = isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD']; | |
| 1009 | + $is_wp_cli = defined( 'WP_CLI' ) && WP_CLI; | |
| 1010 | + | |
| 1011 | + if ( self::is_module_active( 'stats' ) || is_admin() || wp_doing_cron() || $is_post_request || $is_wp_cli ) { | |
| 1012 | + $config->ensure( 'stats' ); | |
| 1013 | + $config->ensure( 'stats_admin' ); | |
| 1014 | + } else { | |
| 1015 | + add_action( | |
| 1016 | + 'rest_api_init', | |
| 1017 | + static function () { | |
| 1018 | + if ( class_exists( 'Automattic\Jetpack\Stats\Main' ) ) { | |
| 1019 | + \Automattic\Jetpack\Stats\Main::init(); | |
| 1020 | + } | |
| 1021 | + if ( class_exists( 'Automattic\Jetpack\Stats_Admin\Main' ) ) { | |
| 1022 | + \Automattic\Jetpack\Stats_Admin\Main::init(); | |
| 1023 | + } | |
| 1024 | + }, | |
| 1025 | + 0 | |
| 1026 | + ); | |
| 1027 | + } | |
| 1028 | + | |
| 1029 | + // Stats v2 (WOOA7S-1595). Unlike Stats above it cannot be deferred when enabled — see | |
| 1030 | + // Analytics::init() for why, and for why it takes no menu_title here. | |
| 1031 | + if ( self::is_premium_analytics_enabled() ) { | |
| 1032 | + \Automattic\Jetpack\PremiumAnalytics\Analytics::init(); | |
| 1033 | + } | |
| 1034 | + | |
| 1035 | + // Outside the check above on purpose — see Enablement_Setting. Deferred like Stats, to keep | |
| 1036 | + // the autoload off the front-end hot path. | |
| 1037 | + add_action( 'rest_api_init', array( __CLASS__, 'register_premium_analytics_enablement_setting' ), 0 ); | |
| 1038 | + | |
| 867 | 1039 | $config->ensure( |
| 868 | 1040 | 'connection', |
| 869 | 1041 | array( |
| 870 | 1042 | 'slug' => 'jetpack', |
| @@ -882,12 +1054,8 @@ | ||
| 882 | 1054 | ); |
| 883 | 1055 | |
| 884 | 1056 | $config->ensure( 'search' ); |
| 885 | 1057 | |
| 886 | - if ( defined( 'ENABLE_WORDADS_SHARED_UI' ) && ENABLE_WORDADS_SHARED_UI ) { | |
| 887 | - $config->ensure( 'wordads' ); | |
| 888 | - } | |
| 889 | - | |
| 890 | 1058 | if ( ! $this->connection_manager ) { |
| 891 | 1059 | $this->connection_manager = new Connection_Manager( 'jetpack' ); |
| 892 | 1060 | } |
| 893 | 1061 | |
| @@ -895,8 +1063,10 @@ | ||
| 895 | 1063 | if ( $modules->is_active( 'publicize' ) && $this->connection_manager->has_connected_user() ) { |
| 896 | 1064 | $config->ensure( 'publicize' ); |
| 897 | 1065 | } |
| 898 | 1066 | |
| 1067 | + add_action( 'jetpack_initialize_tracking', array( $this, 'initialize_tracking' ) ); | |
| 1068 | + | |
| 899 | 1069 | /* |
| 900 | 1070 | * Load things that should only be in Network Admin. |
| 901 | 1071 | * |
| 902 | 1072 | * For now blow away everything else until a more full |
| @@ -911,8 +1081,9 @@ | ||
| 911 | 1081 | $is_connection_ready = self::is_connection_ready(); |
| 912 | 1082 | |
| 913 | 1083 | if ( $is_connection_ready ) { |
| 914 | 1084 | add_action( 'login_form_jetpack_json_api_authorization', array( $this, 'login_form_json_api_authorization' ) ); |
| 1085 | + $this->run_initialize_tracking_action(); | |
| 915 | 1086 | |
| 916 | 1087 | Jetpack_Heartbeat::init(); |
| 917 | 1088 | if ( self::is_module_active( 'stats' ) && self::is_module_active( 'search' ) ) { |
| 918 | 1089 | require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.jetpack-search-performance-logger.php'; |
| @@ -917,8 +1088,19 @@ | ||
| 917 | 1088 | if ( self::is_module_active( 'stats' ) && self::is_module_active( 'search' ) ) { |
| 918 | 1089 | require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.jetpack-search-performance-logger.php'; |
| 919 | 1090 | Jetpack_Search_Performance_Logger::init(); |
| 920 | 1091 | } |
| 1092 | + } else { | |
| 1093 | + add_action( 'jetpack_agreed_to_terms_of_service', array( $this, 'run_initialize_tracking_action' ) ); | |
| 1094 | + add_action( 'rest_api_init', array( $this, 'run_initialize_tracking_action' ) ); | |
| 1095 | + add_filter( | |
| 1096 | + 'xmlrpc_methods', | |
| 1097 | + function ( $methods ) { | |
| 1098 | + $this->run_initialize_tracking_action(); | |
| 1099 | + return $methods; | |
| 1100 | + }, | |
| 1101 | + 1 | |
| 1102 | + ); | |
| 921 | 1103 | } |
| 922 | 1104 | |
| 923 | 1105 | // Initialize remote file upload request handlers. |
| 924 | 1106 | $this->add_remote_request_handlers(); |
| @@ -928,20 +1110,10 @@ | ||
| 928 | 1110 | */ |
| 929 | 1111 | if ( $is_connection_ready ) { |
| 930 | 1112 | require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.jetpack-iframe-embed.php'; |
| 931 | 1113 | add_action( 'init', array( 'Jetpack_Iframe_Embed', 'init' ), 9, 0 ); |
| 932 | - require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.jetpack-keyring-service-helper.php'; | |
| 933 | - add_action( 'init', array( 'Jetpack_Keyring_Service_Helper', 'init' ), 9, 0 ); | |
| 1114 | + add_action( 'rest_api_init', array( $this, 'maybe_initialize_rest_jsonapi' ) ); | |
| 934 | 1115 | } |
| 935 | - | |
| 936 | - if ( ( new Tracking( 'jetpack', $this->connection_manager ) )->should_enable_tracking( new Terms_Of_Service(), new Status() ) ) { | |
| 937 | - add_action( 'init', array( new Plugin_Tracking(), 'init' ) ); | |
| 938 | - } else { | |
| 939 | - /** | |
| 940 | - * Initialize tracking right after the user agrees to the terms of service. | |
| 941 | - */ | |
| 942 | - add_action( 'jetpack_agreed_to_terms_of_service', array( new Plugin_Tracking(), 'init' ) ); | |
| 943 | - } | |
| 944 | 1116 | } |
| 945 | 1117 | |
| 946 | 1118 | /** |
| 947 | 1119 | * Runs on plugins_loaded. Use this to add code that needs to be executed later than other |
| @@ -949,17 +1121,59 @@ | ||
| 949 | 1121 | * |
| 950 | 1122 | * @action plugins_loaded |
| 951 | 1123 | */ |
| 952 | 1124 | public function late_initialization() { |
| 953 | - add_action( 'plugins_loaded', array( 'Jetpack', 'load_modules' ), 100 ); | |
| 1125 | + add_action( 'after_setup_theme', array( 'Jetpack', 'load_modules' ), -2 ); | |
| 954 | 1126 | |
| 955 | - Partner::init(); | |
| 956 | - My_Jetpack_Initializer::init(); | |
| 1127 | + /* | |
| 1128 | + * My Jetpack is a wp-admin dashboard. Its Initializer::init() only wires | |
| 1129 | + * up admin-menu, admin_init, and rest_api_init surfaces — and eagerly | |
| 1130 | + * loads every product class (backup, boost, protect, …) just to register | |
| 1131 | + * admin plugin-action links — so none of it is needed on a plain | |
| 1132 | + * front-end GET page view. (The pieces that do immediate work, e.g. | |
| 1133 | + * Connection REST authentication and Licensing, are already initialized | |
| 1134 | + * unconditionally in Jetpack's constructor, so they are unaffected here.) | |
| 1135 | + * | |
| 1136 | + * Gate the call to the request types where My Jetpack actually does work. | |
| 1137 | + * REST can't be detected yet at plugins_loaded, so initialize on | |
| 1138 | + * rest_api_init for that branch; a plain page view never fires it, so My | |
| 1139 | + * Jetpack stays unloaded there. | |
| 1140 | + */ | |
| 1141 | + if ( self::should_eager_load_packages() ) { | |
| 1142 | + My_Jetpack_Initializer::init(); | |
| 1143 | + } else { | |
| 1144 | + add_action( 'rest_api_init', array( My_Jetpack_Initializer::class, 'init' ), 0 ); | |
| 1145 | + } | |
| 957 | 1146 | |
| 958 | - // Initialize Boost Speed Score | |
| 959 | - $modules = Jetpack_Boost_Modules::init(); | |
| 960 | - new Speed_Score( $modules, 'jetpack-dashboard' ); | |
| 1147 | + Activity_Log_Init::initialize(); | |
| 1148 | + Scan_Page_Init::initialize(); | |
| 1149 | + Jetpack_SEO_Initializer::init(); | |
| 961 | 1150 | |
| 1151 | + if ( ( new Modules() )->is_active( 'podcast' ) ) { | |
| 1152 | + Podcast::init(); | |
| 1153 | + } | |
| 1154 | + | |
| 1155 | + /* | |
| 1156 | + * Initialize Boost Speed Score. It only does work on REST requests (the | |
| 1157 | + * dashboard speed-score endpoints) and on a few Jetpack Boost lifecycle | |
| 1158 | + * actions, so defer constructing it — and loading the boost-speed-score | |
| 1159 | + * package classes — until one of those hooks actually fires instead of on | |
| 1160 | + * every request. Priority 0 ensures the object's own callbacks (added in | |
| 1161 | + * its constructor at the default priority) still run for the firing hook. | |
| 1162 | + */ | |
| 1163 | + $initialize_speed_score = static function () { | |
| 1164 | + static $initialized = false; | |
| 1165 | + if ( $initialized ) { | |
| 1166 | + return; | |
| 1167 | + } | |
| 1168 | + $initialized = true; | |
| 1169 | + new Speed_Score( array(), 'jetpack-dashboard' ); | |
| 1170 | + }; | |
| 1171 | + add_action( 'rest_api_init', $initialize_speed_score, 0 ); | |
| 1172 | + add_action( 'jetpack_boost_deactivate', $initialize_speed_score, 0 ); | |
| 1173 | + add_action( 'jetpack_boost_environment_changed', $initialize_speed_score, 0 ); | |
| 1174 | + add_action( 'handle_environment_change', $initialize_speed_score, 0 ); | |
| 1175 | + | |
| 962 | 1176 | /** |
| 963 | 1177 | * Fires when Jetpack is fully loaded and ready. This is the point where it's safe |
| 964 | 1178 | * to instantiate classes from packages and namespaces that are managed by the Jetpack Autoloader. |
| 965 | 1179 | * |
| @@ -997,8 +1211,10 @@ | ||
| 997 | 1211 | |
| 998 | 1212 | /** |
| 999 | 1213 | * Redirect edit post links to Calypso. |
| 1000 | 1214 | * |
| 1215 | + * @deprecated since 13.9 | |
| 1216 | + * | |
| 1001 | 1217 | * @param string $default_url Post edit URL. |
| 1002 | 1218 | * @param int $post_id Post ID. |
| 1003 | 1219 | * |
| 1004 | 1220 | * @return string |
| @@ -1003,8 +1219,10 @@ | ||
| 1003 | 1219 | * |
| 1004 | 1220 | * @return string |
| 1005 | 1221 | */ |
| 1006 | 1222 | public function point_edit_post_links_to_calypso( $default_url, $post_id ) { |
| 1223 | + _deprecated_function( __METHOD__, '13.9' ); | |
| 1224 | + | |
| 1007 | 1225 | $post = get_post( $post_id ); |
| 1008 | 1226 | |
| 1009 | 1227 | if ( empty( $post ) ) { |
| 1010 | 1228 | return $default_url; |
| @@ -1035,13 +1253,17 @@ | ||
| 1035 | 1253 | |
| 1036 | 1254 | /** |
| 1037 | 1255 | * Redirect edit comment links to Calypso. |
| 1038 | 1256 | * |
| 1257 | + * @deprecated since 13.9 | |
| 1258 | + * | |
| 1039 | 1259 | * @param string $url Comment edit URL. |
| 1040 | 1260 | * |
| 1041 | 1261 | * @return string |
| 1042 | 1262 | */ |
| 1043 | 1263 | public function point_edit_comment_links_to_calypso( $url ) { |
| 1264 | + _deprecated_function( __METHOD__, '13.9' ); | |
| 1265 | + | |
| 1044 | 1266 | // Take the `query` key value from the URL, and parse its parts to the $query_args. `amp;c` matches the comment ID. |
| 1045 | 1267 | $query_args = null; |
| 1046 | 1268 | wp_parse_str( wp_parse_url( $url, PHP_URL_QUERY ), $query_args ); |
| 1047 | 1269 | |
| @@ -1060,9 +1282,8 @@ | ||
| 1060 | 1282 | * |
| 1061 | 1283 | * @return array list of callables. |
| 1062 | 1284 | */ |
| 1063 | 1285 | public function filter_sync_callable_whitelist( $callables ) { |
| 1064 | - | |
| 1065 | 1286 | // Jetpack Functions. |
| 1066 | 1287 | $jetpack_callables = array( |
| 1067 | 1288 | 'single_user_site' => array( 'Jetpack', 'is_single_user_site' ), |
| 1068 | 1289 | 'updates' => array( 'Jetpack', 'get_updates' ), |
| @@ -1067,23 +1288,9 @@ | ||
| 1067 | 1288 | 'single_user_site' => array( 'Jetpack', 'is_single_user_site' ), |
| 1068 | 1289 | 'updates' => array( 'Jetpack', 'get_updates' ), |
| 1069 | 1290 | 'available_jetpack_blocks' => array( 'Jetpack_Gutenberg', 'get_availability' ), // Includes both Gutenberg blocks *and* plugins. |
| 1070 | 1291 | ); |
| 1071 | - $callables = array_merge( $callables, $jetpack_callables ); | |
| 1072 | - | |
| 1073 | - // Jetpack_SSO_Helpers. | |
| 1074 | - if ( include_once JETPACK__PLUGIN_DIR . 'modules/sso/class.jetpack-sso-helpers.php' ) { | |
| 1075 | - $sso_helpers = array( | |
| 1076 | - 'sso_is_two_step_required' => array( 'Jetpack_SSO_Helpers', 'is_two_step_required' ), | |
| 1077 | - 'sso_should_hide_login_form' => array( 'Jetpack_SSO_Helpers', 'should_hide_login_form' ), | |
| 1078 | - 'sso_match_by_email' => array( 'Jetpack_SSO_Helpers', 'match_by_email' ), | |
| 1079 | - 'sso_new_user_override' => array( 'Jetpack_SSO_Helpers', 'new_user_override' ), | |
| 1080 | - 'sso_bypass_default_login_form' => array( 'Jetpack_SSO_Helpers', 'bypass_login_forward_wpcom' ), | |
| 1081 | - ); | |
| 1082 | - $callables = array_merge( $callables, $sso_helpers ); | |
| 1083 | - } | |
| 1084 | - | |
| 1085 | - return $callables; | |
| 1292 | + return array_merge( $callables, $jetpack_callables ); | |
| 1086 | 1293 | } |
| 1087 | 1294 | |
| 1088 | 1295 | /** |
| 1089 | 1296 | * Extend Sync multisite callables with Jetpack Plugin functions. |
| @@ -1108,41 +1315,8 @@ | ||
| 1108 | 1315 | return $callables; |
| 1109 | 1316 | } |
| 1110 | 1317 | |
| 1111 | 1318 | /** |
| 1112 | - * Deprecated | |
| 1113 | - * Please use Automattic\Jetpack\JITMS\JITM::jetpack_track_last_sync_callback instead. | |
| 1114 | - * | |
| 1115 | - * @param array $params The action parameters. | |
| 1116 | - * | |
| 1117 | - * @deprecated since 9.8. | |
| 1118 | - */ | |
| 1119 | - public function jetpack_track_last_sync_callback( $params ) { | |
| 1120 | - _deprecated_function( __METHOD__, 'jetpack-9.8', '\Automattic\Jetpack\JITMS\JITM->jetpack_track_last_sync_callback' ); | |
| 1121 | - return Automattic\Jetpack\JITMS\JITM::get_instance()->jetpack_track_last_sync_callback( $params ); | |
| 1122 | - } | |
| 1123 | - | |
| 1124 | - /** | |
| 1125 | - * Jetpack Connection banner callback function. | |
| 1126 | - * | |
| 1127 | - * @return void | |
| 1128 | - */ | |
| 1129 | - public function jetpack_connection_banner_callback() { | |
| 1130 | - check_ajax_referer( 'jp-connection-banner-nonce', 'nonce' ); | |
| 1131 | - | |
| 1132 | - // Disable the banner dismiss functionality if the pre-connection prompt helpers filter is set. | |
| 1133 | - if ( | |
| 1134 | - isset( $_REQUEST['dismissBanner'] ) && | |
| 1135 | - ! Jetpack_Connection_Banner::force_display() | |
| 1136 | - ) { | |
| 1137 | - Jetpack_Options::update_option( 'dismissed_connection_banner', 1 ); | |
| 1138 | - wp_send_json_success(); | |
| 1139 | - } | |
| 1140 | - | |
| 1141 | - wp_die(); | |
| 1142 | - } | |
| 1143 | - | |
| 1144 | - /** | |
| 1145 | 1319 | * If there are any stats that need to be pushed, but haven't been, push them now. |
| 1146 | 1320 | */ |
| 1147 | 1321 | public function push_stats() { |
| 1148 | 1322 | if ( ! empty( $this->stats ) ) { |
| @@ -1157,16 +1331,8 @@ | ||
| 1157 | 1331 | * @param string $cap Capability name. |
| 1158 | 1332 | */ |
| 1159 | 1333 | public function jetpack_custom_caps( $caps, $cap ) { |
| 1160 | 1334 | switch ( $cap ) { |
| 1161 | - case 'jetpack_manage_modules': | |
| 1162 | - case 'jetpack_activate_modules': | |
| 1163 | - case 'jetpack_deactivate_modules': | |
| 1164 | - $caps = array( 'manage_options' ); | |
| 1165 | - break; | |
| 1166 | - case 'jetpack_configure_modules': | |
| 1167 | - $caps = array( 'manage_options' ); | |
| 1168 | - break; | |
| 1169 | 1335 | case 'jetpack_manage_autoupdates': |
| 1170 | 1336 | $caps = array( |
| 1171 | 1337 | 'manage_options', |
| 1172 | 1338 | 'update_plugins', |
| @@ -1184,9 +1350,9 @@ | ||
| 1184 | 1350 | if ( $is_offline_mode ) { |
| 1185 | 1351 | $caps = array( 'manage_options' ); |
| 1186 | 1352 | break; |
| 1187 | 1353 | } else { |
| 1188 | - $caps = array( 'read' ); | |
| 1354 | + $caps = array( 'edit_posts' ); | |
| 1189 | 1355 | } |
| 1190 | 1356 | break; |
| 1191 | 1357 | } |
| 1192 | 1358 | return $caps; |
| @@ -1345,9 +1511,9 @@ | ||
| 1345 | 1511 | } |
| 1346 | 1512 | /** |
| 1347 | 1513 | * Does the network allow admins to add new users. |
| 1348 | 1514 | * |
| 1349 | - * @return boolian | |
| 1515 | + * @return bool | |
| 1350 | 1516 | */ |
| 1351 | 1517 | public static function network_add_new_users() { |
| 1352 | 1518 | return (bool) get_site_option( 'add_new_users' ); |
| 1353 | 1519 | } |
| @@ -1354,9 +1520,9 @@ | ||
| 1354 | 1520 | /** |
| 1355 | 1521 | * File upload psace left per site in MB. |
| 1356 | 1522 | * -1 means NO LIMIT. |
| 1357 | 1523 | * |
| 1358 | - * @return number | |
| 1524 | + * @return int | |
| 1359 | 1525 | */ |
| 1360 | 1526 | public static function network_site_upload_space() { |
| 1361 | 1527 | // value in MB. |
| 1362 | 1528 | return ( get_site_option( 'upload_space_check_disabled' ) ? -1 : get_space_allowed() ); |
| @@ -1373,9 +1539,9 @@ | ||
| 1373 | 1539 | |
| 1374 | 1540 | /** |
| 1375 | 1541 | * Maximum file upload size set by the network. |
| 1376 | 1542 | * |
| 1377 | - * @return number | |
| 1543 | + * @return int | |
| 1378 | 1544 | */ |
| 1379 | 1545 | public static function network_max_upload_file_size() { |
| 1380 | 1546 | // value in KB. |
| 1381 | 1547 | return get_site_option( 'fileupload_maxk', 300 ); |
| @@ -1534,9 +1700,9 @@ | ||
| 1534 | 1700 | } |
| 1535 | 1701 | return 0; |
| 1536 | 1702 | } |
| 1537 | 1703 | |
| 1538 | -// phpcs:disable WordPress.WP.CapitalPDangit.Misspelled | |
| 1704 | + // phpcs:disable WordPress.WP.CapitalPDangit.MisspelledInComment | |
| 1539 | 1705 | /** |
| 1540 | 1706 | * Gets updates and stores in jetpack_updates. |
| 1541 | 1707 | * |
| 1542 | 1708 | * The jetpack_updates option is saved in the following schema: |
| @@ -1552,8 +1718,9 @@ | ||
| 1552 | 1718 | * |
| 1553 | 1719 | * @return array |
| 1554 | 1720 | */ |
| 1555 | 1721 | public static function get_updates() { |
| 1722 | + $updates = array(); | |
| 1556 | 1723 | $update_data = wp_get_update_data(); |
| 1557 | 1724 | |
| 1558 | 1725 | // Stores the individual update counts as well as the total count. |
| 1559 | 1726 | if ( isset( $update_data['counts'] ) ) { |
| @@ -1566,11 +1733,11 @@ | ||
| 1566 | 1733 | if ( isset( $cur->response ) && 'upgrade' === $cur->response ) { |
| 1567 | 1734 | $updates['wp_update_version'] = $cur->current; |
| 1568 | 1735 | } |
| 1569 | 1736 | } |
| 1570 | - return isset( $updates ) ? $updates : array(); | |
| 1737 | + return $updates; | |
| 1571 | 1738 | } |
| 1572 | - // phpcs:enable | |
| 1739 | + // phpcs:enable WordPress.WP.CapitalPDangit.MisspelledInComment | |
| 1573 | 1740 | |
| 1574 | 1741 | /** |
| 1575 | 1742 | * Get update details for core, plugins, and themes. |
| 1576 | 1743 | * |
| @@ -1628,44 +1795,8 @@ | ||
| 1628 | 1795 | return apply_filters( 'jetpack_is_connection_ready', self::connection()->is_connected(), self::connection() ); |
| 1629 | 1796 | } |
| 1630 | 1797 | |
| 1631 | 1798 | /** |
| 1632 | - * Deprecated: Is Jetpack in development (offline) mode? | |
| 1633 | - * | |
| 1634 | - * This static method is being left here intentionally without the use of _deprecated_function(), as other plugins | |
| 1635 | - * and themes still use it, and we do not want to flood them with notices. | |
| 1636 | - * | |
| 1637 | - * Please use Automattic\Jetpack\Status()->is_offline_mode() instead. | |
| 1638 | - * | |
| 1639 | - * @deprecated since 8.0. | |
| 1640 | - */ | |
| 1641 | - public static function is_development_mode() { | |
| 1642 | - _deprecated_function( __METHOD__, 'jetpack-8.0', '\Automattic\Jetpack\Status->is_offline_mode' ); | |
| 1643 | - return ( new Status() )->is_offline_mode(); | |
| 1644 | - } | |
| 1645 | - | |
| 1646 | - /** | |
| 1647 | - * Whether the site is currently onboarding or not. | |
| 1648 | - * A site is considered as being onboarded if it currently has an onboarding token. | |
| 1649 | - * | |
| 1650 | - * @since 5.8 | |
| 1651 | - * @deprecated Use \Automattic\Jetpack\Status()->is_onboarding() | |
| 1652 | - * | |
| 1653 | - * @access public | |
| 1654 | - * @static | |
| 1655 | - * | |
| 1656 | - * @return bool True if the site is currently onboarding, false otherwise | |
| 1657 | - */ | |
| 1658 | - public static function is_onboarding() { | |
| 1659 | - _deprecated_function( __METHOD__, 'jetpack-10.9', 'Automattic\\Jetpack\\Status\\is_onboarding' ); | |
| 1660 | - | |
| 1661 | - if ( ! method_exists( 'Automattic\Jetpack\Status', 'is_onboarding' ) ) { | |
| 1662 | - return Jetpack_Options::get_option( 'onboarding' ) !== false; | |
| 1663 | - } | |
| 1664 | - return ( new Status() )->is_onboarding(); | |
| 1665 | - } | |
| 1666 | - | |
| 1667 | - /** | |
| 1668 | 1799 | * Determines reason for Jetpack offline mode. |
| 1669 | 1800 | */ |
| 1670 | 1801 | public static function development_mode_trigger_text() { |
| 1671 | 1802 | $status = new Status(); |
| @@ -1679,11 +1810,10 @@ | ||
| 1679 | 1810 | } elseif ( defined( 'WP_LOCAL_DEV' ) && WP_LOCAL_DEV ) { |
| 1680 | 1811 | $notice = __( 'The WP_LOCAL_DEV constant is defined in wp-config.php or elsewhere.', 'jetpack' ); |
| 1681 | 1812 | } elseif ( $status->is_local_site() ) { |
| 1682 | 1813 | $notice = __( 'The site URL is a known local development environment URL (e.g. http://localhost).', 'jetpack' ); |
| 1683 | - /** This filter is documented in packages/status/src/class-status.php */ | |
| 1684 | - } elseif ( has_filter( 'jetpack_development_mode' ) && apply_filters( 'jetpack_development_mode', false ) ) { // This is a deprecated filter name. | |
| 1685 | - $notice = __( 'The jetpack_development_mode filter is set to true.', 'jetpack' ); | |
| 1814 | + } elseif ( get_option( 'jetpack_offline_mode' ) ) { | |
| 1815 | + $notice = __( 'The jetpack_offline_mode option is set to true.', 'jetpack' ); | |
| 1686 | 1816 | } else { |
| 1687 | 1817 | $notice = __( 'The jetpack_offline_mode filter is set to true.', 'jetpack' ); |
| 1688 | 1818 | } |
| 1689 | 1819 | |
| @@ -1698,9 +1828,9 @@ | ||
| 1698 | 1828 | if ( ( new Status() )->is_offline_mode() ) { |
| 1699 | 1829 | $notice = sprintf( |
| 1700 | 1830 | /* translators: %s is a URL */ |
| 1701 | 1831 | __( 'In <a href="%s" target="_blank">Offline Mode</a>:', 'jetpack' ), |
| 1702 | - Redirect::get_url( 'jetpack-support-development-mode' ) | |
| 1832 | + esc_url( Redirect::get_url( 'jetpack-support-development-mode' ) ) | |
| 1703 | 1833 | ); |
| 1704 | 1834 | |
| 1705 | 1835 | $notice .= ' ' . self::development_mode_trigger_text(); |
| 1706 | 1836 | |
| @@ -1709,19 +1839,12 @@ | ||
| 1709 | 1839 | |
| 1710 | 1840 | // Throw up a notice if using a development version and as for feedback. |
| 1711 | 1841 | if ( self::is_development_version() ) { |
| 1712 | 1842 | /* translators: %s is a URL */ |
| 1713 | - $notice = sprintf( __( 'You are currently running a development version of Jetpack. <a href="%s" target="_blank">Submit your feedback</a>', 'jetpack' ), Redirect::get_url( 'jetpack-contact-support-beta-group' ) ); | |
| 1843 | + $notice = sprintf( __( 'You are currently running a development version of Jetpack. <a href="%s" target="_blank">Submit your feedback</a>', 'jetpack' ), esc_url( Redirect::get_url( 'jetpack-contact-support-beta-group' ) ) ); | |
| 1714 | 1844 | |
| 1715 | 1845 | echo '<div class="updated" style="border-color: #f0821e;"><p>' . $notice . '</p></div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- All provided text. |
| 1716 | 1846 | } |
| 1717 | - // Throw up a notice if using staging mode. | |
| 1718 | - if ( ( new Status() )->is_staging_site() ) { | |
| 1719 | - /* translators: %s is a URL */ | |
| 1720 | - $notice = sprintf( __( 'You are running Jetpack on a <a href="%s" target="_blank">staging server</a>.', 'jetpack' ), Redirect::get_url( 'jetpack-support-staging-sites' ) ); | |
| 1721 | - | |
| 1722 | - echo '<div class="updated" style="border-color: #f0821e;"><p>' . $notice . '</p></div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- All provided text. | |
| 1723 | - } | |
| 1724 | 1847 | } |
| 1725 | 1848 | |
| 1726 | 1849 | /** |
| 1727 | 1850 | * Whether Jetpack's version maps to a public release, or a development version. |
| @@ -1742,28 +1865,8 @@ | ||
| 1742 | 1865 | ); |
| 1743 | 1866 | } |
| 1744 | 1867 | |
| 1745 | 1868 | /** |
| 1746 | - * Is a given user (or the current user if none is specified) linked to a WordPress.com user? | |
| 1747 | - * | |
| 1748 | - * @param int $user_id User ID or will use get_current_user_id if false/not provided. | |
| 1749 | - */ | |
| 1750 | - public static function is_user_connected( $user_id = false ) { | |
| 1751 | - _deprecated_function( __METHOD__, 'jetpack-9.5', 'Automattic\\Jetpack\\Connection\\Manager\\is_user_connected' ); | |
| 1752 | - return self::connection()->is_user_connected( $user_id ); | |
| 1753 | - } | |
| 1754 | - | |
| 1755 | - /** | |
| 1756 | - * Get the wpcom user data of the current|specified connected user. | |
| 1757 | - * | |
| 1758 | - * @param null|int $user_id User ID or will use get_current_user_id if null. | |
| 1759 | - */ | |
| 1760 | - public static function get_connected_user_data( $user_id = null ) { | |
| 1761 | - _deprecated_function( __METHOD__, 'jetpack-9.5', 'Automattic\\Jetpack\\Connection\\Manager\\get_connected_user_data' ); | |
| 1762 | - return self::connection()->get_connected_user_data( $user_id ); | |
| 1763 | - } | |
| 1764 | - | |
| 1765 | - /** | |
| 1766 | 1869 | * Get the wpcom email of the current|specified connected user. |
| 1767 | 1870 | * |
| 1768 | 1871 | * @param null|int $user_id User ID or will use get_current_user_id if null. |
| 1769 | 1872 | */ |
| @@ -1815,18 +1918,11 @@ | ||
| 1815 | 1918 | */ |
| 1816 | 1919 | public static function load_modules() { |
| 1817 | 1920 | $status = new Status(); |
| 1818 | 1921 | |
| 1819 | - if ( method_exists( $status, 'is_onboarding' ) ) { | |
| 1820 | - $is_onboarding = $status->is_onboarding(); | |
| 1821 | - } else { | |
| 1822 | - $is_onboarding = self::is_onboarding(); | |
| 1823 | - } | |
| 1824 | - | |
| 1825 | 1922 | if ( |
| 1826 | 1923 | ! self::is_connection_ready() |
| 1827 | 1924 | && ! $status->is_offline_mode() |
| 1828 | - && ! $is_onboarding | |
| 1829 | 1925 | && ( |
| 1830 | 1926 | ! is_multisite() |
| 1831 | 1927 | || ! get_site_option( 'jetpack_protect_active' ) |
| 1832 | 1928 | ) |
| @@ -1947,22 +2043,10 @@ | ||
| 1947 | 2043 | * |
| 1948 | 2044 | * @todo Store the result in core's object cache maybe? |
| 1949 | 2045 | */ |
| 1950 | 2046 | public static function get_active_plugins() { |
| 1951 | - $active_plugins = (array) get_option( 'active_plugins', array() ); | |
| 1952 | - | |
| 1953 | - if ( is_multisite() ) { | |
| 1954 | - // Due to legacy code, active_sitewide_plugins stores them in the keys, | |
| 1955 | - // whereas active_plugins stores them in the values. | |
| 1956 | - $network_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) ); | |
| 1957 | - if ( $network_plugins ) { | |
| 1958 | - $active_plugins = array_merge( $active_plugins, $network_plugins ); | |
| 1959 | - } | |
| 1960 | - } | |
| 1961 | - | |
| 1962 | - sort( $active_plugins ); | |
| 1963 | - | |
| 1964 | - return array_unique( $active_plugins ); | |
| 2047 | + // Delegates to the canonical implementation in the Connection package. | |
| 2048 | + return Heartbeat::get_active_plugins(); | |
| 1965 | 2049 | } |
| 1966 | 2050 | |
| 1967 | 2051 | /** |
| 1968 | 2052 | * Gets and parses additional plugin data to send with the heartbeat data |
| @@ -2100,8 +2184,10 @@ | ||
| 2100 | 2184 | * |
| 2101 | 2185 | * @param bool true Should Twitter Card Meta tags be disabled. Default to true. |
| 2102 | 2186 | */ |
| 2103 | 2187 | if ( ! apply_filters( 'jetpack_disable_twitter_cards', false ) ) { |
| 2188 | + // @todo Remove this require once the deprecated Jetpack_Twitter_Cards wrapper has been removed. | |
| 2189 | + // Twitter Cards functionality now lives in the jetpack-post-media package (Automattic\Jetpack\Post_Media\Twitter_Cards). | |
| 2104 | 2190 | require_once JETPACK__PLUGIN_DIR . 'class.jetpack-twitter-cards.php'; |
| 2105 | 2191 | } |
| 2106 | 2192 | } |
| 2107 | 2193 | |
| @@ -2204,9 +2290,9 @@ | ||
| 2204 | 2290 | if ( isset( $_GET['page'] ) && in_array( $_GET['page'], array( 'jetpack', 'jetpack_modules' ), true ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- we're not changing the site. |
| 2205 | 2291 | $page = sanitize_text_field( wp_unslash( $_GET['page'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- we're not changing the site. |
| 2206 | 2292 | } |
| 2207 | 2293 | wp_safe_redirect( self::admin_url( 'page=' . rawurlencode( $page ) ) ); |
| 2208 | - exit; | |
| 2294 | + exit( 0 ); | |
| 2209 | 2295 | } |
| 2210 | 2296 | } |
| 2211 | 2297 | |
| 2212 | 2298 | /** |
| @@ -2286,12 +2372,14 @@ | ||
| 2286 | 2372 | * @return array |
| 2287 | 2373 | */ |
| 2288 | 2374 | public function handle_deprecated_modules( $modules ) { |
| 2289 | 2375 | $deprecated_modules = array( |
| 2290 | - 'debug' => null, // Closed out and moved to the debugger library. | |
| 2291 | - 'wpcc' => 'sso', // Closed out in 2.6 -- SSO provides the same functionality. | |
| 2292 | - 'gplus-authorship' => null, // Closed out in 3.2 -- Google dropped support. | |
| 2293 | - 'minileven' => null, // Closed out in 8.3 -- Responsive themes are common now, and so is AMP. | |
| 2376 | + 'debug' => null, // Closed out and moved to the debugger library. | |
| 2377 | + 'wpcc' => 'sso', // Closed out in 2.6 -- SSO provides the same functionality. | |
| 2378 | + 'gplus-authorship' => null, // Closed out in 3.2 -- Google dropped support. | |
| 2379 | + 'minileven' => null, // Closed out in 8.3 -- Responsive themes are common now, and so is AMP. | |
| 2380 | + 'lazy-images' => null, // Closed out in 12.8 -- WordPress core now has native lazy loading. | |
| 2381 | + 'enhanced-distribution' => null, // Closed out in 13.3 -- WP.com is winding down the firehose. | |
| 2294 | 2382 | ); |
| 2295 | 2383 | |
| 2296 | 2384 | // Don't activate SSO if they never completed activating WPCC. |
| 2297 | 2385 | if ( self::is_module_active( 'wpcc' ) ) { |
| @@ -2345,8 +2433,17 @@ | ||
| 2345 | 2433 | } |
| 2346 | 2434 | } |
| 2347 | 2435 | } |
| 2348 | 2436 | |
| 2437 | + // Special case to convert block setting to a block module. | |
| 2438 | + $block_key = array_search( 'blocks', $modules, true ); | |
| 2439 | + if ( $block_key !== false ) { // Only care if 'blocks' made it through the previous filters. | |
| 2440 | + $block_option = get_option( 'jetpack_blocks_disabled', null ); | |
| 2441 | + if ( $block_option ) { | |
| 2442 | + unset( $modules[ $block_key ] ); | |
| 2443 | + } | |
| 2444 | + } | |
| 2445 | + | |
| 2349 | 2446 | return $modules; |
| 2350 | 2447 | } |
| 2351 | 2448 | |
| 2352 | 2449 | /** |
| @@ -2459,20 +2556,28 @@ | ||
| 2459 | 2556 | |
| 2460 | 2557 | /** |
| 2461 | 2558 | * Catches PHP errors. Must be used in conjunction with output buffering. |
| 2462 | 2559 | * |
| 2560 | + * @deprecated since 13.5 | |
| 2463 | 2561 | * @param bool $catch True to start catching, False to stop. |
| 2464 | 2562 | * |
| 2465 | 2563 | * @static |
| 2564 | + * @deprecated 13.5 | |
| 2565 | + * @see \Automattic\Jetpack\Errors | |
| 2466 | 2566 | */ |
| 2467 | 2567 | public static function catch_errors( $catch ) { |
| 2568 | + _deprecated_function( __METHOD__, '13.5' ); | |
| 2569 | + // @phan-suppress-next-line PhanDeprecatedClass | |
| 2468 | 2570 | return ( new Errors() )->catch_errors( $catch ); |
| 2469 | 2571 | } |
| 2470 | 2572 | |
| 2471 | 2573 | /** |
| 2472 | 2574 | * Saves any generated PHP errors in ::state( 'php_errors', {errors} ) |
| 2575 | + * | |
| 2576 | + * @deprecated since 13.5 | |
| 2473 | 2577 | */ |
| 2474 | 2578 | public static function catch_errors_on_shutdown() { |
| 2579 | + _deprecated_function( __METHOD__, '13.5' ); | |
| 2475 | 2580 | self::state( 'php_errors', self::alias_directories( ob_get_clean() ) ); |
| 2476 | 2581 | } |
| 2477 | 2582 | |
| 2478 | 2583 | /** |
| @@ -2576,9 +2681,9 @@ | ||
| 2576 | 2681 | ), |
| 2577 | 2682 | add_query_arg( compact( 'min_version', 'max_version', 'other_modules' ), self::admin_url( 'page=jetpack' ) ) |
| 2578 | 2683 | ); |
| 2579 | 2684 | wp_safe_redirect( $url ); |
| 2580 | - exit; | |
| 2685 | + exit( 0 ); | |
| 2581 | 2686 | } |
| 2582 | 2687 | } |
| 2583 | 2688 | |
| 2584 | 2689 | /** |
| @@ -2596,9 +2701,8 @@ | ||
| 2596 | 2701 | |
| 2597 | 2702 | // Check each module for fatal errors, a la wp-admin/plugins.php::activate before activating. |
| 2598 | 2703 | if ( $send_state_messages ) { |
| 2599 | 2704 | self::restate(); |
| 2600 | - self::catch_errors( true ); | |
| 2601 | 2705 | } |
| 2602 | 2706 | |
| 2603 | 2707 | $active = self::get_active_modules(); |
| 2604 | 2708 | |
| @@ -2666,10 +2770,8 @@ | ||
| 2666 | 2770 | if ( $send_state_messages ) { |
| 2667 | 2771 | self::state( 'error', false ); |
| 2668 | 2772 | self::state( 'module', false ); |
| 2669 | 2773 | } |
| 2670 | - | |
| 2671 | - self::catch_errors( false ); | |
| 2672 | 2774 | /** |
| 2673 | 2775 | * Fires when default modules are activated. |
| 2674 | 2776 | * |
| 2675 | 2777 | * @since 1.9.0 |
| @@ -2747,9 +2849,9 @@ | ||
| 2747 | 2849 | * |
| 2748 | 2850 | * @param string $message Error message. |
| 2749 | 2851 | * @param bool $deactivate Deactivate Jetpack or not. |
| 2750 | 2852 | * |
| 2751 | - * @return void | |
| 2853 | + * @return never | |
| 2752 | 2854 | */ |
| 2753 | 2855 | public static function bail_on_activation( $message, $deactivate = true ) { |
| 2754 | 2856 | ?> |
| 2755 | 2857 | <!doctype html> |
| @@ -2787,9 +2889,9 @@ | ||
| 2787 | 2889 | if ( $update ) { |
| 2788 | 2890 | update_option( 'active_plugins', array_filter( $plugins ) ); |
| 2789 | 2891 | } |
| 2790 | 2892 | } |
| 2791 | - exit; | |
| 2893 | + exit( 0 ); | |
| 2792 | 2894 | } |
| 2793 | 2895 | |
| 2794 | 2896 | /** |
| 2795 | 2897 | * Attached to activate_{ plugin_basename( __FILES__ ) } by register_activation_hook() |
| @@ -2814,12 +2916,18 @@ | ||
| 2814 | 2916 | update_option( 'jetpack_activation_source', self::get_activation_source( wp_get_referer() ) ); |
| 2815 | 2917 | |
| 2816 | 2918 | Health::on_jetpack_activated(); |
| 2817 | 2919 | |
| 2920 | + \Automattic\Jetpack\Reprint_Export\Reprint_Exporter::discard_credentials(); | |
| 2921 | + | |
| 2818 | 2922 | if ( self::is_connection_ready() && method_exists( 'Automattic\Jetpack\Sync\Actions', 'do_only_first_initial_sync' ) ) { |
| 2819 | 2923 | Sync_Actions::do_only_first_initial_sync(); |
| 2820 | 2924 | } |
| 2821 | 2925 | |
| 2926 | + if ( ! defined( 'WC_ANALYTICS' ) && class_exists( 'Automattic\Woocommerce_Analytics' ) ) { | |
| 2927 | + Woocommerce_Analytics::maybe_add_proxy_speed_module(); | |
| 2928 | + } | |
| 2929 | + | |
| 2822 | 2930 | self::plugin_initialize(); |
| 2823 | 2931 | } |
| 2824 | 2932 | |
| 2825 | 2933 | /** |
| @@ -2854,9 +2962,9 @@ | ||
| 2854 | 2962 | |
| 2855 | 2963 | if ( $plugins_path === $referer['path'] ) { |
| 2856 | 2964 | $source_type = 'list'; |
| 2857 | 2965 | } elseif ( $plugins_install_path === $referer['path'] ) { |
| 2858 | - $tab = isset( $query_parts['tab'] ) ? $query_parts['tab'] : 'featured'; | |
| 2966 | + $tab = $query_parts['tab'] ?? 'featured'; | |
| 2859 | 2967 | switch ( $tab ) { |
| 2860 | 2968 | case 'popular': |
| 2861 | 2969 | $source_type = 'popular'; |
| 2862 | 2970 | break; |
| @@ -2866,10 +2974,10 @@ | ||
| 2866 | 2974 | case 'favorites': |
| 2867 | 2975 | $source_type = 'favorites'; |
| 2868 | 2976 | break; |
| 2869 | 2977 | case 'search': |
| 2870 | - $source_type = 'search-' . ( isset( $query_parts['type'] ) ? $query_parts['type'] : 'term' ); | |
| 2871 | - $source_query = isset( $query_parts['s'] ) ? $query_parts['s'] : null; | |
| 2978 | + $source_type = 'search-' . ( $query_parts['type'] ?? 'term' ); | |
| 2979 | + $source_query = $query_parts['s'] ?? null; | |
| 2872 | 2980 | break; |
| 2873 | 2981 | default: |
| 2874 | 2982 | $source_type = 'featured'; |
| 2875 | 2983 | } |
| @@ -2878,29 +2986,351 @@ | ||
| 2878 | 2986 | return array( $source_type, $source_query ); |
| 2879 | 2987 | } |
| 2880 | 2988 | |
| 2881 | 2989 | /** |
| 2882 | - * Runs before bumping version numbers up to a new version | |
| 2990 | + * Runs before bumping version numbers up to a new version. | |
| 2883 | 2991 | * |
| 2884 | - * @param string $version Version:timestamp. | |
| 2992 | + * Only ever registered the hooks for the release post update modal, which has been removed. | |
| 2993 | + * No longer hooked to `updating_jetpack_version`. | |
| 2994 | + * | |
| 2995 | + * @deprecated 16.2 | |
| 2996 | + * | |
| 2997 | + * @param string $version Version:timestamp. | |
| 2885 | 2998 | * @param string $old_version Old Version:timestamp or false if not set yet. |
| 2886 | 2999 | */ |
| 2887 | - public static function do_version_bump( $version, $old_version ) { | |
| 2888 | - if ( $old_version ) { // For existing Jetpack installations. | |
| 2889 | - add_action( 'admin_enqueue_scripts', __CLASS__ . '::enqueue_block_style' ); | |
| 3000 | + public static function do_version_bump( $version, $old_version ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Signature preserved for the deprecation shim. | |
| 3001 | + _deprecated_function( __METHOD__, 'jetpack-16.2' ); | |
| 3002 | + } | |
| 2890 | 3003 | |
| 2891 | - // If a front end page is visited after the update, the 'wp' action will fire. | |
| 2892 | - add_action( 'wp', 'Jetpack::set_update_modal_display' ); | |
| 3004 | + /** | |
| 3005 | + * Enables the Newsletter (subscriptions) module for existing sites now that it is a default-on module. | |
| 3006 | + * | |
| 3007 | + * Fresh installs receive the module via its "Auto Activate: Yes" header, so this only handles sites | |
| 3008 | + * upgrading from a version where the module defaulted off. It runs once per site (guarded by the | |
| 3009 | + * subscriptions_default_on_migrated option). Fresh installs are marked as migrated immediately so the | |
| 3010 | + * migration never runs for them. After it has run, the user's choice to deactivate the module again | |
| 3011 | + * (for example from the My Jetpack Products page) is respected and never reverted. | |
| 3012 | + * | |
| 3013 | + * The module requires a connection, so on a disconnected site the migration is deferred without setting | |
| 3014 | + * the guard, allowing a later version bump to retry once the site is connected. | |
| 3015 | + * | |
| 3016 | + * @param string $version New Jetpack version:timestamp. | |
| 3017 | + * @param string|false $old_version Previous Jetpack version:timestamp, or false on a fresh install. | |
| 3018 | + */ | |
| 3019 | + public static function activate_subscriptions_module_for_existing_sites( $version, $old_version ) { | |
| 3020 | + if ( get_option( 'jetpack_subscriptions_default_on_migrated' ) ) { | |
| 3021 | + return; | |
| 3022 | + } | |
| 2893 | 3023 | |
| 2894 | - // If an admin page is visited after the update, the 'current_screen' action will fire. | |
| 2895 | - add_action( 'current_screen', 'Jetpack::set_update_modal_display' ); | |
| 3024 | + // Fresh installs get the module via its "Auto Activate: Yes" header. Mark them as migrated so a | |
| 3025 | + // later opt-out is never reverted by the existing-site path on a subsequent version bump. | |
| 3026 | + if ( ! $old_version ) { | |
| 3027 | + update_option( 'jetpack_subscriptions_default_on_migrated', true ); | |
| 3028 | + return; | |
| 2896 | 3029 | } |
| 3030 | + | |
| 3031 | + if ( ! self::is_connection_ready() ) { | |
| 3032 | + return; | |
| 3033 | + } | |
| 3034 | + | |
| 3035 | + // Mark as migrated only once the module is active, so a transient activation failure is retried on | |
| 3036 | + // a later version bump rather than being silently skipped. | |
| 3037 | + if ( self::is_module_active( 'subscriptions' ) || self::activate_module( 'subscriptions', false, false ) ) { | |
| 3038 | + update_option( 'jetpack_subscriptions_default_on_migrated', true ); | |
| 3039 | + } | |
| 2897 | 3040 | } |
| 2898 | 3041 | |
| 2899 | 3042 | /** |
| 3043 | + * Option flag that records the AI master-switch opt-out reconciliation has run, | |
| 3044 | + * so it never runs twice. | |
| 3045 | + * | |
| 3046 | + * @var string | |
| 3047 | + */ | |
| 3048 | + const AI_MASTER_OPTOUT_MIGRATED_OPTION = 'jetpack_ai_master_optout_migrated'; | |
| 3049 | + | |
| 3050 | + /** | |
| 3051 | + * Register the on-upgrade init hooks whose relative ORDER matters, extracted so | |
| 3052 | + * the ordering can be asserted in tests without invoking plugin_upgrade() (whose | |
| 3053 | + * guards make it unreliable to trigger under test). activate_new_modules() | |
| 3054 | + * (init, default priority 10) auto-activates "Auto Activate: Yes" modules | |
| 3055 | + * including the `ai` master; reconcile_ai_master_optout() must run at a LATER | |
| 3056 | + * priority to honor an explicit AI opt-out. | |
| 3057 | + * | |
| 3058 | + * @return void | |
| 3059 | + */ | |
| 3060 | + public static function register_upgrade_init_hooks() { | |
| 3061 | + add_action( 'init', array( __CLASS__, 'activate_new_modules' ) ); | |
| 3062 | + add_action( 'init', array( __CLASS__, 'reconcile_ai_master_optout' ), 20 ); | |
| 3063 | + } | |
| 3064 | + | |
| 3065 | + /** | |
| 3066 | + * Preserves an explicit Jetpack AI opt-out when the `ai` module becomes the site-wide | |
| 3067 | + * master switch off WordPress.com Simple (self-hosted and Atomic). | |
| 3068 | + * | |
| 3069 | + * The `ai` module is "Auto Activate: Yes", so on upgrade {@see self::activate_new_modules()} | |
| 3070 | + * turns it on for connected sites — the desired default-on / auto-enable-on-connection | |
| 3071 | + * behavior, which this method deliberately leaves alone. The one case it corrects is a site | |
| 3072 | + * that had explicitly disabled Jetpack AI (the `jetpack_ai_enabled` option present and falsey) | |
| 3073 | + * before the module shipped: that opt-out must survive the module becoming the master, so the | |
| 3074 | + * module is deactivated for exactly those sites. An absent or truthy option is left untouched. | |
| 3075 | + * | |
| 3076 | + * Ordering is the whole point. `activate_new_modules()` is hooked on `init` at priority 10 and | |
| 3077 | + * auto-activates the module there; this method is hooked on `init` at priority 20 (see | |
| 3078 | + * {@see self::plugin_upgrade()}), so it runs AFTER the auto-activation and its deactivation is | |
| 3079 | + * the final state. A version-guarded block that ran inline during `plugins_loaded` would be | |
| 3080 | + * undone by the later auto-activation, which is why this is a late-init hook rather than an | |
| 3081 | + * inline upgrade step. | |
| 3082 | + * | |
| 3083 | + * WordPress.com Simple never runs modules — the option stays the master there — so this is a | |
| 3084 | + * no-op on Simple. The {@see self::AI_MASTER_OPTOUT_MIGRATED_OPTION} flag makes it run exactly | |
| 3085 | + * once, which matters because off-Simple the option is no longer the master after this runs: | |
| 3086 | + * a stale falsey option must not keep re-deactivating a module the user later turns back on. | |
| 3087 | + * | |
| 3088 | + * @return void | |
| 3089 | + */ | |
| 3090 | + public static function reconcile_ai_master_optout() { | |
| 3091 | + if ( get_option( self::AI_MASTER_OPTOUT_MIGRATED_OPTION ) ) { | |
| 3092 | + return; | |
| 3093 | + } | |
| 3094 | + | |
| 3095 | + // Simple keeps the `jetpack_ai_enabled` option as the master; modules don't run there. | |
| 3096 | + if ( ( new Host() )->is_wpcom_simple() ) { | |
| 3097 | + return; | |
| 3098 | + } | |
| 3099 | + | |
| 3100 | + // A sentinel default distinguishes an absent option (leave auto-activation alone) from one | |
| 3101 | + // explicitly stored falsey (an opt-out to preserve). | |
| 3102 | + $stored = get_option( 'jetpack_ai_enabled', 'not-set' ); | |
| 3103 | + if ( 'not-set' !== $stored && ! (bool) $stored ) { | |
| 3104 | + ( new Modules() )->deactivate( 'ai' ); | |
| 3105 | + } | |
| 3106 | + | |
| 3107 | + update_option( self::AI_MASTER_OPTOUT_MIGRATED_OPTION, true ); | |
| 3108 | + } | |
| 3109 | + | |
| 3110 | + /** | |
| 3111 | + * Whether a module should be recorded as active in its durable Jetpack SEO option. | |
| 3112 | + * | |
| 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. | |
| 3130 | + */ | |
| 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 | + } | |
| 3159 | + } | |
| 3160 | + | |
| 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 | + /** | |
| 3302 | + * Seeds the Jetpack SEO discoverability cohort once, so the new SEO surface is | |
| 3303 | + * auto-discoverable on fresh installs but opt-in on existing ones (JETPACK-1700). | |
| 3304 | + * | |
| 3305 | + * Hooked on `updating_jetpack_version`, which fires on every install including the | |
| 3306 | + * first — with `$old_version === false` on a brand-new site (the same signal | |
| 3307 | + * {@see self::activate_subscriptions_module_for_existing_sites()} keys off). Fresh | |
| 3308 | + * installs are seeded visible; existing installs are seeded hidden and opt in later | |
| 3309 | + * via the legacy Traffic page or My Jetpack. `add_option()` makes this seed-once: it | |
| 3310 | + * never overrides a value a later opt-in (or opt-out) has set. WordPress.com sites | |
| 3311 | + * ignore this option entirely (always visible) — see | |
| 3312 | + * {@see \Automattic\Jetpack\SEO\Initializer::is_seo_surface_visible()}. | |
| 3313 | + * | |
| 3314 | + * @param string $version The new Jetpack version (unused). | |
| 3315 | + * @param string|false $old_version The previous version, or false on a fresh install. | |
| 3316 | + */ | |
| 3317 | + public static function seed_seo_visibility_cohort( $version, $old_version ) { | |
| 3318 | + add_option( Jetpack_SEO_Initializer::VISIBILITY_OPTION, ! $old_version ); | |
| 3319 | + } | |
| 3320 | + | |
| 3321 | + /** | |
| 2900 | 3322 | * Sets the display_update_modal state. |
| 3323 | + * | |
| 3324 | + * The release post update modal that read this state has been removed. The write is kept so the | |
| 3325 | + * method still behaves as documented for the deprecation window. When this is deleted, also drop | |
| 3326 | + * the matching `display_update_modal` guard in Automattic\Jetpack\CookieState::should_set_cookie(), | |
| 3327 | + * which exists only to keep this key out of the cookie on the Jetpack admin screen. | |
| 3328 | + * | |
| 3329 | + * @deprecated 16.2 | |
| 2901 | 3330 | */ |
| 2902 | 3331 | public static function set_update_modal_display() { |
| 3332 | + _deprecated_function( __METHOD__, 'jetpack-16.2' ); | |
| 2903 | 3333 | self::state( 'display_update_modal', true ); |
| 2904 | 3334 | } |
| 2905 | 3335 | |
| 2906 | 3336 | /** |
| @@ -2905,11 +3335,16 @@ | ||
| 2905 | 3335 | |
| 2906 | 3336 | /** |
| 2907 | 3337 | * Enqueues the block library styles. |
| 2908 | 3338 | * |
| 3339 | + * Only ever used by the release post update modal, which has been removed. | |
| 3340 | + * | |
| 3341 | + * @deprecated 16.2 | |
| 3342 | + * | |
| 2909 | 3343 | * @param string $hook The current admin page. |
| 2910 | 3344 | */ |
| 2911 | 3345 | public static function enqueue_block_style( $hook ) { |
| 3346 | + _deprecated_function( __METHOD__, 'jetpack-16.2' ); | |
| 2912 | 3347 | if ( 'toplevel_page_jetpack' === $hook ) { |
| 2913 | 3348 | wp_enqueue_style( 'wp-block-library' ); |
| 2914 | 3349 | } |
| 2915 | 3350 | } |
| @@ -2938,9 +3373,8 @@ | ||
| 2938 | 3373 | |
| 2939 | 3374 | self::load_modules(); |
| 2940 | 3375 | |
| 2941 | 3376 | Jetpack_Options::delete_option( 'do_activate' ); |
| 2942 | - Jetpack_Options::delete_option( 'dismissed_connection_banner' ); | |
| 2943 | 3377 | } |
| 2944 | 3378 | |
| 2945 | 3379 | /** |
| 2946 | 3380 | * Handles the activation of the default modules depending on the current state of the site: |
| @@ -2999,8 +3433,12 @@ | ||
| 2999 | 3433 | add_filter( 'jetpack_update_activated_state_on_disconnect', '__return_false' ); |
| 3000 | 3434 | self::disconnect(); |
| 3001 | 3435 | Jetpack_Options::delete_option( 'version' ); |
| 3002 | 3436 | } |
| 3437 | + | |
| 3438 | + if ( ! defined( 'WC_ANALYTICS' ) && class_exists( 'Automattic\Woocommerce_Analytics' ) ) { | |
| 3439 | + Woocommerce_Analytics::maybe_remove_proxy_speed_module(); | |
| 3440 | + } | |
| 3003 | 3441 | } |
| 3004 | 3442 | |
| 3005 | 3443 | /** |
| 3006 | 3444 | * Set activated option to 4 on jetpack_idc_disconnect action. |
| @@ -3028,9 +3466,9 @@ | ||
| 3028 | 3466 | $connection->remove_connection( ! Identity_Crisis::validate_sync_error_idc_option() ); |
| 3029 | 3467 | } |
| 3030 | 3468 | |
| 3031 | 3469 | /** |
| 3032 | - * Happens after a successfull disconnection. | |
| 3470 | + * Happens after a successful disconnection. | |
| 3033 | 3471 | * |
| 3034 | 3472 | * @static |
| 3035 | 3473 | */ |
| 3036 | 3474 | public static function jetpack_site_disconnected() { |
| @@ -3035,8 +3473,10 @@ | ||
| 3035 | 3473 | */ |
| 3036 | 3474 | public static function jetpack_site_disconnected() { |
| 3037 | 3475 | Identity_Crisis::clear_all_idc_options(); |
| 3038 | 3476 | |
| 3477 | + \Automattic\Jetpack\Reprint_Export\Reprint_Exporter::discard_credentials(); | |
| 3478 | + | |
| 3039 | 3479 | // Delete all the sync related data. Since it could be taking up space. |
| 3040 | 3480 | Sender::get_instance()->uninstall(); |
| 3041 | 3481 | |
| 3042 | 3482 | /** |
| @@ -3053,10 +3493,13 @@ | ||
| 3053 | 3493 | } |
| 3054 | 3494 | } |
| 3055 | 3495 | |
| 3056 | 3496 | /** |
| 3057 | - * Disconnects the user | |
| 3497 | + * Disconnects the user. | |
| 3058 | 3498 | * |
| 3499 | + * @deprecated 13.4 | |
| 3500 | + * @see \Automattic\Jetpack\Connection\Manager::disconnect_user() | |
| 3501 | + * | |
| 3059 | 3502 | * @param int $user_id The user ID to disconnect. |
| 3060 | 3503 | */ |
| 3061 | 3504 | public function disconnect_user( $user_id ) { |
| 3062 | 3505 | $this->connection_manager->disconnect_user( $user_id ); |
| @@ -3062,21 +3505,8 @@ | ||
| 3062 | 3505 | $this->connection_manager->disconnect_user( $user_id ); |
| 3063 | 3506 | } |
| 3064 | 3507 | |
| 3065 | 3508 | /** |
| 3066 | - * Attempts Jetpack registration. If it fail, a state flag is set: @see ::admin_page_load() | |
| 3067 | - * | |
| 3068 | - * @deprecated since Jetpack 9.7.0 | |
| 3069 | - * @see Automattic\Jetpack\Connection\Manager::try_registration() | |
| 3070 | - * | |
| 3071 | - * @return bool|WP_Error | |
| 3072 | - */ | |
| 3073 | - public static function try_registration() { | |
| 3074 | - _deprecated_function( __METHOD__, 'jetpack-9.7', 'Automattic\\Jetpack\\Connection\\Manager::try_registration' ); | |
| 3075 | - return static::connection()->try_registration(); | |
| 3076 | - } | |
| 3077 | - | |
| 3078 | - /** | |
| 3079 | 3509 | * Checking the domain names in beta versions. |
| 3080 | 3510 | * If this is a development version, before attempting to connect, let's make sure that the domains are viable. |
| 3081 | 3511 | * |
| 3082 | 3512 | * @param null|\WP_Error $error The domain validation error, or `null` if everything's fine. |
| @@ -3083,9 +3513,9 @@ | ||
| 3083 | 3513 | * |
| 3084 | 3514 | * @return null|\WP_Error The domain validation error, or `null` if everything's fine. |
| 3085 | 3515 | */ |
| 3086 | 3516 | public static function registration_check_domains( $error ) { |
| 3087 | - if ( static::is_development_version() && defined( 'PHP_URL_HOST' ) ) { | |
| 3517 | + if ( static::is_development_version() ) { | |
| 3088 | 3518 | $domains_to_check = array_unique( |
| 3089 | 3519 | array( |
| 3090 | 3520 | 'siteurl' => wp_parse_url( get_site_url(), PHP_URL_HOST ), |
| 3091 | 3521 | 'homeurl' => wp_parse_url( get_home_url(), PHP_URL_HOST ), |
| @@ -3110,10 +3540,17 @@ | ||
| 3110 | 3540 | * @param mixed $code Error code to log. |
| 3111 | 3541 | * @param mixed $data Data to log. |
| 3112 | 3542 | */ |
| 3113 | 3543 | public static function log( $code, $data = null ) { |
| 3544 | + | |
| 3545 | + $raw_log = Jetpack_Options::get_option( 'log', array() ); | |
| 3546 | + // This can be modified by the `jetpack_options` filter, so abort if we don't have an array. | |
| 3547 | + if ( ! is_array( $raw_log ) ) { | |
| 3548 | + return; | |
| 3549 | + } | |
| 3550 | + | |
| 3114 | 3551 | // only grab the latest 200 entries. |
| 3115 | - $log = array_slice( Jetpack_Options::get_option( 'log', array() ), -199, 199 ); | |
| 3552 | + $log = array_slice( $raw_log, -199, 199 ); | |
| 3116 | 3553 | |
| 3117 | 3554 | // Append our event to the log. |
| 3118 | 3555 | $log_entry = array( |
| 3119 | 3556 | 'time' => time(), |
| @@ -3213,8 +3650,15 @@ | ||
| 3213 | 3650 | |
| 3214 | 3651 | /** |
| 3215 | 3652 | * Return stat data for WPCOM sync. |
| 3216 | 3653 | * |
| 3654 | + * The Sync stats module was this method's last caller and moved to the Connection package's | |
| 3655 | + * `Heartbeat::generate_stats_array()`, which assembles the heartbeat data through the | |
| 3656 | + * `jetpack_heartbeat_stats_array` filter. Note the package method does not include the extended | |
| 3657 | + * data from `get_additional_stat_data()`, so callers relying on `$extended` need to add it themselves. | |
| 3658 | + * | |
| 3659 | + * @deprecated 16.2 | |
| 3660 | + * | |
| 3217 | 3661 | * @param bool $encode JSON encode the result. |
| 3218 | 3662 | * @param bool $extended Adds additional stats data. |
| 3219 | 3663 | * |
| 3220 | 3664 | * @return array|string Stats data. Array if $encode is false. JSON-encoded string is $encode is true. |
| @@ -3219,10 +3663,13 @@ | ||
| 3219 | 3663 | * |
| 3220 | 3664 | * @return array|string Stats data. Array if $encode is false. JSON-encoded string is $encode is true. |
| 3221 | 3665 | */ |
| 3222 | 3666 | public static function get_stat_data( $encode = true, $extended = true ) { |
| 3223 | - $data = Jetpack_Heartbeat::generate_stats_array(); | |
| 3667 | + _deprecated_function( __METHOD__, 'jetpack-16.2', 'Automattic\\Jetpack\\Heartbeat::generate_stats_array' ); | |
| 3224 | 3668 | |
| 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() ); | |
| 3671 | + | |
| 3225 | 3672 | if ( $extended ) { |
| 3226 | 3673 | $additional_data = self::get_additional_stat_data(); |
| 3227 | 3674 | $data = array_merge( $data, $additional_data ); |
| 3228 | 3675 | } |
| @@ -3227,9 +3674,9 @@ | ||
| 3227 | 3674 | $data = array_merge( $data, $additional_data ); |
| 3228 | 3675 | } |
| 3229 | 3676 | |
| 3230 | 3677 | if ( $encode ) { |
| 3231 | - return wp_json_encode( $data ); | |
| 3678 | + return wp_json_encode( $data, JSON_UNESCAPED_SLASHES ); | |
| 3232 | 3679 | } |
| 3233 | 3680 | |
| 3234 | 3681 | return $data; |
| 3235 | 3682 | } |
| @@ -3301,23 +3748,24 @@ | ||
| 3301 | 3748 | $fallback_no_verify_ssl_certs = Jetpack_Options::get_option( 'fallback_no_verify_ssl_certs' ); |
| 3302 | 3749 | /** Already documented in automattic/jetpack-connection::src/class-client.php */ |
| 3303 | 3750 | $client_verify_ssl_certs = apply_filters( 'jetpack_client_verify_ssl_certs', false ); |
| 3304 | 3751 | |
| 3305 | - if ( ! $is_offline_mode ) { | |
| 3306 | - Jetpack_Connection_Banner::init(); | |
| 3307 | - Jetpack_Connection_Widget::init(); | |
| 3308 | - } | |
| 3752 | + // Run post-activation actions if needed. | |
| 3753 | + $this->plugin_post_activation(); | |
| 3309 | 3754 | |
| 3310 | 3755 | if ( ( self::is_connection_ready() || $is_offline_mode ) && false === $fallback_no_verify_ssl_certs && ! $client_verify_ssl_certs ) { |
| 3311 | 3756 | // Upgrade: 1.1 -> 1.1.1 |
| 3312 | 3757 | // Check and see if host can verify the Jetpack servers' SSL certificate. |
| 3313 | 3758 | $args = array(); |
| 3759 | + // @phan-suppress-next-line PhanAccessMethodInternal -- Phan is correct, but the usage is intentional. | |
| 3314 | 3760 | Client::_wp_remote_request( self::connection()->api_url( 'test' ), $args, true ); |
| 3315 | 3761 | } |
| 3316 | 3762 | |
| 3317 | - Jetpack_Recommendations_Banner::init(); | |
| 3318 | - | |
| 3319 | - if ( current_user_can( 'manage_options' ) && ! self::permit_ssl() ) { | |
| 3763 | + if ( | |
| 3764 | + current_user_can( 'manage_options' ) | |
| 3765 | + && ! self::permit_ssl() | |
| 3766 | + && ! $is_offline_mode | |
| 3767 | + ) { | |
| 3320 | 3768 | add_action( 'jetpack_notices', array( $this, 'alert_auto_ssl_fail' ) ); |
| 3321 | 3769 | } |
| 3322 | 3770 | |
| 3323 | 3771 | add_action( 'load-plugins.php', array( $this, 'intercept_plugin_error_scrape_init' ) ); |
| @@ -3326,12 +3774,8 @@ | ||
| 3326 | 3774 | if ( ! ( is_multisite() && is_plugin_active_for_network( 'jetpack/jetpack.php' ) && ! is_network_admin() ) ) { |
| 3327 | 3775 | add_action( 'admin_enqueue_scripts', array( $this, 'deactivate_dialog' ) ); |
| 3328 | 3776 | } |
| 3329 | 3777 | |
| 3330 | - if ( isset( $_COOKIE['jetpackState']['display_update_modal'] ) ) { | |
| 3331 | - add_action( 'admin_enqueue_scripts', __CLASS__ . '::enqueue_block_style' ); | |
| 3332 | - } | |
| 3333 | - | |
| 3334 | 3778 | add_filter( 'plugin_action_links_' . plugin_basename( JETPACK__PLUGIN_DIR . 'jetpack.php' ), array( $this, 'plugin_action_links' ) ); |
| 3335 | 3779 | |
| 3336 | 3780 | if ( self::is_connection_ready() || $is_offline_mode ) { |
| 3337 | 3781 | // Artificially throw errors in certain specific cases during plugin activation. |
| @@ -3336,13 +3780,8 @@ | ||
| 3336 | 3780 | if ( self::is_connection_ready() || $is_offline_mode ) { |
| 3337 | 3781 | // Artificially throw errors in certain specific cases during plugin activation. |
| 3338 | 3782 | add_action( 'activate_plugin', array( $this, 'throw_error_on_activate_plugin' ) ); |
| 3339 | 3783 | } |
| 3340 | - | |
| 3341 | - // Add custom column in wp-admin/users.php to show whether user is linked. | |
| 3342 | - add_filter( 'manage_users_columns', array( $this, 'jetpack_icon_user_connected' ) ); | |
| 3343 | - add_action( 'manage_users_custom_column', array( $this, 'jetpack_show_user_connected_icon' ), 10, 3 ); | |
| 3344 | - add_action( 'admin_print_styles', array( $this, 'jetpack_user_col_style' ) ); | |
| 3345 | 3784 | } |
| 3346 | 3785 | |
| 3347 | 3786 | /** |
| 3348 | 3787 | * Adds body classes. |
| @@ -3375,8 +3814,9 @@ | ||
| 3375 | 3814 | * Sometimes a plugin can activate without causing errors, but it will cause errors on the next page load. |
| 3376 | 3815 | * This function artificially throws errors for such cases (per a specific list). |
| 3377 | 3816 | * |
| 3378 | 3817 | * @param string $plugin The activated plugin. |
| 3818 | + * @throws RuntimeException If a conflicting plugin is detected. | |
| 3379 | 3819 | */ |
| 3380 | 3820 | public function throw_error_on_activate_plugin( $plugin ) { |
| 3381 | 3821 | $active_modules = self::get_active_modules(); |
| 3382 | 3822 | |
| @@ -3389,8 +3829,9 @@ | ||
| 3389 | 3829 | if ( 'stats.php' === basename( $plugin ) ) { |
| 3390 | 3830 | $throw = true; |
| 3391 | 3831 | } |
| 3392 | 3832 | } else { |
| 3833 | + // @phan-suppress-next-line PhanUndeclaredFunctionInCallable -- Checked above. See also https://github.com/phan/phan/issues/1204. | |
| 3393 | 3834 | $reflection = new ReflectionFunction( 'stats_get_api_key' ); |
| 3394 | 3835 | if ( basename( $plugin ) === basename( $reflection->getFileName() ) ) { |
| 3395 | 3836 | $throw = true; |
| 3396 | 3837 | } |
| @@ -3397,9 +3838,9 @@ | ||
| 3397 | 3838 | } |
| 3398 | 3839 | |
| 3399 | 3840 | if ( $throw ) { |
| 3400 | 3841 | /* translators: Plugin name to deactivate. */ |
| 3401 | - trigger_error( sprintf( esc_html__( 'Jetpack contains the most recent version of the old “%1$s” plugin.', 'jetpack' ), 'WordPress.com Stats' ), E_USER_ERROR ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error | |
| 3842 | + throw new RuntimeException( sprintf( __( 'Jetpack contains the most recent version of the old "%1$s" plugin.', 'jetpack' ), 'WordPress.com Stats' ) ); | |
| 3402 | 3843 | } |
| 3403 | 3844 | } |
| 3404 | 3845 | } |
| 3405 | 3846 | |
| @@ -3481,8 +3922,9 @@ | ||
| 3481 | 3922 | /** |
| 3482 | 3923 | * Handler for Jetpack remote file uploads. |
| 3483 | 3924 | * |
| 3484 | 3925 | * @access public |
| 3926 | + * @return never | |
| 3485 | 3927 | */ |
| 3486 | 3928 | public function remote_request_handlers() { |
| 3487 | 3929 | switch ( current_filter() ) { |
| 3488 | 3930 | case 'wp_ajax_nopriv_jetpack_upload_file': |
| @@ -3509,18 +3951,17 @@ | ||
| 3509 | 3951 | if ( ! is_int( $status_code ) ) { |
| 3510 | 3952 | $status_code = 400; |
| 3511 | 3953 | } |
| 3512 | 3954 | |
| 3513 | - status_header( $status_code ); | |
| 3514 | - die( wp_json_encode( (object) compact( 'error', 'error_description' ) ) ); | |
| 3955 | + wp_send_json( (object) compact( 'error', 'error_description' ), $status_code, JSON_UNESCAPED_SLASHES ); | |
| 3515 | 3956 | } |
| 3516 | 3957 | |
| 3517 | - status_header( 200 ); | |
| 3518 | 3958 | if ( true === $response ) { |
| 3519 | - exit; | |
| 3959 | + status_header( 200 ); | |
| 3960 | + exit( 0 ); | |
| 3520 | 3961 | } |
| 3521 | 3962 | |
| 3522 | - die( wp_json_encode( (object) $response ) ); | |
| 3963 | + wp_send_json( (object) $response, 200, JSON_UNESCAPED_SLASHES ); | |
| 3523 | 3964 | } |
| 3524 | 3965 | |
| 3525 | 3966 | /** |
| 3526 | 3967 | * Uploads a file gotten from the global $_FILES. |
| @@ -3528,9 +3969,9 @@ | ||
| 3528 | 3969 | * the attachment file of the media item (gotten through of the post_id) |
| 3529 | 3970 | * will be updated instead of add a new one. |
| 3530 | 3971 | * |
| 3531 | 3972 | * @param boolean $update_media_item - update media attachment. |
| 3532 | - * @return array - An array describing the uploadind files process. | |
| 3973 | + * @return array|WP_Error - An array describing the uploading files process. | |
| 3533 | 3974 | */ |
| 3534 | 3975 | public function upload_handler( $update_media_item = false ) { |
| 3535 | 3976 | if ( isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' !== strtoupper( sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) ) ) { |
| 3536 | 3977 | return new WP_Error( 405, get_status_header_desc( 405 ), 405 ); |
| @@ -3581,9 +4022,9 @@ | ||
| 3581 | 4022 | return new WP_Error( 'handler_cannot_upload', __( 'The upload handler cannot upload files', 'jetpack' ), 400 ); |
| 3582 | 4023 | } |
| 3583 | 4024 | |
| 3584 | 4025 | $uploaded_files = array(); |
| 3585 | - $global_post = isset( $GLOBALS['post'] ) ? $GLOBALS['post'] : null; | |
| 4026 | + $global_post = $GLOBALS['post'] ?? null; | |
| 3586 | 4027 | unset( $GLOBALS['post'] ); |
| 3587 | 4028 | if ( empty( $_FILES['media']['name'] ) ) { |
| 3588 | 4029 | // Nothing to process, just return. |
| 3589 | 4030 | return $uploaded_files; |
| @@ -3590,9 +4031,9 @@ | ||
| 3590 | 4031 | } |
| 3591 | 4032 | foreach ( $_FILES['media']['name'] as $index => $name ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- As above, unslash sniff is wrong. Validation should happen below. |
| 3592 | 4033 | $file = array(); |
| 3593 | 4034 | foreach ( $media_keys as $media_key ) { |
| 3594 | - $file[ $media_key ] = isset( $_FILES['media'][ $media_key ][ $index ] ) ? $_FILES['media'][ $media_key ][ $index ] : null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- As above, the unslash sniff is wrong. | |
| 4035 | + $file[ $media_key ] = $_FILES['media'][ $media_key ][ $index ] ?? null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,,WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- As above, the unslash sniff is wrong. | |
| 3595 | 4036 | } |
| 3596 | 4037 | |
| 3597 | 4038 | list( $hmac_provided, $salt ) = isset( $_POST['_jetpack_file_hmac_media'][ $index ] ) ? explode( ':', filter_var( wp_unslash( $_POST['_jetpack_file_hmac_media'][ $index ] ) ) ) : array( 'no', '' ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce should have been checked by the caller. |
| 3598 | 4039 | |
| @@ -3638,9 +4079,9 @@ | ||
| 3638 | 4079 | 'type' => (string) $edited_media_item->post_mime_type, |
| 3639 | 4080 | 'meta' => (array) wp_get_attachment_metadata( $post_id ), |
| 3640 | 4081 | ); |
| 3641 | 4082 | |
| 3642 | - return (array) array( $response ); | |
| 4083 | + return array( $response ); | |
| 3643 | 4084 | } |
| 3644 | 4085 | |
| 3645 | 4086 | $attachment_id = media_handle_upload( |
| 3646 | 4087 | '.jetpack.upload.', |
| @@ -3679,67 +4120,8 @@ | ||
| 3679 | 4120 | return $uploaded_files; |
| 3680 | 4121 | } |
| 3681 | 4122 | |
| 3682 | 4123 | /** |
| 3683 | - * Add help to the Jetpack page | |
| 3684 | - * | |
| 3685 | - * @since Jetpack (1.2.3) | |
| 3686 | - * @return void | |
| 3687 | - */ | |
| 3688 | - public function admin_help() { | |
| 3689 | - $current_screen = get_current_screen(); | |
| 3690 | - | |
| 3691 | - // Overview. | |
| 3692 | - $current_screen->add_help_tab( | |
| 3693 | - array( | |
| 3694 | - 'id' => 'home', | |
| 3695 | - 'title' => __( 'Home', 'jetpack' ), | |
| 3696 | - 'content' => | |
| 3697 | - '<p><strong>' . __( 'Jetpack', 'jetpack' ) . '</strong></p>' . | |
| 3698 | - '<p>' . __( 'Jetpack supercharges your self-hosted WordPress site with the awesome cloud power of WordPress.com.', 'jetpack' ) . '</p>' . | |
| 3699 | - '<p>' . __( 'On this page, you are able to view the modules available within Jetpack, learn more about them, and activate or deactivate them as needed.', 'jetpack' ) . '</p>', | |
| 3700 | - ) | |
| 3701 | - ); | |
| 3702 | - | |
| 3703 | - // Screen Content. | |
| 3704 | - if ( current_user_can( 'manage_options' ) ) { | |
| 3705 | - $current_screen->add_help_tab( | |
| 3706 | - array( | |
| 3707 | - 'id' => 'settings', | |
| 3708 | - 'title' => __( 'Settings', 'jetpack' ), | |
| 3709 | - 'content' => | |
| 3710 | - '<p><strong>' . __( 'Jetpack', 'jetpack' ) . '</strong></p>' . | |
| 3711 | - '<p>' . __( 'You can activate or deactivate individual Jetpack modules to suit your needs.', 'jetpack' ) . '</p>' . | |
| 3712 | - '<ol>' . | |
| 3713 | - '<li>' . __( 'Each module has an Activate or Deactivate link so you can toggle one individually.', 'jetpack' ) . '</li>' . | |
| 3714 | - '<li>' . __( 'Using the checkboxes next to each module, you can select multiple modules to toggle via the Bulk Actions menu at the top of the list.', 'jetpack' ) . '</li>' . | |
| 3715 | - '</ol>' . | |
| 3716 | - '<p>' . __( 'Using the tools on the right, you can search for specific modules, filter by module categories or which are active, or change the sorting order.', 'jetpack' ) . '</p>', | |
| 3717 | - ) | |
| 3718 | - ); | |
| 3719 | - } | |
| 3720 | - | |
| 3721 | - // Help Sidebar. | |
| 3722 | - $support_url = Redirect::get_url( 'jetpack-support' ); | |
| 3723 | - $faq_url = Redirect::get_url( 'jetpack-faq' ); | |
| 3724 | - $current_screen->set_help_sidebar( | |
| 3725 | - '<p><strong>' . __( 'For more information:', 'jetpack' ) . '</strong></p>' . | |
| 3726 | - '<p><a href="' . $faq_url . '" rel="noopener noreferrer" target="_blank">' . __( 'Jetpack FAQ', 'jetpack' ) . '</a></p>' . | |
| 3727 | - '<p><a href="' . $support_url . '" rel="noopener noreferrer" target="_blank">' . __( 'Jetpack Support', 'jetpack' ) . '</a></p>' . | |
| 3728 | - '<p><a href="' . self::admin_url( array( 'page' => 'jetpack-debugger' ) ) . '">' . __( 'Jetpack Debugging Center', 'jetpack' ) . '</a></p>' | |
| 3729 | - ); | |
| 3730 | - } | |
| 3731 | - | |
| 3732 | - /** | |
| 3733 | - * Enqueues the jetpack-icons style. | |
| 3734 | - * | |
| 3735 | - * @return void | |
| 3736 | - */ | |
| 3737 | - public function admin_menu_css() { | |
| 3738 | - wp_enqueue_style( 'jetpack-icons' ); | |
| 3739 | - } | |
| 3740 | - | |
| 3741 | - /** | |
| 3742 | 4124 | * Add action links for the Jetpack plugin. |
| 3743 | 4125 | * |
| 3744 | 4126 | * @param array $actions Plugin actions. |
| 3745 | 4127 | * |
| @@ -3745,14 +4127,11 @@ | ||
| 3745 | 4127 | * |
| 3746 | 4128 | * @return array |
| 3747 | 4129 | */ |
| 3748 | 4130 | public function plugin_action_links( $actions ) { |
| 3749 | - $support_link = ( new Host() )->is_woa_site() ? 'https://wordpress.com/help/contact/' : self::admin_url( 'page=jetpack-debugger' ); | |
| 3750 | - | |
| 3751 | 4131 | if ( current_user_can( 'jetpack_manage_modules' ) && ( self::is_connection_ready() || ( new Status() )->is_offline_mode() ) ) { |
| 3752 | 4132 | return array_merge( |
| 3753 | - array( 'settings' => sprintf( '<a href="%s">%s</a>', self::admin_url( 'page=jetpack#/settings' ), __( 'Settings', 'jetpack' ) ) ), | |
| 3754 | - array( 'support' => sprintf( '<a href="%s">%s</a>', $support_link, __( 'Support', 'jetpack' ) ) ), | |
| 4133 | + array( 'settings' => sprintf( '<a href="%s">%s</a>', esc_url( self::admin_url( 'page=jetpack#/settings' ) ), __( 'Settings', 'jetpack' ) ) ), | |
| 3755 | 4134 | $actions |
| 3756 | 4135 | ); |
| 3757 | 4136 | } |
| 3758 | 4137 | |
| @@ -3759,53 +4138,8 @@ | ||
| 3759 | 4138 | return $actions; |
| 3760 | 4139 | } |
| 3761 | 4140 | |
| 3762 | 4141 | /** |
| 3763 | - * Add an activation modal to the plugins page and the main dashboard. | |
| 3764 | - * | |
| 3765 | - * @param string $hook The current admin page. | |
| 3766 | - * | |
| 3767 | - * @return void | |
| 3768 | - */ | |
| 3769 | - public function activate_dialog( $hook ) { | |
| 3770 | - /* | |
| 3771 | - * We do not need it on other plugin pages, | |
| 3772 | - * or when Jetpack is already connected. | |
| 3773 | - */ | |
| 3774 | - if ( | |
| 3775 | - ! in_array( $hook, array( 'plugins.php', 'index.php' ), true ) | |
| 3776 | - || self::is_connection_ready() | |
| 3777 | - ) { | |
| 3778 | - return; | |
| 3779 | - } | |
| 3780 | - | |
| 3781 | - // add an activation script that will pick up deactivation actions for the Jetpack plugin. | |
| 3782 | - Assets::register_script( | |
| 3783 | - 'jetpack-full-activation-modal-js', | |
| 3784 | - '_inc/build/activation-modal.js', | |
| 3785 | - JETPACK__PLUGIN_FILE, | |
| 3786 | - array( | |
| 3787 | - 'enqueue' => true, | |
| 3788 | - 'in_footer' => true, | |
| 3789 | - 'textdomain' => 'jetpack', | |
| 3790 | - 'dependencies' => array( | |
| 3791 | - 'wp-polyfill', | |
| 3792 | - 'wp-components', | |
| 3793 | - ), | |
| 3794 | - ) | |
| 3795 | - ); | |
| 3796 | - | |
| 3797 | - // Add objects to be passed to the initial state of the app. | |
| 3798 | - // Use wp_add_inline_script instead of wp_localize_script, see https://core.trac.wordpress.org/ticket/25280. | |
| 3799 | - wp_add_inline_script( 'jetpack-full-activation-modal-js', 'var Initial_State=JSON.parse(decodeURIComponent("' . rawurlencode( wp_json_encode( Jetpack_Redux_State_Helper::get_minimal_state() ) ) . '"));', 'before' ); | |
| 3800 | - | |
| 3801 | - // Adds Connection package initial state. | |
| 3802 | - Connection_Initial_State::render_script( 'jetpack-full-activation-modal-js' ); | |
| 3803 | - | |
| 3804 | - add_action( 'admin_notices', array( $this, 'jetpack_plugin_portal_containers' ) ); | |
| 3805 | - } | |
| 3806 | - | |
| 3807 | - /** | |
| 3808 | 4142 | * Adds the deactivation warning modal for Jetpack. |
| 3809 | 4143 | * |
| 3810 | 4144 | * @param string $hook The current admin page. |
| 3811 | 4145 | * |
| @@ -3825,14 +4159,10 @@ | ||
| 3825 | 4159 | 'jetpack-plugins-page-js', |
| 3826 | 4160 | '_inc/build/plugins-page.js', |
| 3827 | 4161 | JETPACK__PLUGIN_FILE, |
| 3828 | 4162 | array( |
| 3829 | - 'in_footer' => true, | |
| 3830 | - 'textdomain' => 'jetpack', | |
| 3831 | - 'dependencies' => array( | |
| 3832 | - 'wp-polyfill', | |
| 3833 | - 'wp-components', | |
| 3834 | - ), | |
| 4163 | + 'in_footer' => true, | |
| 4164 | + 'textdomain' => 'jetpack', | |
| 3835 | 4165 | ) |
| 3836 | 4166 | ); |
| 3837 | 4167 | Assets::enqueue_script( 'jetpack-plugins-page-js' ); |
| 3838 | 4168 | |
| @@ -3837,9 +4167,9 @@ | ||
| 3837 | 4167 | Assets::enqueue_script( 'jetpack-plugins-page-js' ); |
| 3838 | 4168 | |
| 3839 | 4169 | // Add objects to be passed to the initial state of the app. |
| 3840 | 4170 | // Use wp_add_inline_script instead of wp_localize_script, see https://core.trac.wordpress.org/ticket/25280. |
| 3841 | - wp_add_inline_script( 'jetpack-plugins-page-js', 'var Initial_State=JSON.parse(decodeURIComponent("' . rawurlencode( wp_json_encode( Jetpack_Redux_State_Helper::get_minimal_state() ) ) . '"));', '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' ); | |
| 3842 | 4172 | |
| 3843 | 4173 | add_action( 'admin_footer', array( $this, 'jetpack_plugin_portal_containers' ) ); |
| 3844 | 4174 | } |
| 3845 | 4175 | } |
| @@ -3888,9 +4218,9 @@ | ||
| 3888 | 4218 | // @todo provide way to go to specific calypso env. |
| 3889 | 4219 | self::get_calypso_host() . 'jetpack/connect' |
| 3890 | 4220 | ) |
| 3891 | 4221 | ); |
| 3892 | - exit; | |
| 4222 | + exit( 0 ); | |
| 3893 | 4223 | } |
| 3894 | 4224 | } |
| 3895 | 4225 | |
| 3896 | 4226 | /* |
| @@ -3925,8 +4255,28 @@ | ||
| 3925 | 4255 | * Done! |
| 3926 | 4256 | */ |
| 3927 | 4257 | |
| 3928 | 4258 | /** |
| 4259 | + * Build the user-facing description stored alongside a registration error code. | |
| 4260 | + * | |
| 4261 | + * @since 16.2 | |
| 4262 | + * | |
| 4263 | + * @param string $error_code The WP_Error code. | |
| 4264 | + * @param string $message The WP_Error message. | |
| 4265 | + * @return string The description, empty when the message is not user-facing copy. | |
| 4266 | + */ | |
| 4267 | + public static function get_registration_error_description( $error_code, $message ) { | |
| 4268 | + // Manager::validate_remote_register_response() does not always put user-facing copy in the | |
| 4269 | + // message slot: wpcom_5??, wpcom_408 and wpcom_bad_response store the HTTP status there, | |
| 4270 | + // and jetpack_id stores the raw response body, which can also overflow the state cookie. | |
| 4271 | + if ( 'jetpack_id' === $error_code || is_numeric( $message ) ) { | |
| 4272 | + return ''; | |
| 4273 | + } | |
| 4274 | + | |
| 4275 | + return mb_substr( (string) $message, 0, 250 ); | |
| 4276 | + } | |
| 4277 | + | |
| 4278 | + /** | |
| 3929 | 4279 | * Handles the page load events for the Jetpack admin page |
| 3930 | 4280 | */ |
| 3931 | 4281 | public function admin_page_load() { |
| 3932 | 4282 | $error = false; |
| @@ -3962,10 +4312,11 @@ | ||
| 3962 | 4312 | $registered = static::connection()->try_registration(); |
| 3963 | 4313 | if ( is_wp_error( $registered ) ) { |
| 3964 | 4314 | $error = $registered->get_error_code(); |
| 3965 | 4315 | self::state( 'error', $error ); |
| 3966 | - self::state( 'error', $registered->get_error_message() ); | |
| 3967 | 4316 | |
| 4317 | + self::state( 'error_description', self::get_registration_error_description( $error, $registered->get_error_message() ) ); | |
| 4318 | + | |
| 3968 | 4319 | /** |
| 3969 | 4320 | * Jetpack registration Error. |
| 3970 | 4321 | * |
| 3971 | 4322 | * @since 7.5.0 |
| @@ -3989,12 +4340,8 @@ | ||
| 3989 | 4340 | do_action( 'jetpack_connection_register_success', $from ); |
| 3990 | 4341 | |
| 3991 | 4342 | $url = $this->build_connect_url( true, $redirect, $from ); |
| 3992 | 4343 | |
| 3993 | - if ( ! empty( $_GET['onboarding'] ) ) { | |
| 3994 | - $url = add_query_arg( 'onboarding', rawurlencode_deep( wp_unslash( $_GET['onboarding'] ) ), $url ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized | |
| 3995 | - } | |
| 3996 | - | |
| 3997 | 4344 | if ( ! empty( $_GET['auth_approved'] ) && 'true' === $_GET['auth_approved'] ) { |
| 3998 | 4345 | $url = add_query_arg( 'auth_approved', 'true', $url ); |
| 3999 | 4346 | } |
| 4000 | 4347 | |
| @@ -3999,9 +4346,9 @@ | ||
| 3999 | 4346 | } |
| 4000 | 4347 | |
| 4001 | 4348 | add_filter( 'allowed_redirect_hosts', array( Host::class, 'allow_wpcom_environments' ) ); |
| 4002 | 4349 | wp_safe_redirect( $url ); |
| 4003 | - exit; | |
| 4350 | + exit( 0 ); | |
| 4004 | 4351 | case 'activate': |
| 4005 | 4352 | if ( ! current_user_can( 'jetpack_activate_modules' ) ) { |
| 4006 | 4353 | $error = 'cheatin'; |
| 4007 | 4354 | break; |
| @@ -4015,9 +4362,9 @@ | ||
| 4015 | 4362 | self::state( 'error', sprintf( __( 'Could not activate %s', 'jetpack' ), $module ) ); |
| 4016 | 4363 | } |
| 4017 | 4364 | // The following two lines will rarely happen, as Jetpack::activate_module normally exits at the end. |
| 4018 | 4365 | wp_safe_redirect( self::admin_url( 'page=jetpack' ) ); |
| 4019 | - exit; | |
| 4366 | + exit( 0 ); | |
| 4020 | 4367 | case 'activate_default_modules': |
| 4021 | 4368 | check_admin_referer( 'activate_default_modules' ); |
| 4022 | 4369 | self::log( 'activate_default_modules' ); |
| 4023 | 4370 | self::restate(); |
| @@ -4025,9 +4372,9 @@ | ||
| 4025 | 4372 | $max_version = isset( $_GET['max_version'] ) ? sanitize_text_field( wp_unslash( $_GET['max_version'] ) ) : false; |
| 4026 | 4373 | $other_modules = isset( $_GET['other_modules'] ) && is_array( $_GET['other_modules'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_GET['other_modules'] ) ) : array(); |
| 4027 | 4374 | self::activate_default_modules( $min_version, $max_version, $other_modules ); |
| 4028 | 4375 | wp_safe_redirect( self::admin_url( 'page=jetpack' ) ); |
| 4029 | - exit; | |
| 4376 | + exit( 0 ); | |
| 4030 | 4377 | case 'disconnect': |
| 4031 | 4378 | if ( ! current_user_can( 'jetpack_disconnect' ) ) { |
| 4032 | 4379 | $error = 'cheatin'; |
| 4033 | 4380 | break; |
| @@ -4036,9 +4383,9 @@ | ||
| 4036 | 4383 | check_admin_referer( 'jetpack-disconnect' ); |
| 4037 | 4384 | self::log( 'disconnect' ); |
| 4038 | 4385 | self::disconnect(); |
| 4039 | 4386 | wp_safe_redirect( self::admin_url( 'disconnected=true' ) ); |
| 4040 | - exit; | |
| 4387 | + exit( 0 ); | |
| 4041 | 4388 | case 'reconnect': |
| 4042 | 4389 | if ( ! current_user_can( 'jetpack_reconnect' ) ) { |
| 4043 | 4390 | $error = 'cheatin'; |
| 4044 | 4391 | break; |
| @@ -4049,9 +4396,9 @@ | ||
| 4049 | 4396 | self::disconnect(); |
| 4050 | 4397 | |
| 4051 | 4398 | add_filter( 'allowed_redirect_hosts', array( Host::class, 'allow_wpcom_environments' ) ); |
| 4052 | 4399 | wp_safe_redirect( $this->build_connect_url( true, false, 'reconnect' ) ); |
| 4053 | - exit; | |
| 4400 | + exit( 0 ); | |
| 4054 | 4401 | case 'deactivate': |
| 4055 | 4402 | if ( ! current_user_can( 'jetpack_deactivate_modules' ) ) { |
| 4056 | 4403 | $error = 'cheatin'; |
| 4057 | 4404 | break; |
| @@ -4065,9 +4412,9 @@ | ||
| 4065 | 4412 | self::state( 'message', 'module_deactivated' ); |
| 4066 | 4413 | } |
| 4067 | 4414 | self::state( 'module', $modules ); |
| 4068 | 4415 | wp_safe_redirect( self::admin_url( 'page=jetpack' ) ); |
| 4069 | - exit; | |
| 4416 | + exit( 0 ); | |
| 4070 | 4417 | case 'unlink': |
| 4071 | 4418 | $redirect = isset( $_GET['redirect'] ) ? sanitize_text_field( wp_unslash( $_GET['redirect'] ) ) : ''; |
| 4072 | 4419 | check_admin_referer( 'jetpack-unlink' ); |
| 4073 | 4420 | self::log( 'unlink' ); |
| @@ -4077,32 +4424,9 @@ | ||
| 4077 | 4424 | wp_safe_redirect( admin_url() ); |
| 4078 | 4425 | } else { |
| 4079 | 4426 | wp_safe_redirect( self::admin_url( array( 'page' => rawurlencode( $redirect ) ) ) ); |
| 4080 | 4427 | } |
| 4081 | - exit; | |
| 4082 | - case 'onboard': | |
| 4083 | - if ( ! current_user_can( 'manage_options' ) ) { | |
| 4084 | - wp_safe_redirect( self::admin_url( 'page=jetpack' ) ); | |
| 4085 | - } else { | |
| 4086 | - self::create_onboarding_token(); | |
| 4087 | - $url = $this->build_connect_url( true ); | |
| 4088 | - | |
| 4089 | - $token = Jetpack_Options::get_option( 'onboarding' ); | |
| 4090 | - | |
| 4091 | - if ( false !== ( $token ) ) { | |
| 4092 | - $url = add_query_arg( 'onboarding', $token, $url ); | |
| 4093 | - } | |
| 4094 | - | |
| 4095 | - $calypso_env = ( new Host() )->get_calypso_env(); | |
| 4096 | - if ( ! empty( $calypso_env ) ) { | |
| 4097 | - $url = add_query_arg( 'calypso_env', $calypso_env, $url ); | |
| 4098 | - } | |
| 4099 | - | |
| 4100 | - add_filter( 'allowed_redirect_hosts', array( Host::class, 'allow_wpcom_environments' ) ); | |
| 4101 | - wp_safe_redirect( $url ); | |
| 4102 | - exit; | |
| 4103 | - } | |
| 4104 | - exit; | |
| 4428 | + exit( 0 ); | |
| 4105 | 4429 | default: |
| 4106 | 4430 | /** |
| 4107 | 4431 | * Fires when a Jetpack admin page is loaded with an unrecognized parameter. |
| 4108 | 4432 | * |
| @@ -4118,9 +4442,10 @@ | ||
| 4118 | 4442 | if ( ! $error ) { |
| 4119 | 4443 | self::activate_new_modules( true ); |
| 4120 | 4444 | } |
| 4121 | 4445 | |
| 4122 | - $message_code = self::state( 'message' ); | |
| 4446 | + $activated_manage = false; | |
| 4447 | + $message_code = self::state( 'message' ); | |
| 4123 | 4448 | if ( self::state( 'optin-manage' ) ) { |
| 4124 | 4449 | $activated_manage = $message_code; |
| 4125 | 4450 | $message_code = 'jetpack-manage'; |
| 4126 | 4451 | } |
| @@ -4294,17 +4619,19 @@ | ||
| 4294 | 4619 | count( $privacy_checks ), |
| 4295 | 4620 | '%1$s = deactivation URL, %2$s = "Deactivate {list of Jetpack module/feature names}', |
| 4296 | 4621 | 'jetpack' |
| 4297 | 4622 | ), |
| 4298 | - wp_nonce_url( | |
| 4299 | - self::admin_url( | |
| 4300 | - array( | |
| 4301 | - 'page' => 'jetpack', | |
| 4302 | - 'action' => 'deactivate', | |
| 4303 | - 'module' => rawurlencode( $module_slugs ), | |
| 4304 | - ) | |
| 4305 | - ), | |
| 4306 | - "jetpack_deactivate-$module_slugs" | |
| 4623 | + esc_url( | |
| 4624 | + wp_nonce_url( | |
| 4625 | + self::admin_url( | |
| 4626 | + array( | |
| 4627 | + 'page' => 'jetpack', | |
| 4628 | + 'action' => 'deactivate', | |
| 4629 | + 'module' => rawurlencode( $module_slugs ), | |
| 4630 | + ) | |
| 4631 | + ), | |
| 4632 | + "jetpack_deactivate-$module_slugs" | |
| 4633 | + ) | |
| 4307 | 4634 | ), |
| 4308 | 4635 | esc_attr( wp_kses( wp_sprintf( _x( 'Deactivate %l', '%l = list of Jetpack module/feature names', 'jetpack' ), $module_names ), array() ) ) |
| 4309 | 4636 | ), |
| 4310 | 4637 | array( |
| @@ -4322,37 +4649,8 @@ | ||
| 4322 | 4649 | endif; |
| 4323 | 4650 | } |
| 4324 | 4651 | |
| 4325 | 4652 | /** |
| 4326 | - * We can't always respond to a signed XML-RPC request with a | |
| 4327 | - * helpful error message. In some circumstances, doing so could | |
| 4328 | - * leak information. | |
| 4329 | - * | |
| 4330 | - * Instead, track that the error occurred via a Jetpack_Option, | |
| 4331 | - * and send that data back in the heartbeat. | |
| 4332 | - * All this does is increment a number, but it's enough to find | |
| 4333 | - * trends. | |
| 4334 | - * | |
| 4335 | - * @param WP_Error $xmlrpc_error The error produced during | |
| 4336 | - * signature validation. | |
| 4337 | - */ | |
| 4338 | - public function track_xmlrpc_error( $xmlrpc_error ) { | |
| 4339 | - $code = is_wp_error( $xmlrpc_error ) | |
| 4340 | - ? $xmlrpc_error->get_error_code() | |
| 4341 | - : 'should-not-happen'; | |
| 4342 | - | |
| 4343 | - $xmlrpc_errors = Jetpack_Options::get_option( 'xmlrpc_errors', array() ); | |
| 4344 | - if ( isset( $xmlrpc_errors[ $code ] ) && $xmlrpc_errors[ $code ] ) { | |
| 4345 | - // No need to update the option if we already have | |
| 4346 | - // this code stored. | |
| 4347 | - return; | |
| 4348 | - } | |
| 4349 | - $xmlrpc_errors[ $code ] = true; | |
| 4350 | - | |
| 4351 | - Jetpack_Options::update_option( 'xmlrpc_errors', $xmlrpc_errors, false ); | |
| 4352 | - } | |
| 4353 | - | |
| 4354 | - /** | |
| 4355 | 4653 | * Initialize the jetpack stats instance only when needed |
| 4356 | 4654 | * |
| 4357 | 4655 | * @return void |
| 4358 | 4656 | */ |
| @@ -4475,9 +4773,9 @@ | ||
| 4475 | 4773 | return $this->build_connect_url( $raw, $redirect, $from, true ); |
| 4476 | 4774 | } |
| 4477 | 4775 | } |
| 4478 | 4776 | |
| 4479 | - $url = $this->build_authorize_url( $redirect ); | |
| 4777 | + $url = ( new Authorize_Redirect( static::connection() ) )->build_authorize_url( $redirect ); | |
| 4480 | 4778 | } |
| 4481 | 4779 | |
| 4482 | 4780 | if ( $from ) { |
| 4483 | 4781 | $url = add_query_arg( 'from', $from, $url ); |
| @@ -4502,66 +4800,30 @@ | ||
| 4502 | 4800 | * @param null $deprecated Deprecated since Jetpack 10.9. |
| 4503 | 4801 | * |
| 4504 | 4802 | * @todo Update default value for redirect since the called function expects a string. |
| 4505 | 4803 | * |
| 4804 | + * @deprecated 13.4 | |
| 4805 | + * | |
| 4506 | 4806 | * @return mixed|void |
| 4507 | 4807 | */ |
| 4508 | 4808 | public static function build_authorize_url( $redirect = false, $deprecated = null ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable |
| 4809 | + _deprecated_function( __METHOD__, 'jetpack-13.4', 'Authorize_Redirect::build_authorize_url' ); | |
| 4509 | 4810 | |
| 4510 | - add_filter( 'jetpack_connect_request_body', array( __CLASS__, 'filter_connect_request_body' ) ); | |
| 4511 | - add_filter( 'jetpack_connect_redirect_url', array( __CLASS__, 'filter_connect_redirect_url' ) ); | |
| 4512 | - | |
| 4513 | - $c8n = self::connection(); | |
| 4514 | - $url = $c8n->get_authorization_url( wp_get_current_user(), $redirect ); | |
| 4515 | - | |
| 4516 | - remove_filter( 'jetpack_connect_request_body', array( __CLASS__, 'filter_connect_request_body' ) ); | |
| 4517 | - remove_filter( 'jetpack_connect_redirect_url', array( __CLASS__, 'filter_connect_redirect_url' ) ); | |
| 4518 | - | |
| 4519 | - /** | |
| 4520 | - * Filter the URL used when authorizing a user to a WordPress.com account. | |
| 4521 | - * | |
| 4522 | - * @since 8.9.0 | |
| 4523 | - * | |
| 4524 | - * @param string $url Connection URL. | |
| 4525 | - */ | |
| 4526 | - return apply_filters( 'jetpack_build_authorize_url', $url ); | |
| 4811 | + return ( new Authorize_Redirect( static::connection() ) )->build_authorize_url( $redirect ); | |
| 4527 | 4812 | } |
| 4528 | 4813 | |
| 4529 | 4814 | /** |
| 4530 | 4815 | * Filters the connection URL parameter array. |
| 4531 | 4816 | * |
| 4817 | + * @deprecated 13.4 | |
| 4818 | + * | |
| 4532 | 4819 | * @param array $args default URL parameters used by the package. |
| 4533 | 4820 | * @return array the modified URL arguments array. |
| 4534 | 4821 | */ |
| 4535 | 4822 | public static function filter_connect_request_body( $args ) { |
| 4536 | - if ( | |
| 4537 | - Constants::is_defined( 'JETPACK__GLOTPRESS_LOCALES_PATH' ) | |
| 4538 | - && include_once Constants::get_constant( 'JETPACK__GLOTPRESS_LOCALES_PATH' ) | |
| 4539 | - ) { | |
| 4540 | - $gp_locale = GP_Locales::by_field( 'wp_locale', get_locale() ); | |
| 4541 | - $args['locale'] = isset( $gp_locale ) && isset( $gp_locale->slug ) | |
| 4542 | - ? $gp_locale->slug | |
| 4543 | - : ''; | |
| 4544 | - } | |
| 4823 | + _deprecated_function( __METHOD__, 'jetpack-13.4', 'Authorize_Redirect::filter_connect_request_body' ); | |
| 4545 | 4824 | |
| 4546 | - $tracking = new Tracking(); | |
| 4547 | - $tracks_identity = $tracking->tracks_get_identity( $args['state'] ); | |
| 4548 | - | |
| 4549 | - $args = array_merge( | |
| 4550 | - $args, | |
| 4551 | - array( | |
| 4552 | - '_ui' => $tracks_identity['_ui'], | |
| 4553 | - '_ut' => $tracks_identity['_ut'], | |
| 4554 | - ) | |
| 4555 | - ); | |
| 4556 | - | |
| 4557 | - $calypso_env = ( new Host() )->get_calypso_env(); | |
| 4558 | - | |
| 4559 | - if ( ! empty( $calypso_env ) ) { | |
| 4560 | - $args['calypso_env'] = $calypso_env; | |
| 4561 | - } | |
| 4562 | - | |
| 4563 | - return $args; | |
| 4825 | + return Authorize_Redirect::filter_connect_request_body( $args ); | |
| 4564 | 4826 | } |
| 4565 | 4827 | |
| 4566 | 4828 | /** |
| 4567 | 4829 | * Filters the `jetpack/v4/connection/data` API response of the Connection package in order to |
| @@ -4598,41 +4860,19 @@ | ||
| 4598 | 4860 | return $current_user_connection_data; |
| 4599 | 4861 | } |
| 4600 | 4862 | |
| 4601 | 4863 | /** |
| 4602 | - * Filters the URL that will process the connection data. It can be different from the URL | |
| 4603 | - * that we send the user to after everything is done. | |
| 4604 | - * | |
| 4605 | - * @param String $processing_url the default redirect URL used by the package. | |
| 4606 | - * @return String the modified URL. | |
| 4607 | - * | |
| 4608 | - * @deprecated since Jetpack 9.5.0 | |
| 4609 | - */ | |
| 4610 | - public static function filter_connect_processing_url( $processing_url ) { | |
| 4611 | - _deprecated_function( __METHOD__, 'jetpack-9.5' ); | |
| 4612 | - | |
| 4613 | - $processing_url = admin_url( 'admin.php?page=jetpack' ); // Making PHPCS happy. | |
| 4614 | - return $processing_url; | |
| 4615 | - } | |
| 4616 | - | |
| 4617 | - /** | |
| 4618 | 4864 | * Filters the redirection URL that is used for connect requests. The redirect |
| 4619 | 4865 | * URL should return the user back to the Jetpack console. |
| 4620 | 4866 | * |
| 4867 | + * @deprecated 13.4 | |
| 4868 | + * | |
| 4621 | 4869 | * @param String $redirect the default redirect URL used by the package. |
| 4622 | 4870 | * @return String the modified URL. |
| 4623 | 4871 | */ |
| 4624 | 4872 | public static function filter_connect_redirect_url( $redirect ) { |
| 4625 | - $jetpack_admin_page = esc_url_raw( admin_url( 'admin.php?page=jetpack' ) ); | |
| 4626 | - $redirect = $redirect | |
| 4627 | - ? wp_validate_redirect( esc_url_raw( $redirect ), $jetpack_admin_page ) | |
| 4628 | - : $jetpack_admin_page; | |
| 4629 | - | |
| 4630 | - if ( isset( $_REQUEST['is_multisite'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- not making a site change here. | |
| 4631 | - $redirect = Jetpack_Network::init()->get_url( 'network_admin_page' ); | |
| 4632 | - } | |
| 4633 | - | |
| 4634 | - return $redirect; | |
| 4873 | + _deprecated_function( __METHOD__, 'jetpack-13.4', 'Authorize_Redirect::filter_connect_redirect_url' ); | |
| 4874 | + return Authorize_Redirect::filter_connect_redirect_url( $redirect ); | |
| 4635 | 4875 | } |
| 4636 | 4876 | |
| 4637 | 4877 | /** |
| 4638 | 4878 | * This action fires at the beginning of the Manager::authorize method. |
| @@ -4696,11 +4936,8 @@ | ||
| 4696 | 4936 | * |
| 4697 | 4937 | * @param array $data The request data. |
| 4698 | 4938 | */ |
| 4699 | 4939 | public static function authorize_ending_authorized( $data ) { |
| 4700 | - // If this site has been through the Jetpack Onboarding flow, delete the onboarding token. | |
| 4701 | - self::invalidate_onboarding_token(); | |
| 4702 | - | |
| 4703 | 4940 | // If redirect_uri is SSO, ensure SSO module is enabled. |
| 4704 | 4941 | parse_str( wp_parse_url( $data['redirect_uri'], PHP_URL_QUERY ), $redirect_options ); |
| 4705 | 4942 | |
| 4706 | 4943 | /** This filter is documented in class.jetpack-cli.php */ |
| @@ -4824,13 +5061,9 @@ | ||
| 4824 | 5061 | * |
| 4825 | 5062 | * @return int 0 if the same sort or (+/-) to indicate which is greater. |
| 4826 | 5063 | */ |
| 4827 | 5064 | public static function sort_modules( $a, $b ) { |
| 4828 | - if ( $a['sort'] === $b['sort'] ) { | |
| 4829 | - return 0; | |
| 4830 | - } | |
| 4831 | - | |
| 4832 | - return ( $a['sort'] < $b['sort'] ) ? -1 : 1; | |
| 5065 | + return $a['sort'] <=> $b['sort']; | |
| 4833 | 5066 | } |
| 4834 | 5067 | |
| 4835 | 5068 | /** |
| 4836 | 5069 | * Recheck SSL status for use via an AJAX call. |
| @@ -4844,10 +5077,12 @@ | ||
| 4844 | 5077 | $result = self::permit_ssl( true ); |
| 4845 | 5078 | wp_send_json( |
| 4846 | 5079 | array( |
| 4847 | 5080 | 'enabled' => $result, |
| 4848 | - 'message' => get_transient( 'jetpack_https_test_message' ), | |
| 4849 | - ) | |
| 5081 | + 'message' => self::get_ssl_test_message(), | |
| 5082 | + ), | |
| 5083 | + null, // @phan-suppress-current-line PhanTypeMismatchArgumentProbablyReal -- It takes null, but its phpdoc only says int. | |
| 5084 | + JSON_UNESCAPED_SLASHES | |
| 4850 | 5085 | ); |
| 4851 | 5086 | } |
| 4852 | 5087 | |
| 4853 | 5088 | /* Client API */ |
| @@ -4854,8 +5089,10 @@ | ||
| 4854 | 5089 | |
| 4855 | 5090 | /** |
| 4856 | 5091 | * Verify the onboarding token. |
| 4857 | 5092 | * |
| 5093 | + * @deprecated since 13.9 | |
| 5094 | + * | |
| 4858 | 5095 | * @param array $token_data Token data. |
| 4859 | 5096 | * @param string $token Token value. |
| 4860 | 5097 | * @param string $request_data JSON-encoded request data. |
| 4861 | 5098 | * |
| @@ -4861,8 +5098,9 @@ | ||
| 4861 | 5098 | * |
| 4862 | 5099 | * @return mixed |
| 4863 | 5100 | */ |
| 4864 | 5101 | public static function verify_onboarding_token( $token_data, $token, $request_data ) { |
| 5102 | + _deprecated_function( __METHOD__, '13.9' ); | |
| 4865 | 5103 | // Default to a blog token. |
| 4866 | 5104 | $token_type = 'blog'; |
| 4867 | 5105 | |
| 4868 | 5106 | // Let's see if this is onboarding. In such case, use user token type and the provided user id. |
| @@ -4890,9 +5128,9 @@ | ||
| 4890 | 5128 | $jp_user = get_user_by( 'email', $jpo_user ); |
| 4891 | 5129 | if ( is_a( $jp_user, 'WP_User' ) ) { |
| 4892 | 5130 | wp_set_current_user( $jp_user->ID ); |
| 4893 | 5131 | $user_can = is_multisite() |
| 4894 | - ? current_user_can_for_blog( get_current_blog_id(), 'manage_options' ) | |
| 5132 | + ? current_user_can_for_site( get_current_blog_id(), 'manage_options' ) | |
| 4895 | 5133 | : current_user_can( 'manage_options' ); |
| 4896 | 5134 | if ( $user_can ) { |
| 4897 | 5135 | $token_type = 'user'; |
| 4898 | 5136 | $token->external_user_id = $jp_user->ID; |
| @@ -4909,11 +5147,13 @@ | ||
| 4909 | 5147 | |
| 4910 | 5148 | /** |
| 4911 | 5149 | * Create a random secret for validating onboarding payload |
| 4912 | 5150 | * |
| 5151 | + * @deprecated since 13.9 | |
| 4913 | 5152 | * @return string Secret token |
| 4914 | 5153 | */ |
| 4915 | 5154 | public static function create_onboarding_token() { |
| 5155 | + _deprecated_function( __METHOD__, '13.9' ); | |
| 4916 | 5156 | $token = Jetpack_Options::get_option( 'onboarding' ); |
| 4917 | 5157 | if ( false === ( $token ) ) { |
| 4918 | 5158 | $token = wp_generate_password( 32, false ); |
| 4919 | 5159 | Jetpack_Options::update_option( 'onboarding', $token ); |
| @@ -4924,11 +5164,13 @@ | ||
| 4924 | 5164 | |
| 4925 | 5165 | /** |
| 4926 | 5166 | * Remove the onboarding token |
| 4927 | 5167 | * |
| 5168 | + * @deprecated since 13.9 | |
| 4928 | 5169 | * @return bool True on success, false on failure |
| 4929 | 5170 | */ |
| 4930 | 5171 | public static function invalidate_onboarding_token() { |
| 5172 | + _deprecated_function( __METHOD__, '13.9' ); | |
| 4931 | 5173 | return Jetpack_Options::delete_option( 'onboarding' ); |
| 4932 | 5174 | } |
| 4933 | 5175 | |
| 4934 | 5176 | /** |
| @@ -4933,8 +5175,10 @@ | ||
| 4933 | 5175 | |
| 4934 | 5176 | /** |
| 4935 | 5177 | * Validate an onboarding token for a specific action |
| 4936 | 5178 | * |
| 5179 | + * @deprecated since 13.9 | |
| 5180 | + * | |
| 4937 | 5181 | * @param string $token Onboarding token. |
| 4938 | 5182 | * @param string $action Action name. |
| 4939 | 5183 | * |
| 4940 | 5184 | * @return boolean True if token/action pair is accepted, false if not |
| @@ -4939,8 +5183,9 @@ | ||
| 4939 | 5183 | * |
| 4940 | 5184 | * @return boolean True if token/action pair is accepted, false if not |
| 4941 | 5185 | */ |
| 4942 | 5186 | public static function validate_onboarding_token_action( $token, $action ) { |
| 5187 | + _deprecated_function( __METHOD__, '13.9' ); | |
| 4943 | 5188 | // Compare tokens, bail if tokens do not match. |
| 4944 | 5189 | if ( ! hash_equals( $token, Jetpack_Options::get_option( 'onboarding' ) ) ) { |
| 4945 | 5190 | return false; |
| 4946 | 5191 | } |
| @@ -4966,39 +5211,33 @@ | ||
| 4966 | 5211 | * @return boolean |
| 4967 | 5212 | * @since 2.3.3 |
| 4968 | 5213 | */ |
| 4969 | 5214 | public static function permit_ssl( $force_recheck = false ) { |
| 4970 | - // Do some fancy tests to see if ssl is being supported. | |
| 4971 | - if ( ! $force_recheck ) { | |
| 4972 | - $ssl = get_transient( 'jetpack_https_test' ); | |
| 4973 | - } | |
| 5215 | + // Delegates to the canonical SSL check in the Connection package. | |
| 5216 | + return Heartbeat::permit_ssl( $force_recheck ); | |
| 5217 | + } | |
| 4974 | 5218 | |
| 4975 | - if ( $force_recheck || false === $ssl ) { | |
| 4976 | - $message = ''; | |
| 4977 | - if ( 'https' !== substr( JETPACK__API_BASE, 0, 5 ) ) { | |
| 4978 | - $ssl = 0; | |
| 4979 | - } else { | |
| 4980 | - $ssl = 1; | |
| 5219 | + /** | |
| 5220 | + * Returns a localized message describing the last SSL connectivity failure, if any. | |
| 5221 | + * | |
| 5222 | + * The Connection package's canonical SSL check stores a neutral reason code; this maps it to | |
| 5223 | + * a translated, `jetpack`-domain message for display in the admin notice and AJAX recheck. | |
| 5224 | + * | |
| 5225 | + * @since 16.1 | |
| 5226 | + * | |
| 5227 | + * @return string The localized message, or an empty string when there is no failure. | |
| 5228 | + */ | |
| 5229 | + public static function get_ssl_test_message() { | |
| 5230 | + $error = Heartbeat::get_ssl_test_error(); | |
| 4981 | 5231 | |
| 4982 | - if ( ! wp_http_supports( array( 'ssl' => true ) ) ) { | |
| 4983 | - $ssl = 0; | |
| 4984 | - $message = __( 'WordPress reports no SSL support', 'jetpack' ); | |
| 4985 | - } else { | |
| 4986 | - $response = wp_remote_get( JETPACK__API_BASE . 'test/1/' ); | |
| 4987 | - if ( is_wp_error( $response ) ) { | |
| 4988 | - $ssl = 0; | |
| 4989 | - $message = __( 'WordPress reports no SSL support', 'jetpack' ); | |
| 4990 | - } elseif ( 'OK' !== wp_remote_retrieve_body( $response ) ) { | |
| 4991 | - $ssl = 0; | |
| 4992 | - $message = __( 'Response was not OK: ', 'jetpack' ) . wp_remote_retrieve_body( $response ); | |
| 4993 | - } | |
| 4994 | - } | |
| 4995 | - } | |
| 4996 | - set_transient( 'jetpack_https_test', $ssl, DAY_IN_SECONDS ); | |
| 4997 | - set_transient( 'jetpack_https_test_message', $message, DAY_IN_SECONDS ); | |
| 5232 | + switch ( $error['code'] ) { | |
| 5233 | + case 'no_ssl_support': | |
| 5234 | + return __( 'WordPress reports no SSL support', 'jetpack' ); | |
| 5235 | + case 'bad_response': | |
| 5236 | + return __( 'Response was not OK: ', 'jetpack' ) . $error['detail']; | |
| 5237 | + default: | |
| 5238 | + return ''; | |
| 4998 | 5239 | } |
| 4999 | - | |
| 5000 | - return (bool) $ssl; | |
| 5001 | 5240 | } |
| 5002 | 5241 | |
| 5003 | 5242 | /** |
| 5004 | 5243 | * Displays an admin_notice, alerting the user that outbound SSL isn't working. |
| @@ -5017,9 +5256,9 @@ | ||
| 5017 | 5256 | <p><?php esc_html_e( 'Your site could not connect to WordPress.com via HTTPS. This could be due to any number of reasons, including faulty SSL certificates, misconfigured or missing SSL libraries, or network issues.', 'jetpack' ); ?></p> |
| 5018 | 5257 | <p> |
| 5019 | 5258 | <?php esc_html_e( 'Jetpack will re-test for HTTPS support once a day, but you can click here to try again immediately: ', 'jetpack' ); ?> |
| 5020 | 5259 | <a href="#" id="jetpack-recheck-ssl-button"><?php esc_html_e( 'Try again', 'jetpack' ); ?></a> |
| 5021 | - <span id="jetpack-recheck-ssl-output"><?php echo esc_html( get_transient( 'jetpack_https_test_message' ) ); ?></span> | |
| 5260 | + <span id="jetpack-recheck-ssl-output"><?php echo esc_html( self::get_ssl_test_message() ); ?></span> | |
| 5022 | 5261 | </p> |
| 5023 | 5262 | <p> |
| 5024 | 5263 | <?php |
| 5025 | 5264 | printf( |
| @@ -5038,18 +5277,18 @@ | ||
| 5038 | 5277 | <script type="text/javascript"> |
| 5039 | 5278 | jQuery( document ).ready( function( $ ) { |
| 5040 | 5279 | $( '#jetpack-recheck-ssl-button' ).click( function( e ) { |
| 5041 | 5280 | var $this = $( this ); |
| 5042 | - $this.html( <?php echo wp_json_encode( __( 'Checking', 'jetpack' ) ); ?> ); | |
| 5281 | + $this.html( <?php echo wp_json_encode( esc_html__( 'Checking', 'jetpack' ), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?> ); | |
| 5043 | 5282 | $( '#jetpack-recheck-ssl-output' ).html( '' ); |
| 5044 | 5283 | e.preventDefault(); |
| 5045 | - var data = { action: 'jetpack-recheck-ssl', 'ajax-nonce': <?php echo wp_json_encode( $ajax_nonce ); ?> }; | |
| 5284 | + var data = { action: 'jetpack-recheck-ssl', 'ajax-nonce': <?php echo wp_json_encode( $ajax_nonce, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?> }; | |
| 5046 | 5285 | $.post( ajaxurl, data ) |
| 5047 | 5286 | .done( function( response ) { |
| 5048 | 5287 | if ( response.enabled ) { |
| 5049 | 5288 | $( '#jetpack-ssl-warning' ).hide(); |
| 5050 | 5289 | } else { |
| 5051 | - this.html( <?php echo wp_json_encode( __( 'Try again', 'jetpack' ) ); ?> ); | |
| 5290 | + this.html( <?php echo wp_json_encode( esc_html__( 'Try again', 'jetpack' ), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?> ); | |
| 5052 | 5291 | $( '#jetpack-recheck-ssl-output' ).html( 'SSL Failed: ' + response.message ); |
| 5053 | 5292 | } |
| 5054 | 5293 | }.bind( $this ) ); |
| 5055 | 5294 | } ); |
| @@ -5075,26 +5314,8 @@ | ||
| 5075 | 5314 | return $jetpack->connection_manager; |
| 5076 | 5315 | } |
| 5077 | 5316 | |
| 5078 | 5317 | /** |
| 5079 | - * Creates two secret tokens and the end of life timestamp for them. | |
| 5080 | - * | |
| 5081 | - * Note these tokens are unique per call, NOT static per site for connecting. | |
| 5082 | - * | |
| 5083 | - * @deprecated 9.5 Use Automattic\Jetpack\Connection\Secrets->generate() instead. | |
| 5084 | - * | |
| 5085 | - * @since 2.6 | |
| 5086 | - * @param String $action The action name. | |
| 5087 | - * @param Integer $user_id The user identifier. | |
| 5088 | - * @param Integer $exp Expiration time in seconds. | |
| 5089 | - * @return array | |
| 5090 | - */ | |
| 5091 | - public static function generate_secrets( $action, $user_id = false, $exp = 600 ) { | |
| 5092 | - _deprecated_function( __METHOD__, 'jetpack-9.5', 'Automattic\\Jetpack\\Connection\\Secrets->generate' ); | |
| 5093 | - return self::connection()->generate_secrets( $action, $user_id, $exp ); | |
| 5094 | - } | |
| 5095 | - | |
| 5096 | - /** | |
| 5097 | 5318 | * Get verification secrets. |
| 5098 | 5319 | * |
| 5099 | 5320 | * @param string $action Action name. |
| 5100 | 5321 | * @param int $user_id User ID. |
| @@ -5115,35 +5336,8 @@ | ||
| 5115 | 5336 | return $secrets; |
| 5116 | 5337 | } |
| 5117 | 5338 | |
| 5118 | 5339 | /** |
| 5119 | - * Register a connection. | |
| 5120 | - * | |
| 5121 | - * @deprecated Jetpack 9.7.0 | |
| 5122 | - * @see Automattic\Jetpack\Connection\Manager::try_registration() | |
| 5123 | - * | |
| 5124 | - * @return bool|WP_Error | |
| 5125 | - */ | |
| 5126 | - public static function register() { | |
| 5127 | - _deprecated_function( __METHOD__, 'jetpack-9.7', 'Automattic\\Jetpack\\Connection\\Manager::try_registration' ); | |
| 5128 | - return static::connection()->try_registration( false ); | |
| 5129 | - } | |
| 5130 | - | |
| 5131 | - /** | |
| 5132 | - * Filters the registration request body to include tracking properties. | |
| 5133 | - * | |
| 5134 | - * @deprecated Jetpack 9.7.0 | |
| 5135 | - * @see Automattic\Jetpack\Connection\Utils::filter_register_request_body() | |
| 5136 | - * | |
| 5137 | - * @param array $properties Token request properties. | |
| 5138 | - * @return array amended properties. | |
| 5139 | - */ | |
| 5140 | - public static function filter_register_request_body( $properties ) { | |
| 5141 | - _deprecated_function( __METHOD__, 'jetpack-9.7', 'Automattic\\Jetpack\\Connection\\Utils::filter_register_request_body' ); | |
| 5142 | - return Connection_Utils::filter_register_request_body( $properties ); | |
| 5143 | - } | |
| 5144 | - | |
| 5145 | - /** | |
| 5146 | 5340 | * Filters the token request body to include tracking properties. |
| 5147 | 5341 | * |
| 5148 | 5342 | * @param array $properties Token request properties. |
| 5149 | 5343 | * |
| @@ -5164,9 +5358,9 @@ | ||
| 5164 | 5358 | |
| 5165 | 5359 | /** |
| 5166 | 5360 | * If the db version is showing something other that what we've got now, bump it to current. |
| 5167 | 5361 | * |
| 5168 | - * @return bool: True if the option was incorrect and updated, false if nothing happened. | |
| 5362 | + * @return bool True if the option was incorrect and updated, false if nothing happened. | |
| 5169 | 5363 | */ |
| 5170 | 5364 | public static function maybe_set_version_option() { |
| 5171 | 5365 | list( $version ) = explode( ':', Jetpack_Options::get_option( 'version' ) ); |
| 5172 | 5366 | if ( JETPACK__VERSION !== $version ) { |
| @@ -5184,21 +5378,8 @@ | ||
| 5184 | 5378 | |
| 5185 | 5379 | /* Client Server API */ |
| 5186 | 5380 | |
| 5187 | 5381 | /** |
| 5188 | - * Loads the Jetpack XML-RPC client. | |
| 5189 | - * No longer necessary, as the XML-RPC client will be automagically loaded. | |
| 5190 | - * | |
| 5191 | - * Note: we cannot remove this function yet as it is used in this plugin: | |
| 5192 | - * https://wordpress.org/plugins/jetpack-subscription-form/ | |
| 5193 | - * | |
| 5194 | - * @deprecated since 7.7.0 | |
| 5195 | - */ | |
| 5196 | - public static function load_xml_rpc_client() { | |
| 5197 | - _deprecated_function( __METHOD__, 'jetpack-7.7' ); | |
| 5198 | - } | |
| 5199 | - | |
| 5200 | - /** | |
| 5201 | 5382 | * State is passed via cookies from one request to the next, but never to subsequent requests. |
| 5202 | 5383 | * SET: state( $key, $value ); |
| 5203 | 5384 | * GET: $value = state( $key ); |
| 5204 | 5385 | * |
| @@ -5272,20 +5453,8 @@ | ||
| 5272 | 5453 | |
| 5273 | 5454 | self::state( 'privacy_checks', $privacy_checks ); |
| 5274 | 5455 | } |
| 5275 | 5456 | |
| 5276 | - /** | |
| 5277 | - * Serve a WordPress.com static resource via a randomized wp.com subdomain. | |
| 5278 | - * | |
| 5279 | - * @deprecated 9.3.0 Use Assets::staticize_subdomain. | |
| 5280 | - * | |
| 5281 | - * @param string $url WordPress.com static resource URL. | |
| 5282 | - */ | |
| 5283 | - public static function staticize_subdomain( $url ) { | |
| 5284 | - _deprecated_function( __METHOD__, 'jetpack-9.3.0', 'Automattic\Jetpack\Assets::staticize_subdomain' ); | |
| 5285 | - return Assets::staticize_subdomain( $url ); | |
| 5286 | - } | |
| 5287 | - | |
| 5288 | 5457 | /* JSON API Authorization */ |
| 5289 | 5458 | |
| 5290 | 5459 | /** |
| 5291 | 5460 | * Handles the login action for Authorizing the JSON API |
| @@ -5290,13 +5459,14 @@ | ||
| 5290 | 5459 | /** |
| 5291 | 5460 | * Handles the login action for Authorizing the JSON API |
| 5292 | 5461 | */ |
| 5293 | 5462 | public function login_form_json_api_authorization() { |
| 5294 | - $this->verify_json_api_authorization_request(); | |
| 5463 | + $authorize_json_api = new Authorize_Json_Api(); | |
| 5464 | + $authorize_json_api->verify_json_api_authorization_request(); | |
| 5295 | 5465 | |
| 5296 | - add_action( 'wp_login', array( $this, 'store_json_api_authorization_token' ), 10, 2 ); | |
| 5466 | + add_action( 'wp_login', array( $authorize_json_api, 'store_json_api_authorization_token' ), 10, 2 ); | |
| 5297 | 5467 | |
| 5298 | - add_action( 'login_message', array( $this, 'login_message_json_api_authorization' ) ); | |
| 5468 | + add_action( 'login_message', array( $authorize_json_api, 'login_message_json_api_authorization' ) ); | |
| 5299 | 5469 | add_action( 'login_form', array( $this, 'preserve_action_in_login_form_for_json_api_authorization' ) ); |
| 5300 | 5470 | add_filter( 'site_url', array( $this, 'post_login_form_to_signed_url' ), 10, 3 ); |
| 5301 | 5471 | } |
| 5302 | 5472 | |
| @@ -5334,16 +5504,17 @@ | ||
| 5334 | 5504 | |
| 5335 | 5505 | /** |
| 5336 | 5506 | * If someone logs in to approve API access, store the Access Code in usermeta. |
| 5337 | 5507 | * |
| 5508 | + * @deprecated 13.4 | |
| 5509 | + * | |
| 5338 | 5510 | * @param string $user_login Unused. |
| 5339 | 5511 | * @param WP_User $user User logged in. |
| 5340 | 5512 | */ |
| 5341 | 5513 | public function store_json_api_authorization_token( $user_login, $user ) { |
| 5342 | - add_filter( 'login_redirect', array( $this, 'add_token_to_login_redirect_json_api_authorization' ), 10, 3 ); | |
| 5343 | - add_filter( 'allowed_redirect_hosts', array( $this, 'allow_wpcom_public_api_domain' ) ); | |
| 5344 | - $token = wp_generate_password( 32, false ); | |
| 5345 | - update_user_meta( $user->ID, 'jetpack_json_api_' . $this->json_api_authorization_request['client_id'], $token ); | |
| 5514 | + _deprecated_function( __METHOD__, 'jetpack-13.4', 'Automattic\\Jetpack\\Connection\\Authorize_Json_Api::store_json_api_authorization_token' ); | |
| 5515 | + | |
| 5516 | + return ( new Authorize_Json_Api() )->store_json_api_authorization_token( $user_login, $user ); | |
| 5346 | 5517 | } |
| 5347 | 5518 | |
| 5348 | 5519 | /** |
| 5349 | 5520 | * Add public-api.wordpress.com to the safe redirect allowed list - only added when someone allows API access. |
| @@ -5349,23 +5520,29 @@ | ||
| 5349 | 5520 | * Add public-api.wordpress.com to the safe redirect allowed list - only added when someone allows API access. |
| 5350 | 5521 | * |
| 5351 | 5522 | * To be used with a filter of allowed domains for a redirect. |
| 5352 | 5523 | * |
| 5524 | + * @deprecated 13.4 | |
| 5525 | + * | |
| 5353 | 5526 | * @param array $domains Allowed WP.com Environments. |
| 5354 | 5527 | */ |
| 5355 | 5528 | public function allow_wpcom_public_api_domain( $domains ) { |
| 5356 | - $domains[] = 'public-api.wordpress.com'; | |
| 5357 | - return $domains; | |
| 5529 | + _deprecated_function( __METHOD__, 'jetpack-13.4', 'Automattic\\Jetpack\\Status\\Host::allow_wpcom_public_api_domain' ); | |
| 5530 | + | |
| 5531 | + return Host::allow_wpcom_public_api_domain( $domains ); | |
| 5358 | 5532 | } |
| 5359 | 5533 | |
| 5360 | 5534 | /** |
| 5361 | 5535 | * Check if the redirect is encoded. |
| 5362 | 5536 | * |
| 5537 | + * @deprecated 13.4 | |
| 5538 | + * | |
| 5363 | 5539 | * @param string $redirect_url Redirect URL. |
| 5364 | 5540 | * |
| 5365 | 5541 | * @return bool If redirect has been encoded. |
| 5366 | 5542 | */ |
| 5367 | 5543 | public static function is_redirect_encoded( $redirect_url ) { |
| 5544 | + _deprecated_function( __METHOD__, 'jetpack-13.4' ); | |
| 5368 | 5545 | return preg_match( '/https?%3A%2F%2F/i', $redirect_url ) > 0; |
| 5369 | 5546 | } |
| 5370 | 5547 | |
| 5371 | 5548 | /** |
| @@ -5383,8 +5560,10 @@ | ||
| 5383 | 5560 | |
| 5384 | 5561 | /** |
| 5385 | 5562 | * Add the Access Code details to the public-api.wordpress.com redirect. |
| 5386 | 5563 | * |
| 5564 | + * @deprecated 13.4 | |
| 5565 | + * | |
| 5387 | 5566 | * @param string $redirect_to URL. |
| 5388 | 5567 | * @param string $original_redirect_to URL. |
| 5389 | 5568 | * @param WP_User $user WP_User for the redirect. |
| 5390 | 5569 | * |
| @@ -5390,23 +5569,18 @@ | ||
| 5390 | 5569 | * |
| 5391 | 5570 | * @return string |
| 5392 | 5571 | */ |
| 5393 | 5572 | public function add_token_to_login_redirect_json_api_authorization( $redirect_to, $original_redirect_to, $user ) { |
| 5394 | - return add_query_arg( | |
| 5395 | - urlencode_deep( | |
| 5396 | - array( | |
| 5397 | - 'jetpack-code' => get_user_meta( $user->ID, 'jetpack_json_api_' . $this->json_api_authorization_request['client_id'], true ), | |
| 5398 | - 'jetpack-user-id' => (int) $user->ID, | |
| 5399 | - 'jetpack-state' => $this->json_api_authorization_request['state'], | |
| 5400 | - ) | |
| 5401 | - ), | |
| 5402 | - $redirect_to | |
| 5403 | - ); | |
| 5573 | + _deprecated_function( __METHOD__, 'jetpack-13.4', 'Automattic\\Jetpack\\Connection\\Authorize_Json_Api::add_token_to_login_redirect_json_api_authorization' ); | |
| 5574 | + | |
| 5575 | + return ( new Authorize_Json_Api() )->add_token_to_login_redirect_json_api_authorization( $redirect_to, $original_redirect_to, $user ); | |
| 5404 | 5576 | } |
| 5405 | 5577 | |
| 5406 | 5578 | /** |
| 5407 | 5579 | * Verifies the request by checking the signature |
| 5408 | 5580 | * |
| 5581 | + * @deprecated 13.4 | |
| 5582 | + * | |
| 5409 | 5583 | * @since 4.6.0 Method was updated to use `$_REQUEST` instead of `$_GET` and `$_POST`. Method also updated to allow |
| 5410 | 5584 | * passing in an `$environment` argument that overrides `$_REQUEST`. This was useful for integrating with SSO. |
| 5411 | 5585 | * |
| 5412 | 5586 | * @param null|array $environment Value to override $_REQUEST. |
| @@ -5411,194 +5585,24 @@ | ||
| 5411 | 5585 | * |
| 5412 | 5586 | * @param null|array $environment Value to override $_REQUEST. |
| 5413 | 5587 | */ |
| 5414 | 5588 | public function verify_json_api_authorization_request( $environment = null ) { |
| 5415 | - $environment = $environment === null | |
| 5416 | - ? $_REQUEST // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- nonce verification handled later in function. | |
| 5417 | - : $environment; | |
| 5589 | + _deprecated_function( __METHOD__, 'jetpack-13.4', 'Automattic\\Jetpack\\Connection\\Authorize_Json_Api::verify_json_api_authorization_request' ); | |
| 5418 | 5590 | |
| 5419 | - list( $env_token,, $env_user_id ) = explode( ':', $environment['token'] ); | |
| 5420 | - $token = ( new Tokens() )->get_access_token( $env_user_id, $env_token ); | |
| 5421 | - if ( ! $token || empty( $token->secret ) ) { | |
| 5422 | - wp_die( esc_html__( 'You must connect your Jetpack plugin to WordPress.com to use this feature.', 'jetpack' ) ); | |
| 5423 | - } | |
| 5424 | - | |
| 5425 | - $die_error = __( 'Someone may be trying to trick you into giving them access to your site. Or it could be you just encountered a bug :). Either way, please close this window.', 'jetpack' ); | |
| 5426 | - | |
| 5427 | - // Host has encoded the request URL, probably as a result of a bad http => https redirect. | |
| 5428 | - if ( self::is_redirect_encoded( esc_url_raw( wp_unslash( $_GET['redirect_to'] ) ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- no site changes, we're erroring out. | |
| 5429 | - /** | |
| 5430 | - * Jetpack authorisation request Error. | |
| 5431 | - * | |
| 5432 | - * @since 7.5.0 | |
| 5433 | - */ | |
| 5434 | - do_action( 'jetpack_verify_api_authorization_request_error_double_encode' ); | |
| 5435 | - $die_error = sprintf( | |
| 5436 | - /* translators: %s is a URL */ | |
| 5437 | - __( 'Your site is incorrectly double-encoding redirects from http to https. This is preventing Jetpack from authenticating your connection. Please visit our <a href="%s">support page</a> for details about how to resolve this.', 'jetpack' ), | |
| 5438 | - Redirect::get_url( 'jetpack-support-double-encoding' ) | |
| 5439 | - ); | |
| 5440 | - } | |
| 5441 | - | |
| 5442 | - $jetpack_signature = new Jetpack_Signature( $token->secret, (int) Jetpack_Options::get_option( 'time_diff' ) ); | |
| 5443 | - | |
| 5444 | - if ( isset( $environment['jetpack_json_api_original_query'] ) ) { | |
| 5445 | - $signature = $jetpack_signature->sign_request( | |
| 5446 | - $environment['token'], | |
| 5447 | - $environment['timestamp'], | |
| 5448 | - $environment['nonce'], | |
| 5449 | - '', | |
| 5450 | - 'GET', | |
| 5451 | - $environment['jetpack_json_api_original_query'], | |
| 5452 | - null, | |
| 5453 | - true | |
| 5454 | - ); | |
| 5455 | - } else { | |
| 5456 | - $signature = $jetpack_signature->sign_current_request( | |
| 5457 | - array( | |
| 5458 | - 'body' => null, | |
| 5459 | - 'method' => 'GET', | |
| 5460 | - ) | |
| 5461 | - ); | |
| 5462 | - } | |
| 5463 | - | |
| 5464 | - if ( ! $signature ) { | |
| 5465 | - wp_die( | |
| 5466 | - wp_kses( | |
| 5467 | - $die_error, | |
| 5468 | - array( | |
| 5469 | - 'a' => array( | |
| 5470 | - 'href' => array(), | |
| 5471 | - ), | |
| 5472 | - ) | |
| 5473 | - ) | |
| 5474 | - ); | |
| 5475 | - } elseif ( is_wp_error( $signature ) ) { | |
| 5476 | - wp_die( | |
| 5477 | - wp_kses( | |
| 5478 | - $die_error, | |
| 5479 | - array( | |
| 5480 | - 'a' => array( | |
| 5481 | - 'href' => array(), | |
| 5482 | - ), | |
| 5483 | - ) | |
| 5484 | - ) | |
| 5485 | - ); | |
| 5486 | - } elseif ( ! hash_equals( $signature, $environment['signature'] ) ) { | |
| 5487 | - if ( is_ssl() ) { | |
| 5488 | - // If we signed an HTTP request on the Jetpack Servers, but got redirected to HTTPS by the local blog, check the HTTP signature as well. | |
| 5489 | - $signature = $jetpack_signature->sign_current_request( | |
| 5490 | - array( | |
| 5491 | - 'scheme' => 'http', | |
| 5492 | - 'body' => null, | |
| 5493 | - 'method' => 'GET', | |
| 5494 | - ) | |
| 5495 | - ); | |
| 5496 | - if ( ! $signature || is_wp_error( $signature ) || ! hash_equals( $signature, $environment['signature'] ) ) { | |
| 5497 | - wp_die( | |
| 5498 | - wp_kses( | |
| 5499 | - $die_error, | |
| 5500 | - array( | |
| 5501 | - 'a' => array( | |
| 5502 | - 'href' => array(), | |
| 5503 | - ), | |
| 5504 | - ) | |
| 5505 | - ) | |
| 5506 | - ); | |
| 5507 | - } | |
| 5508 | - } else { | |
| 5509 | - wp_die( | |
| 5510 | - wp_kses( | |
| 5511 | - $die_error, | |
| 5512 | - array( | |
| 5513 | - 'a' => array( | |
| 5514 | - 'href' => array(), | |
| 5515 | - ), | |
| 5516 | - ) | |
| 5517 | - ) | |
| 5518 | - ); | |
| 5519 | - } | |
| 5520 | - } | |
| 5521 | - | |
| 5522 | - $timestamp = (int) $environment['timestamp']; | |
| 5523 | - $nonce = stripslashes( (string) $environment['nonce'] ); | |
| 5524 | - | |
| 5525 | - if ( ! $this->connection_manager ) { | |
| 5526 | - $this->connection_manager = new Connection_Manager(); | |
| 5527 | - } | |
| 5528 | - | |
| 5529 | - if ( ! ( new Nonce_Handler() )->add( $timestamp, $nonce ) ) { | |
| 5530 | - // De-nonce the nonce, at least for 5 minutes. | |
| 5531 | - // We have to reuse this nonce at least once (used the first time when the initial request is made, used a second time when the login form is POSTed). | |
| 5532 | - $old_nonce_time = get_option( "jetpack_nonce_{$timestamp}_{$nonce}" ); | |
| 5533 | - if ( $old_nonce_time < time() - 300 ) { | |
| 5534 | - wp_die( esc_html__( 'The authorization process expired. Please go back and try again.', 'jetpack' ) ); | |
| 5535 | - } | |
| 5536 | - } | |
| 5537 | - | |
| 5538 | - $data = json_decode( base64_decode( stripslashes( $environment['data'] ) ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode | |
| 5539 | - $data_filters = array( | |
| 5540 | - 'state' => 'opaque', | |
| 5541 | - 'client_id' => 'int', | |
| 5542 | - 'client_title' => 'string', | |
| 5543 | - 'client_image' => 'url', | |
| 5544 | - ); | |
| 5545 | - | |
| 5546 | - foreach ( $data_filters as $key => $sanitation ) { | |
| 5547 | - if ( ! isset( $data->$key ) ) { | |
| 5548 | - wp_die( | |
| 5549 | - wp_kses( | |
| 5550 | - $die_error, | |
| 5551 | - array( | |
| 5552 | - 'a' => array( | |
| 5553 | - 'href' => array(), | |
| 5554 | - ), | |
| 5555 | - ) | |
| 5556 | - ) | |
| 5557 | - ); | |
| 5558 | - } | |
| 5559 | - | |
| 5560 | - switch ( $sanitation ) { | |
| 5561 | - case 'int': | |
| 5562 | - $this->json_api_authorization_request[ $key ] = (int) $data->$key; | |
| 5563 | - break; | |
| 5564 | - case 'opaque': | |
| 5565 | - $this->json_api_authorization_request[ $key ] = (string) $data->$key; | |
| 5566 | - break; | |
| 5567 | - case 'string': | |
| 5568 | - $this->json_api_authorization_request[ $key ] = wp_kses( (string) $data->$key, array() ); | |
| 5569 | - break; | |
| 5570 | - case 'url': | |
| 5571 | - $this->json_api_authorization_request[ $key ] = esc_url_raw( (string) $data->$key ); | |
| 5572 | - break; | |
| 5573 | - } | |
| 5574 | - } | |
| 5575 | - | |
| 5576 | - if ( empty( $this->json_api_authorization_request['client_id'] ) ) { | |
| 5577 | - wp_die( | |
| 5578 | - wp_kses( | |
| 5579 | - $die_error, | |
| 5580 | - array( | |
| 5581 | - 'a' => array( | |
| 5582 | - 'href' => array(), | |
| 5583 | - ), | |
| 5584 | - ) | |
| 5585 | - ) | |
| 5586 | - ); | |
| 5587 | - } | |
| 5591 | + return ( new Authorize_Json_Api() )->verify_json_api_authorization_request( $environment ); | |
| 5588 | 5592 | } |
| 5589 | 5593 | |
| 5590 | 5594 | /** |
| 5591 | 5595 | * HTML for the JSON API authorization notice. |
| 5592 | 5596 | * |
| 5597 | + * @deprecated 13.4 | |
| 5598 | + * | |
| 5593 | 5599 | * @return string |
| 5594 | 5600 | */ |
| 5595 | 5601 | public function login_message_json_api_authorization() { |
| 5596 | - return '<p class="message">' . sprintf( | |
| 5597 | - /* translators: Name/image of the client requesting authorization */ | |
| 5598 | - esc_html__( '%s wants to access your site’s data. Log in to authorize that access.', 'jetpack' ), | |
| 5599 | - '<strong>' . esc_html( $this->json_api_authorization_request['client_title'] ) . '</strong>' | |
| 5600 | - ) . '<img src="' . esc_url( $this->json_api_authorization_request['client_image'] ) . '" /></p>'; | |
| 5602 | + _deprecated_function( __METHOD__, 'jetpack-13.4', 'Automattic\\Jetpack\\Connection\\Authorize_Json_Api::login_message_json_api_authorization' ); | |
| 5603 | + | |
| 5604 | + return ( new Authorize_Json_Api() )->login_message_json_api_authorization(); | |
| 5601 | 5605 | } |
| 5602 | 5606 | |
| 5603 | 5607 | /** |
| 5604 | 5608 | * Get $content_width, but with a <s>twist</s> filter. |
| @@ -5642,32 +5646,23 @@ | ||
| 5642 | 5646 | |
| 5643 | 5647 | /** |
| 5644 | 5648 | * Checks if the site is currently in an identity crisis. |
| 5645 | 5649 | * |
| 5650 | + * Now delegates to the Connection package so this matches what the heartbeat itself reports. | |
| 5651 | + * Note the package guards on `Connection\Manager::is_connected()` where this used to guard on | |
| 5652 | + * `Jetpack::is_connection_ready()`, so the `jetpack_is_connection_ready` filter no longer applies. | |
| 5653 | + * | |
| 5654 | + * @deprecated 16.2 | |
| 5655 | + * | |
| 5646 | 5656 | * @return array|bool Array of options that are in a crisis, or false if everything is OK. |
| 5647 | 5657 | */ |
| 5648 | 5658 | public static function check_identity_crisis() { |
| 5649 | - if ( ! self::is_connection_ready() || ( new Status() )->is_offline_mode() || ! Identity_Crisis::validate_sync_error_idc_option() ) { | |
| 5650 | - return false; | |
| 5651 | - } | |
| 5659 | + _deprecated_function( __METHOD__, 'jetpack-16.2', 'Automattic\\Jetpack\\Identity_Crisis::check_identity_crisis' ); | |
| 5652 | 5660 | |
| 5653 | - return Jetpack_Options::get_option( 'sync_error_idc' ); | |
| 5661 | + return Identity_Crisis::check_identity_crisis(); | |
| 5654 | 5662 | } |
| 5655 | 5663 | |
| 5656 | 5664 | /** |
| 5657 | - * Checks whether the sync_error_idc option is valid or not, and if not, will do cleanup. | |
| 5658 | - * | |
| 5659 | - * @since 4.4.0 | |
| 5660 | - * @since 5.4.0 Do not call get_sync_error_idc_option() unless site is in IDC | |
| 5661 | - * | |
| 5662 | - * @return bool | |
| 5663 | - */ | |
| 5664 | - public static function validate_sync_error_idc_option() { | |
| 5665 | - _deprecated_function( __METHOD__, 'jetpack-9.8', '\\Automattic\\Jetpack\\Identity_Crisis::validate_sync_error_idc_option' ); | |
| 5666 | - return Identity_Crisis::validate_sync_error_idc_option(); | |
| 5667 | - } | |
| 5668 | - | |
| 5669 | - /** | |
| 5670 | 5665 | * Normalizes a url by doing three things: |
| 5671 | 5666 | * - Strips protocol |
| 5672 | 5667 | * - Strips www |
| 5673 | 5668 | * - Adds a trailing slash |
| @@ -5688,35 +5683,8 @@ | ||
| 5688 | 5683 | return $url; |
| 5689 | 5684 | } |
| 5690 | 5685 | |
| 5691 | 5686 | /** |
| 5692 | - * Gets the value that is to be saved in the jetpack_sync_error_idc option. | |
| 5693 | - * | |
| 5694 | - * @since 4.4.0 | |
| 5695 | - * @since 5.4.0 Add transient since home/siteurl retrieved directly from DB | |
| 5696 | - * @deprecated 9.8.0 Use \\Automattic\\Jetpack\\Identity_Crisis::get_sync_error_idc_option | |
| 5697 | - * | |
| 5698 | - * @param array $response HTTP response. | |
| 5699 | - * @return array Array of the local urls, wpcom urls, and error code | |
| 5700 | - */ | |
| 5701 | - public static function get_sync_error_idc_option( $response = array() ) { | |
| 5702 | - _deprecated_function( __METHOD__, 'jetpack-9.8', '\\Automattic\\Jetpack\\Identity_Crisis::get_sync_error_idc_option' ); | |
| 5703 | - return Identity_Crisis::get_sync_error_idc_option( $response ); | |
| 5704 | - } | |
| 5705 | - | |
| 5706 | - /** | |
| 5707 | - * Returns the value of the jetpack_sync_idc_optin filter, or constant. | |
| 5708 | - * If set to true, the site will be put into staging mode. | |
| 5709 | - * | |
| 5710 | - * @since 4.3.2 | |
| 5711 | - * @return bool | |
| 5712 | - */ | |
| 5713 | - public static function sync_idc_optin() { | |
| 5714 | - _deprecated_function( __METHOD__, 'jetpack-9.8', '\\Automattic\\Jetpack\\Identity_Crisis::sync_idc_optin' ); | |
| 5715 | - return Identity_Crisis::sync_idc_optin(); | |
| 5716 | - } | |
| 5717 | - | |
| 5718 | - /** | |
| 5719 | 5687 | * Maybe Use a .min.css stylesheet, maybe not. |
| 5720 | 5688 | * |
| 5721 | 5689 | * Hooks onto `plugins_url` filter at priority 1, and accepts all 3 args. |
| 5722 | 5690 | * |
| @@ -5737,9 +5705,9 @@ | ||
| 5737 | 5705 | // Strip out the abspath. |
| 5738 | 5706 | $base = dirname( plugin_basename( $plugin ) ); |
| 5739 | 5707 | |
| 5740 | 5708 | // Short out on non-Jetpack assets. |
| 5741 | - if ( 'jetpack/' !== substr( $base, 0, 8 ) ) { | |
| 5709 | + if ( ! str_starts_with( $base, 'jetpack/' ) ) { | |
| 5742 | 5710 | return $url; |
| 5743 | 5711 | } |
| 5744 | 5712 | |
| 5745 | 5713 | // File name parsing. |
| @@ -5779,15 +5747,15 @@ | ||
| 5779 | 5747 | * |
| 5780 | 5748 | * @return mixed |
| 5781 | 5749 | */ |
| 5782 | 5750 | public static function set_suffix_on_min( $src, $handle ) { |
| 5783 | - if ( false === strpos( $src, '.min.css' ) ) { | |
| 5751 | + if ( ! is_string( $src ) || ! str_contains( $src, '.min.css' ) ) { | |
| 5784 | 5752 | return $src; |
| 5785 | 5753 | } |
| 5786 | 5754 | |
| 5787 | 5755 | if ( ! empty( self::$min_assets ) ) { |
| 5788 | 5756 | foreach ( self::$min_assets as $file => $path ) { |
| 5789 | - if ( false !== strpos( $src, $file ) ) { | |
| 5757 | + if ( str_contains( $src, $file ) ) { | |
| 5790 | 5758 | wp_style_add_data( $handle, 'suffix', '.min' ); |
| 5791 | 5759 | return $src; |
| 5792 | 5760 | } |
| 5793 | 5761 | } |
| @@ -5817,8 +5785,10 @@ | ||
| 5817 | 5785 | * |
| 5818 | 5786 | * Data passed in with the $data parameter will be available in the |
| 5819 | 5787 | * template file as $data['value'] |
| 5820 | 5788 | * |
| 5789 | + * @html-template-var array $data | |
| 5790 | + * | |
| 5821 | 5791 | * @param string $template - Template file to load. |
| 5822 | 5792 | * @param array $data - Any data to pass along to the template. |
| 5823 | 5793 | * @return boolean - If template file was found. |
| 5824 | 5794 | **/ |
| @@ -5836,8 +5806,19 @@ | ||
| 5836 | 5806 | return false; |
| 5837 | 5807 | } |
| 5838 | 5808 | |
| 5839 | 5809 | /** |
| 5810 | + * Register Jetpack-specific tests on the connection package's health test suite. | |
| 5811 | + * | |
| 5812 | + * @param \Automattic\Jetpack\Connection\Connection_Health_Tests $connection_tests The test suite instance. | |
| 5813 | + */ | |
| 5814 | + public function register_jetpack_connection_tests( $connection_tests ) { | |
| 5815 | + require_once JETPACK__PLUGIN_DIR . '_inc/lib/debugger/class-jetpack-cxn-tests.php'; | |
| 5816 | + $jetpack_tests = new Jetpack_Cxn_Tests(); | |
| 5817 | + $jetpack_tests->register_tests_on( $connection_tests ); | |
| 5818 | + } | |
| 5819 | + | |
| 5820 | + /** | |
| 5840 | 5821 | * Throws warnings for deprecated hooks to be removed from Jetpack that cannot remain in the original place in the code. |
| 5841 | 5822 | */ |
| 5842 | 5823 | public function deprecated_hooks() { |
| 5843 | 5824 | $filter_deprecated_list = array( |
| @@ -5964,13 +5945,8 @@ | ||
| 5964 | 5945 | 'jetpack_cache_plans' => array( |
| 5965 | 5946 | 'replacement' => null, |
| 5966 | 5947 | 'version' => 'jetpack-6.1.0', |
| 5967 | 5948 | ), |
| 5968 | - | |
| 5969 | - 'jetpack_lazy_images_skip_image_with_atttributes' => array( | |
| 5970 | - 'replacement' => 'jetpack_lazy_images_skip_image_with_attributes', | |
| 5971 | - 'version' => 'jetpack-6.5.0', | |
| 5972 | - ), | |
| 5973 | 5949 | 'jetpack_enable_site_verification' => array( |
| 5974 | 5950 | 'replacement' => null, |
| 5975 | 5951 | 'version' => 'jetpack-6.5.0', |
| 5976 | 5952 | ), |
| @@ -6054,8 +6030,22 @@ | ||
| 6054 | 6030 | 'jetpack_are_blogging_prompts_enabled' => array( |
| 6055 | 6031 | 'replacement' => null, |
| 6056 | 6032 | 'version' => 'jetpack-11.8.0', |
| 6057 | 6033 | ), |
| 6034 | + 'jetpack_subscriptions_modal_enabled' => array( | |
| 6035 | + 'replacement' => null, | |
| 6036 | + 'version' => 'jetpack-12.7.0', | |
| 6037 | + ), | |
| 6038 | + 'jetpack_pre_connection_prompt_helpers' => array( | |
| 6039 | + 'replacement' => null, | |
| 6040 | + 'version' => 'jetpack-13.2.0', | |
| 6041 | + ), | |
| 6042 | + 'jetpack_contact_form_use_package' => array( | |
| 6043 | + 'replacement' => null, | |
| 6044 | + 'version' => 'jetpack-13.4.0', | |
| 6045 | + ), | |
| 6046 | + // jetpack_implode_frontend_css has been removed, but is not listed here. The updated behavior is exactly the only use of the filter. | |
| 6047 | + // We can reassess formally deprecating it here later; for now, it would be noise with no functional difference. | |
| 6058 | 6048 | ); |
| 6059 | 6049 | |
| 6060 | 6050 | foreach ( $filter_deprecated_list as $tag => $args ) { |
| 6061 | 6051 | if ( has_filter( $tag ) ) { |
| @@ -6158,9 +6148,9 @@ | ||
| 6158 | 6148 | foreach ( $matches as $match ) { |
| 6159 | 6149 | $url = trim( $match['path'], "'\" \t" ); |
| 6160 | 6150 | |
| 6161 | 6151 | // If this is a data url, we don't want to mess with it. |
| 6162 | - if ( 'data:' === substr( $url, 0, 5 ) ) { | |
| 6152 | + if ( str_starts_with( $url, 'data:' ) ) { | |
| 6163 | 6153 | continue; |
| 6164 | 6154 | } |
| 6165 | 6155 | |
| 6166 | 6156 | // If this is an absolute or protocol-agnostic url, |
| @@ -6186,113 +6176,8 @@ | ||
| 6186 | 6176 | return $css; |
| 6187 | 6177 | } |
| 6188 | 6178 | |
| 6189 | 6179 | /** |
| 6190 | - * This methods removes all of the registered css files on the front end | |
| 6191 | - * from Jetpack in favor of using a single file. In effect "imploding" | |
| 6192 | - * all the files into one file. | |
| 6193 | - * | |
| 6194 | - * Pros: | |
| 6195 | - * - Uses only ONE css asset connection instead of 15 | |
| 6196 | - * - Saves a minimum of 56k | |
| 6197 | - * - Reduces server load | |
| 6198 | - * - Reduces time to first painted byte | |
| 6199 | - * | |
| 6200 | - * Cons: | |
| 6201 | - * - Loads css for ALL modules. However all selectors are prefixed so it | |
| 6202 | - * should not cause any issues with themes. | |
| 6203 | - * - Plugins/themes dequeuing styles no longer do anything. See | |
| 6204 | - * jetpack_implode_frontend_css filter for a workaround | |
| 6205 | - * | |
| 6206 | - * For some situations developers may wish to disable css imploding and | |
| 6207 | - * instead operate in legacy mode where each file loads seperately and | |
| 6208 | - * can be edited individually or dequeued. This can be accomplished with | |
| 6209 | - * the following line: | |
| 6210 | - * | |
| 6211 | - * add_filter( 'jetpack_implode_frontend_css', '__return_false' ); | |
| 6212 | - * | |
| 6213 | - * @param bool $travis_test Is this a test run. | |
| 6214 | - * | |
| 6215 | - * @since 3.2 | |
| 6216 | - */ | |
| 6217 | - public function implode_frontend_css( $travis_test = false ) { | |
| 6218 | - $do_implode = true; | |
| 6219 | - if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) { | |
| 6220 | - $do_implode = false; | |
| 6221 | - } | |
| 6222 | - | |
| 6223 | - // Do not implode CSS when the page loads via the AMP plugin. | |
| 6224 | - if ( class_exists( Jetpack_AMP_Support::class ) && Jetpack_AMP_Support::is_amp_request() ) { | |
| 6225 | - $do_implode = false; | |
| 6226 | - } | |
| 6227 | - | |
| 6228 | - /** | |
| 6229 | - * Allow CSS to be concatenated into a single jetpack.css file. | |
| 6230 | - * | |
| 6231 | - * @since 3.2.0 | |
| 6232 | - * | |
| 6233 | - * @param bool $do_implode Should CSS be concatenated? Default to true. | |
| 6234 | - */ | |
| 6235 | - $do_implode = apply_filters( 'jetpack_implode_frontend_css', $do_implode ); | |
| 6236 | - | |
| 6237 | - // Do not use the imploded file when default behavior was altered through the filter. | |
| 6238 | - if ( ! $do_implode ) { | |
| 6239 | - return; | |
| 6240 | - } | |
| 6241 | - | |
| 6242 | - // We do not want to use the imploded file in dev mode, or if not connected. | |
| 6243 | - if ( ( new Status() )->is_offline_mode() || ! self::is_connection_ready() ) { | |
| 6244 | - if ( ! $travis_test ) { | |
| 6245 | - return; | |
| 6246 | - } | |
| 6247 | - } | |
| 6248 | - | |
| 6249 | - // Do not use the imploded file if sharing css was dequeued via the sharing settings screen. | |
| 6250 | - if ( get_option( 'sharedaddy_disable_resources' ) ) { | |
| 6251 | - return; | |
| 6252 | - } | |
| 6253 | - | |
| 6254 | - /* | |
| 6255 | - * Now we assume Jetpack is connected and able to serve the single | |
| 6256 | - * file. | |
| 6257 | - * | |
| 6258 | - * In the future there will be a check here to serve the file locally | |
| 6259 | - * or potentially from the Jetpack CDN | |
| 6260 | - * | |
| 6261 | - * For now: | |
| 6262 | - * - Enqueue a single imploded css file | |
| 6263 | - * - Zero out the style_loader_tag for the bundled ones | |
| 6264 | - * - Be happy, drink scotch | |
| 6265 | - */ | |
| 6266 | - | |
| 6267 | - add_filter( 'style_loader_tag', array( $this, 'concat_remove_style_loader_tag' ), 10, 2 ); | |
| 6268 | - | |
| 6269 | - $version = self::is_development_version() ? filemtime( JETPACK__PLUGIN_DIR . 'css/jetpack.css' ) : JETPACK__VERSION; | |
| 6270 | - | |
| 6271 | - wp_enqueue_style( 'jetpack_css', plugins_url( 'css/jetpack.css', __FILE__ ), array(), $version ); | |
| 6272 | - wp_style_add_data( 'jetpack_css', 'rtl', 'replace' ); | |
| 6273 | - } | |
| 6274 | - | |
| 6275 | - /** | |
| 6276 | - * Removes styles that are part of concatenated group. | |
| 6277 | - * | |
| 6278 | - * @param string $tag Style tag. | |
| 6279 | - * @param string $handle Style handle. | |
| 6280 | - * | |
| 6281 | - * @return string | |
| 6282 | - */ | |
| 6283 | - public function concat_remove_style_loader_tag( $tag, $handle ) { | |
| 6284 | - if ( in_array( $handle, $this->concatenated_style_handles, true ) ) { | |
| 6285 | - $tag = ''; | |
| 6286 | - if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { | |
| 6287 | - $tag = '<!-- `' . esc_html( $handle ) . "` is included in the concatenated jetpack.css -->\r\n"; | |
| 6288 | - } | |
| 6289 | - } | |
| 6290 | - | |
| 6291 | - return $tag; | |
| 6292 | - } | |
| 6293 | - | |
| 6294 | - /** | |
| 6295 | 6180 | * Check the heartbeat data |
| 6296 | 6181 | * |
| 6297 | 6182 | * Organizes the heartbeat data by severity. For example, if the site |
| 6298 | 6183 | * is in an ID crisis, it will be in the $filtered_data['bad'] array. |
| @@ -6304,9 +6189,20 @@ | ||
| 6304 | 6189 | * |
| 6305 | 6190 | * $return array $filtered_data |
| 6306 | 6191 | */ |
| 6307 | 6192 | public static function jetpack_check_heartbeat_data() { |
| 6308 | - $raw_data = Jetpack_Heartbeat::generate_stats_array(); | |
| 6193 | + /* | |
| 6194 | + * Site environment stats (incl. wp-version/php-version checked below) now live in the Connection package, | |
| 6195 | + * and the IDC stat is contributed by the Connection package's `jetpack_heartbeat_stats_array` filter | |
| 6196 | + * callback. We rebuild the stat here rather than running that filter: the filter's callbacks have side | |
| 6197 | + * effects (Connection\Manager::add_stats_to_heartbeat() consumes and deletes the `xmlrpc_errors` option) | |
| 6198 | + * and return non-scalar values, neither of which is appropriate for this read-only diagnostic. | |
| 6199 | + */ | |
| 6200 | + $raw_data = array_merge( | |
| 6201 | + Jetpack_Heartbeat::generate_stats_array(), | |
| 6202 | + Heartbeat::get_environment_stats(), | |
| 6203 | + array( 'identitycrisis' => Identity_Crisis::check_identity_crisis() ? 'yes' : 'no' ) | |
| 6204 | + ); | |
| 6309 | 6205 | |
| 6310 | 6206 | $good = array(); |
| 6311 | 6207 | $caution = array(); |
| 6312 | 6208 | $bad = array(); |
| @@ -6372,23 +6268,8 @@ | ||
| 6372 | 6268 | return Jetpack_Options::get_options_for_reset(); |
| 6373 | 6269 | } |
| 6374 | 6270 | |
| 6375 | 6271 | /** |
| 6376 | - * Strip http:// or https:// from a url, replaces forward slash with ::, | |
| 6377 | - * so we can bring them directly to their site in calypso. | |
| 6378 | - * | |
| 6379 | - * @deprecated 9.2.0 Use Automattic\Jetpack\Status::get_site_suffix | |
| 6380 | - * | |
| 6381 | - * @param string $url URL. | |
| 6382 | - * @return string url without the guff. | |
| 6383 | - */ | |
| 6384 | - public static function build_raw_urls( $url ) { | |
| 6385 | - _deprecated_function( __METHOD__, 'jetpack-9.2.0', 'Automattic\Jetpack\Status::get_site_suffix' ); | |
| 6386 | - | |
| 6387 | - return ( new Status() )->get_site_suffix( $url ); | |
| 6388 | - } | |
| 6389 | - | |
| 6390 | - /** | |
| 6391 | 6272 | * Get the user's meta box order. |
| 6392 | 6273 | * |
| 6393 | 6274 | * @param array $sorted Value for the user's option. |
| 6394 | 6275 | * @return mixed |
| @@ -6398,9 +6279,9 @@ | ||
| 6398 | 6279 | return $sorted; |
| 6399 | 6280 | } |
| 6400 | 6281 | |
| 6401 | 6282 | foreach ( $sorted as $box_context => $ids ) { |
| 6402 | - if ( false === strpos( $ids, 'dashboard_stats' ) ) { | |
| 6283 | + if ( ! str_contains( $ids, 'dashboard_stats' ) ) { | |
| 6403 | 6284 | // If the old id isn't anywhere in the ids, don't bother exploding and fail out. |
| 6404 | 6285 | continue; |
| 6405 | 6286 | } |
| 6406 | 6287 | |
| @@ -6417,68 +6298,9 @@ | ||
| 6417 | 6298 | } |
| 6418 | 6299 | |
| 6419 | 6300 | return $sorted; |
| 6420 | 6301 | } |
| 6421 | - | |
| 6422 | 6302 | /** |
| 6423 | - * Adds a "blank" column in the user admin table to display indication of user connection. | |
| 6424 | - * | |
| 6425 | - * @param array $columns User list table columns. | |
| 6426 | - * | |
| 6427 | - * @return array | |
| 6428 | - */ | |
| 6429 | - public function jetpack_icon_user_connected( $columns ) { | |
| 6430 | - $columns['user_jetpack'] = ''; | |
| 6431 | - return $columns; | |
| 6432 | - } | |
| 6433 | - | |
| 6434 | - /** | |
| 6435 | - * Show Jetpack icon if the user is linked. | |
| 6436 | - * | |
| 6437 | - * @param string $val HTML for the icon. | |
| 6438 | - * @param string $col User list table column. | |
| 6439 | - * @param int $user_id User ID. | |
| 6440 | - * | |
| 6441 | - * @return string | |
| 6442 | - */ | |
| 6443 | - public function jetpack_show_user_connected_icon( $val, $col, $user_id ) { | |
| 6444 | - if ( 'user_jetpack' === $col && self::connection()->is_user_connected( $user_id ) ) { | |
| 6445 | - $jetpack_logo = new Jetpack_Logo(); | |
| 6446 | - $emblem_html = sprintf( | |
| 6447 | - '<a title="%1$s" class="jp-emblem-user-admin">%2$s</a>', | |
| 6448 | - esc_attr__( 'This user is linked and ready to fly with Jetpack.', 'jetpack' ), | |
| 6449 | - $jetpack_logo->get_jp_emblem() | |
| 6450 | - ); | |
| 6451 | - return $emblem_html; | |
| 6452 | - } | |
| 6453 | - | |
| 6454 | - return $val; | |
| 6455 | - } | |
| 6456 | - | |
| 6457 | - /** | |
| 6458 | - * Style the Jetpack user column | |
| 6459 | - */ | |
| 6460 | - public function jetpack_user_col_style() { | |
| 6461 | - global $current_screen; | |
| 6462 | - if ( ! empty( $current_screen->base ) && 'users' === $current_screen->base ) { | |
| 6463 | - ?> | |
| 6464 | - <style> | |
| 6465 | - .fixed .column-user_jetpack { | |
| 6466 | - width: 21px; | |
| 6467 | - } | |
| 6468 | - .jp-emblem-user-admin svg { | |
| 6469 | - width: 20px; | |
| 6470 | - height: 20px; | |
| 6471 | - } | |
| 6472 | - .jp-emblem-user-admin path { | |
| 6473 | - fill: #069e08; | |
| 6474 | - } | |
| 6475 | - </style> | |
| 6476 | - <?php | |
| 6477 | - } | |
| 6478 | - } | |
| 6479 | - | |
| 6480 | - /** | |
| 6481 | 6303 | * Checks if Akismet is active and working. |
| 6482 | 6304 | * |
| 6483 | 6305 | * We dropped support for Akismet 3.0 with Jetpack 6.1.1 while introducing a check for an Akismet valid key |
| 6484 | 6306 | * that implied usage of methods present since more recent version. |
| @@ -6639,13 +6461,20 @@ | ||
| 6639 | 6461 | } |
| 6640 | 6462 | } |
| 6641 | 6463 | |
| 6642 | 6464 | /** |
| 6643 | - * Returns a boolean for whether backups UI should be displayed or not. | |
| 6465 | + * Whether UI for backups should be displayed. | |
| 6644 | 6466 | * |
| 6467 | + * On WPCom platforms this is gated on the backups-self-serve site feature. | |
| 6468 | + * On self-hosted Jetpack sites it falls back to the jetpack_show_backups filter. | |
| 6469 | + * | |
| 6645 | 6470 | * @return bool Should backups UI be displayed? |
| 6646 | 6471 | */ |
| 6647 | 6472 | public static function show_backups_ui() { |
| 6473 | + if ( ( new \Automattic\Jetpack\Status\Host() )->is_wpcom_platform() ) { | |
| 6474 | + return function_exists( 'wpcom_site_has_feature' ) && wpcom_site_has_feature( 'backups-self-serve' ); | |
| 6475 | + } | |
| 6476 | + | |
| 6648 | 6477 | /** |
| 6649 | 6478 | * Whether UI for backups should be displayed. |
| 6650 | 6479 | * |
| 6651 | 6480 | * @since 6.5.0 |
| @@ -6655,8 +6484,24 @@ | ||
| 6655 | 6484 | return self::is_plugin_active( 'vaultpress/vaultpress.php' ) || apply_filters( 'jetpack_show_backups', true ); |
| 6656 | 6485 | } |
| 6657 | 6486 | |
| 6658 | 6487 | /** |
| 6488 | + * Whether UI for security scanning should be displayed. | |
| 6489 | + * | |
| 6490 | + * On WPCom platforms this is gated on the scan-self-serve site feature. | |
| 6491 | + * On self-hosted Jetpack sites it always returns true. | |
| 6492 | + * | |
| 6493 | + * @return bool Should scan UI be displayed? | |
| 6494 | + */ | |
| 6495 | + public static function show_scan_ui() { | |
| 6496 | + if ( ( new \Automattic\Jetpack\Status\Host() )->is_wpcom_platform() ) { | |
| 6497 | + return function_exists( 'wpcom_site_has_feature' ) && wpcom_site_has_feature( 'scan-self-serve' ); | |
| 6498 | + } | |
| 6499 | + | |
| 6500 | + return true; | |
| 6501 | + } | |
| 6502 | + | |
| 6503 | + /** | |
| 6659 | 6504 | * Clean leftoveruser meta. |
| 6660 | 6505 | * |
| 6661 | 6506 | * Delete Jetpack-related user meta when it is no longer needed. |
| 6662 | 6507 | * |
| @@ -6728,8 +6573,40 @@ | ||
| 6728 | 6573 | 'url' => Redirect::get_url( 'jetpack-faq-backup-disclaimer' ), |
| 6729 | 6574 | ), |
| 6730 | 6575 | ); |
| 6731 | 6576 | |
| 6577 | + $products['creator'] = array( | |
| 6578 | + 'title' => __( 'Jetpack Creator', 'jetpack' ), | |
| 6579 | + 'slug' => 'jetpack_creator_yearly', | |
| 6580 | + 'description' => __( 'Craft stunning content, boost your subscriber base, and monetize your online presence.', 'jetpack' ), | |
| 6581 | + 'show_promotion' => true, | |
| 6582 | + 'discount_percent' => 50, | |
| 6583 | + 'included_in_plans' => array( 'complete' ), | |
| 6584 | + 'features' => array( | |
| 6585 | + _x( 'Unlimited subscriber imports', 'Creator Product Feature', 'jetpack' ), | |
| 6586 | + _x( 'Earn more from your content', 'Creator Product Feature', 'jetpack' ), | |
| 6587 | + _x( 'Accept payments with PayPal', 'Creator Product Feature', 'jetpack' ), | |
| 6588 | + _x( 'Increase earnings with WordAds', 'Creator Product Feature', 'jetpack' ), | |
| 6589 | + ), | |
| 6590 | + ); | |
| 6591 | + | |
| 6592 | + $products['growth'] = array( | |
| 6593 | + 'title' => __( 'Jetpack Growth', 'jetpack' ), | |
| 6594 | + 'slug' => 'jetpack_growth_yearly', | |
| 6595 | + 'description' => __( 'Essential tools to help you grow your audience, track visitor engagement, and turn leads into loyal customers and advocates.', 'jetpack' ), | |
| 6596 | + 'show_promotion' => true, | |
| 6597 | + 'discount_percent' => 50, | |
| 6598 | + 'included_in_plans' => array( 'complete' ), | |
| 6599 | + 'features' => array( | |
| 6600 | + _x( 'Jetpack Social', 'Growth Product Feature', 'jetpack' ), | |
| 6601 | + _x( 'Jetpack Stats (10K site views, upgradeable)', 'Growth Product Feature', 'jetpack' ), | |
| 6602 | + _x( 'Unlimited subscriber imports', 'Growth Product Feature', 'jetpack' ), | |
| 6603 | + _x( 'Earn more from your content', 'Growth Product Feature', 'jetpack' ), | |
| 6604 | + _x( 'Accept payments with PayPal', 'Growth Product Feature', 'jetpack' ), | |
| 6605 | + _x( 'Increase earnings with WordAds', 'Growth Product Feature', 'jetpack' ), | |
| 6606 | + ), | |
| 6607 | + ); | |
| 6608 | + | |
| 6732 | 6609 | $products['scan'] = array( |
| 6733 | 6610 | 'title' => __( 'Jetpack Scan', 'jetpack' ), |
| 6734 | 6611 | 'slug' => 'jetpack_scan', |
| 6735 | 6612 | 'description' => __( 'Automatic scanning and one-click fixes keep your site one step ahead of security threats and malware.', 'jetpack' ), |
| @@ -6759,9 +6636,9 @@ | ||
| 6759 | 6636 | ), |
| 6760 | 6637 | ); |
| 6761 | 6638 | |
| 6762 | 6639 | $products['akismet'] = array( |
| 6763 | - 'title' => __( 'Akismet Anti-Spam', 'jetpack' ), | |
| 6640 | + 'title' => __( 'Akismet Anti-spam', 'jetpack' ), | |
| 6764 | 6641 | 'slug' => 'jetpack_anti_spam', |
| 6765 | 6642 | 'description' => __( 'Save time and get better responses by automatically blocking spam from your comments and forms.', 'jetpack' ), |
| 6766 | 6643 | 'show_promotion' => true, |
| 6767 | 6644 | 'discount_percent' => 50, |
| @@ -6855,5 +6732,106 @@ | ||
| 6855 | 6732 | |
| 6856 | 6733 | return true; |
| 6857 | 6734 | } |
| 6858 | 6735 | |
| 6736 | + /** | |
| 6737 | + * Add 5-star review link on the Jetpack Plugin meta, in the plugins list table (on the plugins page). | |
| 6738 | + * | |
| 6739 | + * @param array $plugin_meta An array of the plugin's metadata. | |
| 6740 | + * @param string $plugin_file Path to the plugin file. | |
| 6741 | + * | |
| 6742 | + * @return array $plugin_meta An array of the plugin's metadata. | |
| 6743 | + */ | |
| 6744 | + public function add_5_star_review_link( $plugin_meta, $plugin_file ) { | |
| 6745 | + if ( $plugin_file !== 'jetpack/jetpack.php' ) { | |
| 6746 | + return $plugin_meta; | |
| 6747 | + } | |
| 6748 | + | |
| 6749 | + $u = get_current_user_id(); | |
| 6750 | + $site = get_site_url(); | |
| 6751 | + | |
| 6752 | + $plugin_meta[] = '<a href="https://jetpack.com/redirect?source=jetpack-plugin-review&site=' . esc_attr( $site ) . '&u=' . esc_attr( $u ) . '" target="_blank" rel="noopener noreferrer" title="' . esc_attr__( 'Rate Jetpack on WordPress.org', 'jetpack' ) . '" style="color: #ffb900">' | |
| 6753 | + . str_repeat( '<span class="dashicons dashicons-star-filled" style="font-size: 16px; width:16px; height: 16px"></span>', 5 ) | |
| 6754 | + . '</a>'; | |
| 6755 | + | |
| 6756 | + return $plugin_meta; | |
| 6757 | + } | |
| 6758 | + | |
| 6759 | + /** | |
| 6760 | + * Lazy instantiation of the Plugin_Tracking object. | |
| 6761 | + * | |
| 6762 | + * @since 13.9 | |
| 6763 | + * | |
| 6764 | + * @return void | |
| 6765 | + */ | |
| 6766 | + public function initialize_tracking() { | |
| 6767 | + if ( did_action( 'jetpack_initialize_tracking' ) > 1 ) { | |
| 6768 | + // Only need to run once. | |
| 6769 | + return; | |
| 6770 | + } | |
| 6771 | + | |
| 6772 | + if ( ( new Tracking( 'jetpack', $this->connection_manager ) )->should_enable_tracking( new Terms_Of_Service(), new Status() ) || static::is_connection_ready() ) { | |
| 6773 | + ( new Plugin_Tracking() )->init(); | |
| 6774 | + } | |
| 6775 | + } | |
| 6776 | + | |
| 6777 | + /** | |
| 6778 | + * Run the "initialize tracking" hook. | |
| 6779 | + * | |
| 6780 | + * @since 13.9 | |
| 6781 | + */ | |
| 6782 | + public function run_initialize_tracking_action() { | |
| 6783 | + /** | |
| 6784 | + * Fires when the tracking needs to be initialized. | |
| 6785 | + * Doesn't necessarily mean that will actually happen, depends if the 'jetpack_tos_agreed' option is set. | |
| 6786 | + * | |
| 6787 | + * @since 13.9 | |
| 6788 | + */ | |
| 6789 | + do_action( 'jetpack_initialize_tracking' ); | |
| 6790 | + } | |
| 6791 | + | |
| 6792 | + /** | |
| 6793 | + * Initialize REST jsonAPI if needed. | |
| 6794 | + * | |
| 6795 | + * @return void | |
| 6796 | + */ | |
| 6797 | + public function maybe_initialize_rest_jsonapi() { | |
| 6798 | + // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 6799 | + if ( ! empty( $_GET['jsonapi'] ) && ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) ) { | |
| 6800 | + require_once ABSPATH . 'wp-admin/includes/admin.php'; // JSON API relies on WP functionality not autoloaded in REST. | |
| 6801 | + | |
| 6802 | + define( 'WPCOM_JSON_API__BASE', 'public-api.wordpress.com/rest/v1' ); | |
| 6803 | + require_once JETPACK__PLUGIN_DIR . 'class.json-api-endpoints.php'; | |
| 6804 | + } | |
| 6805 | + } | |
| 6806 | + | |
| 6807 | + /** | |
| 6808 | + * Run plugin post-activation actions if we need to. | |
| 6809 | + * | |
| 6810 | + * @return void | |
| 6811 | + */ | |
| 6812 | + private function plugin_post_activation() { | |
| 6813 | + if ( ( new Status() )->is_offline_mode() ) { | |
| 6814 | + return; | |
| 6815 | + } | |
| 6816 | + | |
| 6817 | + if ( get_transient( 'activated_jetpack' ) ) { | |
| 6818 | + delete_transient( 'activated_jetpack' ); | |
| 6819 | + | |
| 6820 | + if ( ( new Host() )->is_woa_site() ) { | |
| 6821 | + $redirect_url = static::admin_url( 'page=jetpack' ); | |
| 6822 | + } elseif ( is_network_admin() ) { | |
| 6823 | + $redirect_url = admin_url( 'network/admin.php?page=jetpack' ); | |
| 6824 | + } elseif ( get_transient( 'my_jetpack_product_activated' ) ) { | |
| 6825 | + // don't redirect if this is an activation that just came from My Jetpack | |
| 6826 | + // My Jetpack has its own set of post-activation redirects | |
| 6827 | + return; | |
| 6828 | + } elseif ( My_Jetpack_Initializer::should_initialize() ) { | |
| 6829 | + $redirect_url = static::admin_url( 'page=my-jetpack' ); | |
| 6830 | + } else { | |
| 6831 | + $redirect_url = static::admin_url( 'page=jetpack' ); | |
| 6832 | + } | |
| 6833 | + | |
| 6834 | + wp_safe_redirect( $redirect_url ); | |
| 6835 | + } | |
| 6836 | + } | |
| 6859 | 6837 | } |