diff options
Diffstat (limited to 'plugins/jetpack/class.jetpack.php')
-rw-r--r-- | plugins/jetpack/class.jetpack.php | 3706 |
1 files changed, 1887 insertions, 1819 deletions
diff --git a/plugins/jetpack/class.jetpack.php b/plugins/jetpack/class.jetpack.php index 746e0d60..36b4b7a2 100644 --- a/plugins/jetpack/class.jetpack.php +++ b/plugins/jetpack/class.jetpack.php @@ -1,4 +1,20 @@ <?php +use Automattic\Jetpack\Assets; +use Automattic\Jetpack\Assets\Logo as Jetpack_Logo; +use Automattic\Jetpack\Connection\Client; +use Automattic\Jetpack\Connection\Manager as Connection_Manager; +use Automattic\Jetpack\Connection\REST_Connector as REST_Connector; +use Automattic\Jetpack\Connection\XMLRPC_Connector as XMLRPC_Connector; +use Automattic\Jetpack\Connection\Utils as Connection_Utils; +use Automattic\Jetpack\Constants; +use Automattic\Jetpack\Roles; +use Automattic\Jetpack\Status; +use Automattic\Jetpack\Sync\Functions; +use Automattic\Jetpack\Sync\Sender; +use Automattic\Jetpack\Sync\Users; +use Automattic\Jetpack\Terms_Of_Service; +use Automattic\Jetpack\Tracking; +use Automattic\Jetpack\Plugin\Tracking as Plugin_Tracking; /* Options: @@ -22,16 +38,17 @@ jetpack_do_activate (bool) Flag for "activating" the plugin on sites where the activation hook never fired (auto-installs) */ -require_once( JETPACK__PLUGIN_DIR . '_inc/lib/class.media.php' ); +require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.media.php'; class Jetpack { public $xmlrpc_server = null; - private $xmlrpc_verification = null; private $rest_authentication_status = null; public $HTTP_RAW_POST_DATA = null; // copy of $GLOBALS['HTTP_RAW_POST_DATA'] + private $tracking; + /** * @var array The handles of styles that are concatenated into jetpack.css. * @@ -68,6 +85,15 @@ class Jetpack { ); /** + * The handles of scripts that can be loaded asynchronously. + * + * @var array + */ + public $async_script_handles = array( + 'woocommerce-analytics', + ); + + /** * Contains all assets that have had their URL rewritten to minified versions. * * @var array @@ -88,10 +114,20 @@ class Jetpack { 'widget-visibility' => array( 'widget-visibility-without-jetpack/widget-visibility-without-jetpack.php', 'Widget Visibility Without Jetpack' ), 'sharedaddy' => array( 'jetpack-sharing/sharedaddy.php', 'Jetpack Sharing' ), 'gravatar-hovercards' => array( 'jetpack-gravatar-hovercards/gravatar-hovercards.php', 'Jetpack Gravatar Hovercards' ), - 'latex' => array( 'wp-latex/wp-latex.php', 'WP LaTeX' ) + 'latex' => array( 'wp-latex/wp-latex.php', 'WP LaTeX' ), ); - static $capability_translations = array( + /** + * Map of roles we care about, and their corresponding minimum capabilities. + * + * @deprecated 7.6 Use Automattic\Jetpack\Roles::$capability_translations instead. + * + * @access public + * @static + * + * @var array + */ + public static $capability_translations = array( 'administrator' => 'manage_options', 'editor' => 'edit_others_posts', 'author' => 'publish_posts', @@ -114,89 +150,89 @@ class Jetpack { * @var array */ private $conflicting_plugins = array( - 'comments' => array( - 'Intense Debate' => 'intensedebate/intensedebate.php', - 'Disqus' => 'disqus-comment-system/disqus.php', - 'Livefyre' => 'livefyre-comments/livefyre.php', - 'Comments Evolved for WordPress' => 'gplus-comments/comments-evolved.php', - 'Google+ Comments' => 'google-plus-comments/google-plus-comments.php', - 'WP-SpamShield Anti-Spam' => 'wp-spamshield/wp-spamshield.php', + 'comments' => array( + 'Intense Debate' => 'intensedebate/intensedebate.php', + 'Disqus' => 'disqus-comment-system/disqus.php', + 'Livefyre' => 'livefyre-comments/livefyre.php', + 'Comments Evolved for WordPress' => 'gplus-comments/comments-evolved.php', + 'Google+ Comments' => 'google-plus-comments/google-plus-comments.php', + 'WP-SpamShield Anti-Spam' => 'wp-spamshield/wp-spamshield.php', ), - 'comment-likes' => array( - 'Epoch' => 'epoch/plugincore.php', + 'comment-likes' => array( + 'Epoch' => 'epoch/plugincore.php', ), - 'contact-form' => array( - 'Contact Form 7' => 'contact-form-7/wp-contact-form-7.php', - 'Gravity Forms' => 'gravityforms/gravityforms.php', - 'Contact Form Plugin' => 'contact-form-plugin/contact_form.php', - 'Easy Contact Forms' => 'easy-contact-forms/easy-contact-forms.php', - 'Fast Secure Contact Form' => 'si-contact-form/si-contact-form.php', - 'Ninja Forms' => 'ninja-forms/ninja-forms.php', + 'contact-form' => array( + 'Contact Form 7' => 'contact-form-7/wp-contact-form-7.php', + 'Gravity Forms' => 'gravityforms/gravityforms.php', + 'Contact Form Plugin' => 'contact-form-plugin/contact_form.php', + 'Easy Contact Forms' => 'easy-contact-forms/easy-contact-forms.php', + 'Fast Secure Contact Form' => 'si-contact-form/si-contact-form.php', + 'Ninja Forms' => 'ninja-forms/ninja-forms.php', ), - 'minileven' => array( - 'WPtouch' => 'wptouch/wptouch.php', + 'minileven' => array( + 'WPtouch' => 'wptouch/wptouch.php', ), - 'latex' => array( - 'LaTeX for WordPress' => 'latex/latex.php', - 'Youngwhans Simple Latex' => 'youngwhans-simple-latex/yw-latex.php', - 'Easy WP LaTeX' => 'easy-wp-latex-lite/easy-wp-latex-lite.php', - 'MathJax-LaTeX' => 'mathjax-latex/mathjax-latex.php', - 'Enable Latex' => 'enable-latex/enable-latex.php', - 'WP QuickLaTeX' => 'wp-quicklatex/wp-quicklatex.php', + 'latex' => array( + 'LaTeX for WordPress' => 'latex/latex.php', + 'Youngwhans Simple Latex' => 'youngwhans-simple-latex/yw-latex.php', + 'Easy WP LaTeX' => 'easy-wp-latex-lite/easy-wp-latex-lite.php', + 'MathJax-LaTeX' => 'mathjax-latex/mathjax-latex.php', + 'Enable Latex' => 'enable-latex/enable-latex.php', + 'WP QuickLaTeX' => 'wp-quicklatex/wp-quicklatex.php', ), - 'protect' => array( - 'Limit Login Attempts' => 'limit-login-attempts/limit-login-attempts.php', - 'Captcha' => 'captcha/captcha.php', - 'Brute Force Login Protection' => 'brute-force-login-protection/brute-force-login-protection.php', - 'Login Security Solution' => 'login-security-solution/login-security-solution.php', - 'WPSecureOps Brute Force Protect' => 'wpsecureops-bruteforce-protect/wpsecureops-bruteforce-protect.php', - 'BulletProof Security' => 'bulletproof-security/bulletproof-security.php', - 'SiteGuard WP Plugin' => 'siteguard/siteguard.php', - 'Security-protection' => 'security-protection/security-protection.php', - 'Login Security' => 'login-security/login-security.php', - 'Botnet Attack Blocker' => 'botnet-attack-blocker/botnet-attack-blocker.php', - 'Wordfence Security' => 'wordfence/wordfence.php', - 'All In One WP Security & Firewall' => 'all-in-one-wp-security-and-firewall/wp-security.php', - 'iThemes Security' => 'better-wp-security/better-wp-security.php', + 'protect' => array( + 'Limit Login Attempts' => 'limit-login-attempts/limit-login-attempts.php', + 'Captcha' => 'captcha/captcha.php', + 'Brute Force Login Protection' => 'brute-force-login-protection/brute-force-login-protection.php', + 'Login Security Solution' => 'login-security-solution/login-security-solution.php', + 'WPSecureOps Brute Force Protect' => 'wpsecureops-bruteforce-protect/wpsecureops-bruteforce-protect.php', + 'BulletProof Security' => 'bulletproof-security/bulletproof-security.php', + 'SiteGuard WP Plugin' => 'siteguard/siteguard.php', + 'Security-protection' => 'security-protection/security-protection.php', + 'Login Security' => 'login-security/login-security.php', + 'Botnet Attack Blocker' => 'botnet-attack-blocker/botnet-attack-blocker.php', + 'Wordfence Security' => 'wordfence/wordfence.php', + 'All In One WP Security & Firewall' => 'all-in-one-wp-security-and-firewall/wp-security.php', + 'iThemes Security' => 'better-wp-security/better-wp-security.php', ), - 'random-redirect' => array( - 'Random Redirect 2' => 'random-redirect-2/random-redirect.php', + 'random-redirect' => array( + 'Random Redirect 2' => 'random-redirect-2/random-redirect.php', ), - 'related-posts' => array( - 'YARPP' => 'yet-another-related-posts-plugin/yarpp.php', - 'WordPress Related Posts' => 'wordpress-23-related-posts-plugin/wp_related_posts.php', - 'nrelate Related Content' => 'nrelate-related-content/nrelate-related.php', - 'Contextual Related Posts' => 'contextual-related-posts/contextual-related-posts.php', - 'Related Posts for WordPress' => 'microkids-related-posts/microkids-related-posts.php', - 'outbrain' => 'outbrain/outbrain.php', - 'Shareaholic' => 'shareaholic/shareaholic.php', - 'Sexybookmarks' => 'sexybookmarks/shareaholic.php', + 'related-posts' => array( + 'YARPP' => 'yet-another-related-posts-plugin/yarpp.php', + 'WordPress Related Posts' => 'wordpress-23-related-posts-plugin/wp_related_posts.php', + 'nrelate Related Content' => 'nrelate-related-content/nrelate-related.php', + 'Contextual Related Posts' => 'contextual-related-posts/contextual-related-posts.php', + 'Related Posts for WordPress' => 'microkids-related-posts/microkids-related-posts.php', + 'outbrain' => 'outbrain/outbrain.php', + 'Shareaholic' => 'shareaholic/shareaholic.php', + 'Sexybookmarks' => 'sexybookmarks/shareaholic.php', ), - 'sharedaddy' => array( - 'AddThis' => 'addthis/addthis_social_widget.php', - 'Add To Any' => 'add-to-any/add-to-any.php', - 'ShareThis' => 'share-this/sharethis.php', - 'Shareaholic' => 'shareaholic/shareaholic.php', + 'sharedaddy' => array( + 'AddThis' => 'addthis/addthis_social_widget.php', + 'Add To Any' => 'add-to-any/add-to-any.php', + 'ShareThis' => 'share-this/sharethis.php', + 'Shareaholic' => 'shareaholic/shareaholic.php', ), - 'seo-tools' => array( - 'WordPress SEO by Yoast' => 'wordpress-seo/wp-seo.php', - 'WordPress SEO Premium by Yoast' => 'wordpress-seo-premium/wp-seo-premium.php', - 'All in One SEO Pack' => 'all-in-one-seo-pack/all_in_one_seo_pack.php', - 'All in One SEO Pack Pro' => 'all-in-one-seo-pack-pro/all_in_one_seo_pack.php', - 'The SEO Framework' => 'autodescription/autodescription.php', + 'seo-tools' => array( + 'WordPress SEO by Yoast' => 'wordpress-seo/wp-seo.php', + 'WordPress SEO Premium by Yoast' => 'wordpress-seo-premium/wp-seo-premium.php', + 'All in One SEO Pack' => 'all-in-one-seo-pack/all_in_one_seo_pack.php', + 'All in One SEO Pack Pro' => 'all-in-one-seo-pack-pro/all_in_one_seo_pack.php', + 'The SEO Framework' => 'autodescription/autodescription.php', ), 'verification-tools' => array( - 'WordPress SEO by Yoast' => 'wordpress-seo/wp-seo.php', - 'WordPress SEO Premium by Yoast' => 'wordpress-seo-premium/wp-seo-premium.php', - 'All in One SEO Pack' => 'all-in-one-seo-pack/all_in_one_seo_pack.php', - 'All in One SEO Pack Pro' => 'all-in-one-seo-pack-pro/all_in_one_seo_pack.php', - 'The SEO Framework' => 'autodescription/autodescription.php', + 'WordPress SEO by Yoast' => 'wordpress-seo/wp-seo.php', + 'WordPress SEO Premium by Yoast' => 'wordpress-seo-premium/wp-seo-premium.php', + 'All in One SEO Pack' => 'all-in-one-seo-pack/all_in_one_seo_pack.php', + 'All in One SEO Pack Pro' => 'all-in-one-seo-pack-pro/all_in_one_seo_pack.php', + 'The SEO Framework' => 'autodescription/autodescription.php', ), - 'widget-visibility' => array( - 'Widget Logic' => 'widget-logic/widget_logic.php', - 'Dynamic Widgets' => 'dynamic-widgets/dynamic-widgets.php', + 'widget-visibility' => array( + 'Widget Logic' => 'widget-logic/widget_logic.php', + 'Dynamic Widgets' => 'dynamic-widgets/dynamic-widgets.php', ), - 'sitemaps' => array( + 'sitemaps' => array( 'Google XML Sitemaps' => 'google-sitemap-generator/sitemap.php', 'Better WordPress Google XML Sitemaps' => 'bwp-google-xml-sitemaps/bwp-simple-gxs.php', 'Google XML Sitemaps for qTranslate' => 'google-xml-sitemaps-v3-for-qtranslate/sitemap.php', @@ -213,7 +249,7 @@ class Jetpack { 'XML Sitemaps' => 'xml-sitemaps/xml-sitemaps.php', 'MSM Sitemaps' => 'msm-sitemap/msm-sitemap.php', ), - 'lazy-images' => array( + 'lazy-images' => array( 'Lazy Load' => 'lazy-load/lazy-load.php', 'BJ Lazy Load' => 'bj-lazy-load/bj-lazy-load.php', 'Lazy Load by WP Rocket' => 'rocket-lazy-load/rocket-lazy-load.php', @@ -231,31 +267,31 @@ class Jetpack { */ private $open_graph_conflicting_plugins = array( '2-click-socialmedia-buttons/2-click-socialmedia-buttons.php', - // 2 Click Social Media Buttons + // 2 Click Social Media Buttons 'add-link-to-facebook/add-link-to-facebook.php', // Add Link to Facebook 'add-meta-tags/add-meta-tags.php', // Add Meta Tags 'easy-facebook-share-thumbnails/esft.php', // Easy Facebook Share Thumbnail 'heateor-open-graph-meta-tags/heateor-open-graph-meta-tags.php', - // Open Graph Meta Tags by Heateor + // Open Graph Meta Tags by Heateor 'facebook/facebook.php', // Facebook (official plugin) 'facebook-awd/AWD_facebook.php', // Facebook AWD All in one 'facebook-featured-image-and-open-graph-meta-tags/fb-featured-image.php', - // Facebook Featured Image & OG Meta Tags + // Facebook Featured Image & OG Meta Tags 'facebook-meta-tags/facebook-metatags.php', // Facebook Meta Tags 'wonderm00ns-simple-facebook-open-graph-tags/wonderm00n-open-graph.php', - // Facebook Open Graph Meta Tags for WordPress + // Facebook Open Graph Meta Tags for WordPress 'facebook-revised-open-graph-meta-tag/index.php', // Facebook Revised Open Graph Meta Tag 'facebook-thumb-fixer/_facebook-thumb-fixer.php', // Facebook Thumb Fixer 'facebook-and-digg-thumbnail-generator/facebook-and-digg-thumbnail-generator.php', - // Fedmich's Facebook Open Graph Meta + // Fedmich's Facebook Open Graph Meta 'network-publisher/networkpub.php', // Network Publisher 'nextgen-facebook/nextgen-facebook.php', // NextGEN Facebook OG 'social-networks-auto-poster-facebook-twitter-g/NextScripts_SNAP.php', - // NextScripts SNAP + // NextScripts SNAP 'og-tags/og-tags.php', // OG Tags 'opengraph/opengraph.php', // Open Graph 'open-graph-protocol-framework/open-graph-protocol-framework.php', - // Open Graph Protocol Framework + // Open Graph Protocol Framework 'seo-facebook-comments/seofacebook.php', // SEO Facebook Comments 'seo-ultimate/seo-ultimate.php', // SEO Ultimate 'sexybookmarks/sexy-bookmarks.php', // Shareaholic @@ -267,30 +303,30 @@ class Jetpack { 'socialize/socialize.php', // Socialize 'squirrly-seo/squirrly.php', // SEO by SQUIRRLY™ 'only-tweet-like-share-and-google-1/tweet-like-plusone.php', - // Tweet, Like, Google +1 and Share + // Tweet, Like, Google +1 and Share 'wordbooker/wordbooker.php', // Wordbooker 'wpsso/wpsso.php', // WordPress Social Sharing Optimization 'wp-caregiver/wp-caregiver.php', // WP Caregiver 'wp-facebook-like-send-open-graph-meta/wp-facebook-like-send-open-graph-meta.php', - // WP Facebook Like Send & Open Graph Meta + // WP Facebook Like Send & Open Graph Meta 'wp-facebook-open-graph-protocol/wp-facebook-ogp.php', // WP Facebook Open Graph protocol 'wp-ogp/wp-ogp.php', // WP-OGP 'zoltonorg-social-plugin/zosp.php', // Zolton.org Social Plugin 'wp-fb-share-like-button/wp_fb_share-like_widget.php', // WP Facebook Like Button - 'open-graph-metabox/open-graph-metabox.php' // Open Graph Metabox + 'open-graph-metabox/open-graph-metabox.php', // Open Graph Metabox ); /** * Plugins for which we turn off our Twitter Cards Tags implementation. */ private $twitter_cards_conflicting_plugins = array( - // 'twitter/twitter.php', // The official one handles this on its own. - // // https://github.com/twitter/wordpress/blob/master/src/Twitter/WordPress/Cards/Compatibility.php - 'eewee-twitter-card/index.php', // Eewee Twitter Card + // 'twitter/twitter.php', // The official one handles this on its own. + // https://github.com/twitter/wordpress/blob/master/src/Twitter/WordPress/Cards/Compatibility.php + 'eewee-twitter-card/index.php', // Eewee Twitter Card 'ig-twitter-cards/ig-twitter-cards.php', // IG:Twitter Cards 'jm-twitter-cards/jm-twitter-cards.php', // JM Twitter Cards 'kevinjohn-gallagher-pure-web-brilliants-social-graph-twitter-cards-extention/kevinjohn_gallagher___social_graph_twitter_output.php', - // Pure Web Brilliant's Social Graph Twitter Cards Extension + // Pure Web Brilliant's Social Graph Twitter Cards Extension 'twitter-cards/twitter-cards.php', // Twitter Cards 'twitter-cards-meta/twitter-cards-meta.php', // Twitter Cards Meta 'wp-to-twitter/wp-to-twitter.php', // WP to Twitter @@ -299,18 +335,21 @@ class Jetpack { /** * Message to display in admin_notice + * * @var string */ public $message = ''; /** * Error to display in admin_notice + * * @var string */ public $error = ''; /** * Modules that need more privacy description. + * * @var string */ public $privacy_checks = ''; @@ -333,12 +372,18 @@ class Jetpack { public $json_api_authorization_request = array(); /** + * @var Automattic\Jetpack\Connection\Manager + */ + protected $connection_manager; + + /** * @var string Transient key used to prevent multiple simultaneous plugin upgrades */ public static $plugin_upgrade_lock_key = 'jetpack_upgrade_lock'; /** * Holds the singleton instance of this class + * * @since 2.3.3 * @var Jetpack */ @@ -346,11 +391,12 @@ class Jetpack { /** * Singleton + * * @static */ public static function init() { if ( ! self::$instance ) { - self::$instance = new Jetpack; + self::$instance = new Jetpack(); self::$instance->plugin_upgrade(); } @@ -362,7 +408,7 @@ class Jetpack { * Must never be called statically */ function plugin_upgrade() { - if ( Jetpack::is_active() ) { + if ( self::is_active() ) { list( $version ) = explode( ':', Jetpack_Options::get_option( 'version' ) ); if ( JETPACK__VERSION != $version ) { // Prevent multiple upgrades at once - only a single process should trigger @@ -375,10 +421,10 @@ class Jetpack { set_transient( self::$plugin_upgrade_lock_key, 1, 10 ); // check which active modules actually exist and remove others from active_modules list - $unfiltered_modules = Jetpack::get_active_modules(); - $modules = array_filter( $unfiltered_modules, array( 'Jetpack', 'is_module' ) ); + $unfiltered_modules = self::get_active_modules(); + $modules = array_filter( $unfiltered_modules, array( 'Jetpack', 'is_module' ) ); if ( array_diff( $unfiltered_modules, $modules ) ) { - Jetpack::update_active_modules( $modules ); + self::update_active_modules( $modules ); } add_action( 'init', array( __CLASS__, 'activate_new_modules' ) ); @@ -420,7 +466,7 @@ class Jetpack { return; } - Jetpack::maybe_set_version_option(); + self::maybe_set_version_option(); if ( method_exists( 'Jetpack_Widget_Conditions', 'migrate_post_type_rules' ) ) { Jetpack_Widget_Conditions::migrate_post_type_rules(); @@ -433,59 +479,69 @@ class Jetpack { do_action( 'jetpack_sitemaps_purge_data' ); } + // Delete old stats cache + delete_option( 'jetpack_restapi_stats_cache' ); + delete_transient( self::$plugin_upgrade_lock_key ); } + /** + * Saves all the currently active modules to options. + * Also fires Action hooks for each newly activated and deactivated module. + * + * @param $modules Array Array of active modules to be saved in options. + * + * @return $success bool true for success, false for failure. + */ static function update_active_modules( $modules ) { - $current_modules = Jetpack_Options::get_option( 'active_modules', array() ); - - $success = Jetpack_Options::update_option( 'active_modules', array_unique( $modules ) ); - - if ( is_array( $modules ) && is_array( $current_modules ) ) { - $new_active_modules = array_diff( $modules, $current_modules ); - foreach( $new_active_modules as $module ) { - /** - * Fires when a specific module is activated. - * - * @since 1.9.0 - * - * @param string $module Module slug. - * @param boolean $success whether the module was activated. @since 4.2 - */ - do_action( 'jetpack_activate_module', $module, $success ); - - /** - * Fires when a module is activated. - * The dynamic part of the filter, $module, is the module slug. - * - * @since 1.9.0 - * - * @param string $module Module slug. - */ - do_action( "jetpack_activate_module_$module", $module ); - } + $current_modules = Jetpack_Options::get_option( 'active_modules', array() ); + $active_modules = self::get_active_modules(); + $new_active_modules = array_diff( $modules, $current_modules ); + $new_inactive_modules = array_diff( $active_modules, $modules ); + $new_current_modules = array_diff( array_merge( $current_modules, $new_active_modules ), $new_inactive_modules ); + $reindexed_modules = array_values( $new_current_modules ); + $success = Jetpack_Options::update_option( 'active_modules', array_unique( $reindexed_modules ) ); + + foreach ( $new_active_modules as $module ) { + /** + * Fires when a specific module is activated. + * + * @since 1.9.0 + * + * @param string $module Module slug. + * @param boolean $success whether the module was activated. @since 4.2 + */ + do_action( 'jetpack_activate_module', $module, $success ); + /** + * Fires when a module is activated. + * The dynamic part of the filter, $module, is the module slug. + * + * @since 1.9.0 + * + * @param string $module Module slug. + */ + do_action( "jetpack_activate_module_$module", $module ); + } - $new_deactive_modules = array_diff( $current_modules, $modules ); - foreach( $new_deactive_modules as $module ) { - /** - * Fired after a module has been deactivated. - * - * @since 4.2.0 - * - * @param string $module Module slug. - * @param boolean $success whether the module was deactivated. - */ - do_action( 'jetpack_deactivate_module', $module, $success ); - /** - * Fires when a module is deactivated. - * The dynamic part of the filter, $module, is the module slug. - * - * @since 1.9.0 - * - * @param string $module Module slug. - */ - do_action( "jetpack_deactivate_module_$module", $module ); - } + foreach ( $new_inactive_modules as $module ) { + /** + * Fired after a module has been deactivated. + * + * @since 4.2.0 + * + * @param string $module Module slug. + * @param boolean $success whether the module was deactivated. + */ + do_action( 'jetpack_deactivate_module', $module, $success ); + /** + * Fires when a module is deactivated. + * The dynamic part of the filter, $module, is the module slug. + * + * @since 1.9.0 + * + * @param string $module Module slug. + */ + do_action( "jetpack_deactivate_module_$module", $module ); } return $success; @@ -507,13 +563,29 @@ class Jetpack { /* * Enable enhanced handling of previewing sites in Calypso */ - if ( Jetpack::is_active() ) { + if ( self::is_active() ) { require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.jetpack-iframe-embed.php'; add_action( 'init', array( 'Jetpack_Iframe_Embed', 'init' ), 9, 0 ); require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.jetpack-keyring-service-helper.php'; add_action( 'init', array( 'Jetpack_Keyring_Service_Helper', 'init' ), 9, 0 ); } + add_action( 'plugins_loaded', array( $this, 'after_plugins_loaded' ) ); + + add_filter( + 'jetpack_connection_secret_generator', + function( $callable ) { + return function() { + return wp_generate_password( 32, false ); + }; + } + ); + + add_action( 'jetpack_verify_signature_error', array( $this, 'track_xmlrpc_error' ) ); + + $this->connection_manager = new Connection_Manager(); + $this->connection_manager->init(); + /* * Load things that should only be in Network Admin. * @@ -522,105 +594,53 @@ class Jetpack { * available */ if ( is_multisite() ) { - Jetpack_Network::init(); + $network = Jetpack_Network::init(); + $network->set_connection( $this->connection_manager ); } + add_filter( + 'jetpack_signature_check_token', + array( __CLASS__, 'verify_onboarding_token' ), + 10, + 3 + ); + /** * Prepare Gutenberg Editor functionality */ require_once JETPACK__PLUGIN_DIR . 'class.jetpack-gutenberg.php'; - Jetpack_Gutenberg::init(); - Jetpack_Gutenberg::load_independent_blocks(); + add_action( 'plugins_loaded', array( 'Jetpack_Gutenberg', 'init' ) ); + add_action( 'plugins_loaded', array( 'Jetpack_Gutenberg', 'load_independent_blocks' ) ); add_action( 'enqueue_block_editor_assets', array( 'Jetpack_Gutenberg', 'enqueue_block_editor_assets' ) ); add_action( 'set_user_role', array( $this, 'maybe_clear_other_linked_admins_transient' ), 10, 3 ); - // Unlink user before deleting the user from .com - add_action( 'deleted_user', array( $this, 'unlink_user' ), 10, 1 ); - add_action( 'remove_user_from_blog', array( $this, 'unlink_user' ), 10, 1 ); - - // Alternate XML-RPC, via ?for=jetpack&jetpack=comms - if ( isset( $_GET['jetpack'] ) && 'comms' == $_GET['jetpack'] && isset( $_GET['for'] ) && 'jetpack' == $_GET['for'] ) { - if ( ! defined( 'XMLRPC_REQUEST' ) ) { - define( 'XMLRPC_REQUEST', true ); - } - - add_action( 'template_redirect', array( $this, 'alternate_xmlrpc' ) ); - - add_filter( 'xmlrpc_methods', array( $this, 'remove_non_jetpack_xmlrpc_methods' ), 1000 ); - } - - if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST && isset( $_GET['for'] ) && 'jetpack' == $_GET['for'] ) { - @ini_set( 'display_errors', false ); // Display errors can cause the XML to be not well formed. - - require_once JETPACK__PLUGIN_DIR . 'class.jetpack-xmlrpc-server.php'; - $this->xmlrpc_server = new Jetpack_XMLRPC_Server(); + // Unlink user before deleting the user from WP.com. + add_action( 'deleted_user', array( 'Automattic\\Jetpack\\Connection\\Manager', 'disconnect_user' ), 10, 1 ); + add_action( 'remove_user_from_blog', array( 'Automattic\\Jetpack\\Connection\\Manager', 'disconnect_user' ), 10, 1 ); - $this->require_jetpack_authentication(); + // Initialize remote file upload request handlers. + $this->add_remote_request_handlers(); - if ( Jetpack::is_active() ) { - // Hack to preserve $HTTP_RAW_POST_DATA - add_filter( 'xmlrpc_methods', array( $this, 'xmlrpc_methods' ) ); - - $signed = $this->verify_xml_rpc_signature(); - if ( $signed && ! is_wp_error( $signed ) ) { - // The actual API methods. - add_filter( 'xmlrpc_methods', array( $this->xmlrpc_server, 'xmlrpc_methods' ) ); - } else { - // The jetpack.authorize method should be available for unauthenticated users on a site with an - // active Jetpack connection, so that additional users can link their account. - add_filter( 'xmlrpc_methods', array( $this->xmlrpc_server, 'authorize_xmlrpc_methods' ) ); - } - } else { - // The bootstrap API methods. - add_filter( 'xmlrpc_methods', array( $this->xmlrpc_server, 'bootstrap_xmlrpc_methods' ) ); - $signed = $this->verify_xml_rpc_signature(); - if ( $signed && ! is_wp_error( $signed ) ) { - // the jetpack Provision method is available for blog-token-signed requests - add_filter( 'xmlrpc_methods', array( $this->xmlrpc_server, 'provision_xmlrpc_methods' ) ); - } - } - - // Now that no one can authenticate, and we're whitelisting all XML-RPC methods, force enable_xmlrpc on. - add_filter( 'pre_option_enable_xmlrpc', '__return_true' ); - } elseif ( - is_admin() && - isset( $_POST['action'] ) && ( - 'jetpack_upload_file' == $_POST['action'] || - 'jetpack_update_file' == $_POST['action'] - ) - ) { - $this->require_jetpack_authentication(); - $this->add_remote_request_handlers(); - } else { - if ( Jetpack::is_active() ) { - add_action( 'login_form_jetpack_json_api_authorization', array( &$this, 'login_form_json_api_authorization' ) ); - add_filter( 'xmlrpc_methods', array( $this, 'public_xmlrpc_methods' ) ); - } - } + if ( self::is_active() ) { + add_action( 'login_form_jetpack_json_api_authorization', array( $this, 'login_form_json_api_authorization' ) ); - if ( Jetpack::is_active() ) { Jetpack_Heartbeat::init(); - if ( Jetpack::is_module_active( 'stats' ) && Jetpack::is_module_active( 'search' ) ) { + if ( self::is_module_active( 'stats' ) && self::is_module_active( 'search' ) ) { require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.jetpack-search-performance-logger.php'; Jetpack_Search_Performance_Logger::init(); } } + add_action( 'jetpack_event_log', array( 'Jetpack', 'log' ), 10, 2 ); + add_filter( 'determine_current_user', array( $this, 'wp_rest_authenticate' ) ); add_filter( 'rest_authentication_errors', array( $this, 'wp_rest_authentication_errors' ) ); - add_action( 'jetpack_clean_nonces', array( 'Jetpack', 'clean_nonces' ) ); - if ( ! wp_next_scheduled( 'jetpack_clean_nonces' ) ) { - wp_schedule_event( time(), 'hourly', 'jetpack_clean_nonces' ); - } - - add_filter( 'xmlrpc_blog_options', array( $this, 'xmlrpc_options' ) ); - add_action( 'admin_init', array( $this, 'admin_init' ) ); add_action( 'admin_init', array( $this, 'dismiss_jetpack_notice' ) ); - add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) ); + add_filter( 'admin_body_class', array( $this, 'admin_body_class' ), 20 ); add_action( 'wp_dashboard_setup', array( $this, 'wp_dashboard_setup' ) ); // Filter the dashboard meta box order to swap the new one in in place of the old one. @@ -629,12 +649,6 @@ class Jetpack { // returns HTTPS support status add_action( 'wp_ajax_jetpack-recheck-ssl', array( $this, 'ajax_recheck_ssl' ) ); - // JITM AJAX callback function - add_action( 'wp_ajax_jitm_ajax', array( $this, 'jetpack_jitm_ajax_callback' ) ); - - // Universal ajax callback for all tracking events triggered via js - add_action( 'wp_ajax_jetpack_tracks', array( $this, 'jetpack_admin_ajax_tracks_callback' ) ); - add_action( 'wp_ajax_jetpack_connection_banner', array( $this, 'jetpack_connection_banner_callback' ) ); add_action( 'wp_loaded', array( $this, 'register_assets' ) ); @@ -648,12 +662,13 @@ class Jetpack { * These actions run checks to load additional files. * They check for external files or plugins, so they need to run as late as possible. */ - add_action( 'wp_head', array( $this, 'check_open_graph' ), 1 ); - add_action( 'plugins_loaded', array( $this, 'check_twitter_tags' ), 999 ); + add_action( 'wp_head', array( $this, 'check_open_graph' ), 1 ); + add_action( 'amp_story_head', array( $this, 'check_open_graph' ), 1 ); + add_action( 'plugins_loaded', array( $this, 'check_twitter_tags' ), 999 ); add_action( 'plugins_loaded', array( $this, 'check_rest_api_compat' ), 1000 ); - add_filter( 'plugins_url', array( 'Jetpack', 'maybe_min_asset' ), 1, 3 ); - add_action( 'style_loader_src', array( 'Jetpack', 'set_suffix_on_min' ), 10, 2 ); + add_filter( 'plugins_url', array( 'Jetpack', 'maybe_min_asset' ), 1, 3 ); + add_action( 'style_loader_src', array( 'Jetpack', 'set_suffix_on_min' ), 10, 2 ); add_filter( 'style_loader_tag', array( 'Jetpack', 'maybe_inline_style' ), 10, 2 ); add_filter( 'map_meta_cap', array( $this, 'jetpack_custom_caps' ), 1, 4 ); @@ -663,20 +678,26 @@ class Jetpack { add_filter( 'jetpack_get_default_modules', array( $this, 'handle_deprecated_modules' ), 99 ); // A filter to control all just in time messages - add_filter( 'jetpack_just_in_time_msgs', '__return_true', 9 ); - add_filter( 'jetpack_just_in_time_msg_cache', '__return_true', 9); + add_filter( 'jetpack_just_in_time_msgs', array( $this, 'is_active_and_not_development_mode' ), 9 ); + + add_filter( 'jetpack_just_in_time_msg_cache', '__return_true', 9 ); // If enabled, point edit post, page, and comment links to Calypso instead of WP-Admin. // We should make sure to only do this for front end links. - if ( Jetpack::get_option( 'edit_links_calypso_redirect' ) && ! is_admin() ) { + if ( self::get_option( 'edit_links_calypso_redirect' ) && ! is_admin() ) { add_filter( 'get_edit_post_link', array( $this, 'point_edit_post_links_to_calypso' ), 1, 2 ); add_filter( 'get_edit_comment_link', array( $this, 'point_edit_comment_links_to_calypso' ), 1 ); - //we'll override wp_notify_postauthor and wp_notify_moderator pluggable functions - //so they point moderation links on emails to Calypso + // we'll override wp_notify_postauthor and wp_notify_moderator pluggable functions + // so they point moderation links on emails to Calypso jetpack_require_lib( 'functions.wp-notify' ); } + // Hide edit post link if mobile app. + if ( Jetpack_User_Agent_Info::is_mobile_app() ) { + add_filter( 'edit_post_link', '__return_empty_string' ); + } + // Update the Jetpack plan from API on heartbeats add_action( 'jetpack_heartbeat', array( 'Jetpack_Plan', 'refresh_from_wpcom' ) ); @@ -686,7 +707,7 @@ class Jetpack { * * Super late priority so we catch all the registered styles */ - if( !is_admin() ) { + if ( ! is_admin() ) { add_action( 'wp_print_styles', array( $this, 'implode_frontend_css' ), -1 ); // Run first add_action( 'wp_print_footer_scripts', array( $this, 'implode_frontend_css' ), -1 ); // Run first to trigger before `print_late_styles` } @@ -700,6 +721,75 @@ class Jetpack { if ( ! has_action( 'shutdown', array( $this, 'push_stats' ) ) ) { add_action( 'shutdown', array( $this, 'push_stats' ) ); } + + /* + * Load some scripts asynchronously. + */ + add_action( 'script_loader_tag', array( $this, 'script_add_async' ), 10, 3 ); + + // Actions for Manager::authorize(). + add_action( 'jetpack_authorize_starting', array( $this, 'authorize_starting' ) ); + add_action( 'jetpack_authorize_ending_linked', array( $this, 'authorize_ending_linked' ) ); + add_action( 'jetpack_authorize_ending_authorized', array( $this, 'authorize_ending_authorized' ) ); + + // Filters for the Manager::get_token() urls and request body. + add_filter( 'jetpack_token_processing_url', array( __CLASS__, 'filter_connect_processing_url' ) ); + add_filter( 'jetpack_token_redirect_url', array( __CLASS__, 'filter_connect_redirect_url' ) ); + add_filter( 'jetpack_token_request_body', array( __CLASS__, 'filter_token_request_body' ) ); + } + + /** + * Runs after all the plugins have loaded but before init. + */ + function after_plugins_loaded() { + + $terms_of_service = new Terms_Of_Service(); + $tracking = new Plugin_Tracking(); + if ( $terms_of_service->has_agreed() ) { + add_action( 'init', array( $tracking, 'init' ) ); + } else { + /** + * Initialize tracking right after the user agrees to the terms of service. + */ + add_action( 'jetpack_agreed_to_terms_of_service', array( $tracking, 'init' ) ); + } + } + + /** + * Sets up the XMLRPC request handlers. + * + * @deprecated since 7.7.0 + * @see Automattic\Jetpack\Connection\Manager::setup_xmlrpc_handlers() + * + * @param Array $request_params Incoming request parameters. + * @param Boolean $is_active Whether the connection is currently active. + * @param Boolean $is_signed Whether the signature check has been successful. + * @param Jetpack_XMLRPC_Server $xmlrpc_server (optional) An instance of the server to use instead of instantiating a new one. + */ + public function setup_xmlrpc_handlers( + $request_params, + $is_active, + $is_signed, + Jetpack_XMLRPC_Server $xmlrpc_server = null + ) { + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::setup_xmlrpc_handlers' ); + return $this->connection_manager->setup_xmlrpc_handlers( + $request_params, + $is_active, + $is_signed, + $xmlrpc_server + ); + } + + /** + * Initialize REST API registration connector. + * + * @deprecated since 7.7.0 + * @see Automattic\Jetpack\Connection\Manager::initialize_rest_api_registration_connector() + */ + public function initialize_rest_api_registration_connector() { + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::initialize_rest_api_registration_connector' ); + $this->connection_manager->initialize_rest_api_registration_connector(); } /** @@ -738,9 +828,9 @@ class Jetpack { // Mapping the allowed CPTs on WordPress.com to corresponding paths in Calypso. // https://en.support.wordpress.com/custom-post-types/ $allowed_post_types = array( - 'post' => 'post', - 'page' => 'page', - 'jetpack-portfolio' => 'edit/jetpack-portfolio', + 'post' => 'post', + 'page' => 'page', + 'jetpack-portfolio' => 'edit/jetpack-portfolio', 'jetpack-testimonial' => 'edit/jetpack-testimonial', ); @@ -750,7 +840,7 @@ class Jetpack { $path_prefix = $allowed_post_types[ $post_type ]; - $site_slug = Jetpack::build_raw_urls( get_home_url() ); + $site_slug = self::build_raw_urls( get_home_url() ); return esc_url( sprintf( 'https://wordpress.com/%s/%s/%d', $path_prefix, $site_slug, $post_id ) ); } @@ -758,10 +848,13 @@ class Jetpack { function point_edit_comment_links_to_calypso( $url ) { // Take the `query` key value from the URL, and parse its parts to the $query_args. `amp;c` matches the comment ID. wp_parse_str( wp_parse_url( $url, PHP_URL_QUERY ), $query_args ); - return esc_url( sprintf( 'https://wordpress.com/comment/%s/%d', - Jetpack::build_raw_urls( get_home_url() ), - $query_args['amp;c'] - ) ); + return esc_url( + sprintf( + 'https://wordpress.com/comment/%s/%d', + self::build_raw_urls( get_home_url() ), + $query_args['amp;c'] + ) + ); } function jetpack_track_last_sync_callback( $params ) { @@ -803,19 +896,15 @@ class Jetpack { * Only used in our alternate XML-RPC endpoint, where we want to * ensure that Core and other plugins' methods are not exposed. * - * @param array $methods - * @return array filtered $methods + * @deprecated since 7.7.0 + * @see Automattic\Jetpack\Connection\Manager::remove_non_jetpack_xmlrpc_methods() + * + * @param array $methods A list of registered WordPress XMLRPC methods. + * @return array Filtered $methods */ - function remove_non_jetpack_xmlrpc_methods( $methods ) { - $jetpack_methods = array(); - - foreach ( $methods as $method => $callback ) { - if ( 0 === strpos( $method, 'jetpack.' ) ) { - $jetpack_methods[ $method ] = $callback; - } - } - - return $jetpack_methods; + public function remove_non_jetpack_xmlrpc_methods( $methods ) { + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::remove_non_jetpack_xmlrpc_methods' ); + return $this->connection_manager->remove_non_jetpack_xmlrpc_methods( $methods ); } /** @@ -824,131 +913,22 @@ class Jetpack { * security/firewall policies, we provide our own alternate XML RPC API endpoint * which is accessible via a different URI. Most of the below is copied directly * from /xmlrpc.php so that we're replicating it as closely as possible. + * + * @deprecated since 7.7.0 + * @see Automattic\Jetpack\Connection\Manager::alternate_xmlrpc() */ - function alternate_xmlrpc() { - // phpcs:disable PHPCompatibility.Variables.RemovedPredefinedGlobalVariables.http_raw_post_dataDeprecatedRemoved - global $HTTP_RAW_POST_DATA; - - // Some browser-embedded clients send cookies. We don't want them. - $_COOKIE = array(); - - // A bug in PHP < 5.2.2 makes $HTTP_RAW_POST_DATA not set by default, - // but we can do it ourself. - if ( ! isset( $HTTP_RAW_POST_DATA ) ) { - $HTTP_RAW_POST_DATA = file_get_contents( 'php://input' ); - } - - // fix for mozBlog and other cases where '<?xml' isn't on the very first line - if ( isset( $HTTP_RAW_POST_DATA ) ) { - $HTTP_RAW_POST_DATA = trim( $HTTP_RAW_POST_DATA ); - } - - // phpcs:enable - - include_once( ABSPATH . 'wp-admin/includes/admin.php' ); - include_once( ABSPATH . WPINC . '/class-IXR.php' ); - include_once( ABSPATH . WPINC . '/class-wp-xmlrpc-server.php' ); - - /** - * Filters the class used for handling XML-RPC requests. - * - * @since 3.1.0 - * - * @param string $class The name of the XML-RPC server class. - */ - $wp_xmlrpc_server_class = apply_filters( 'wp_xmlrpc_server_class', 'wp_xmlrpc_server' ); - $wp_xmlrpc_server = new $wp_xmlrpc_server_class; - - // Fire off the request - nocache_headers(); - $wp_xmlrpc_server->serve_request(); - - exit; - } - - function jetpack_admin_ajax_tracks_callback() { - // Check for nonce - if ( ! isset( $_REQUEST['tracksNonce'] ) || ! wp_verify_nonce( $_REQUEST['tracksNonce'], 'jp-tracks-ajax-nonce' ) ) { - wp_die( 'Permissions check failed.' ); - } - - if ( ! isset( $_REQUEST['tracksEventName'] ) || ! isset( $_REQUEST['tracksEventType'] ) ) { - wp_die( 'No valid event name or type.' ); - } - - $tracks_data = array(); - if ( 'click' === $_REQUEST['tracksEventType'] && isset( $_REQUEST['tracksEventProp'] ) ) { - if ( is_array( $_REQUEST['tracksEventProp'] ) ) { - $tracks_data = $_REQUEST['tracksEventProp']; - } else { - $tracks_data = array( 'clicked' => $_REQUEST['tracksEventProp'] ); - } - } - - JetpackTracking::record_user_event( $_REQUEST['tracksEventName'], $tracks_data ); - wp_send_json_success(); - wp_die(); + public function alternate_xmlrpc() { + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::alternate_xmlrpc' ); + $this->connection_manager->alternate_xmlrpc(); } /** * The callback for the JITM ajax requests. + * + * @deprecated since 7.9.0 */ function jetpack_jitm_ajax_callback() { - // Check for nonce - if ( ! isset( $_REQUEST['jitmNonce'] ) || ! wp_verify_nonce( $_REQUEST['jitmNonce'], 'jetpack-jitm-nonce' ) ) { - wp_die( 'Module activation failed due to lack of appropriate permissions' ); - } - if ( isset( $_REQUEST['jitmActionToTake'] ) && 'activate' == $_REQUEST['jitmActionToTake'] ) { - $module_slug = $_REQUEST['jitmModule']; - Jetpack::log( 'activate', $module_slug ); - Jetpack::activate_module( $module_slug, false, false ); - Jetpack::state( 'message', 'no_message' ); - - //A Jetpack module is being activated through a JITM, track it - $this->stat( 'jitm', $module_slug.'-activated-' . JETPACK__VERSION ); - $this->do_stats( 'server_side' ); - - wp_send_json_success(); - } - if ( isset( $_REQUEST['jitmActionToTake'] ) && 'dismiss' == $_REQUEST['jitmActionToTake'] ) { - // get the hide_jitm options array - $jetpack_hide_jitm = Jetpack_Options::get_option( 'hide_jitm' ); - $module_slug = $_REQUEST['jitmModule']; - - if( ! $jetpack_hide_jitm ) { - $jetpack_hide_jitm = array( - $module_slug => 'hide' - ); - } else { - $jetpack_hide_jitm[$module_slug] = 'hide'; - } - - Jetpack_Options::update_option( 'hide_jitm', $jetpack_hide_jitm ); - - //jitm is being dismissed forever, track it - $this->stat( 'jitm', $module_slug.'-dismissed-' . JETPACK__VERSION ); - $this->do_stats( 'server_side' ); - - wp_send_json_success(); - } - if ( isset( $_REQUEST['jitmActionToTake'] ) && 'launch' == $_REQUEST['jitmActionToTake'] ) { - $module_slug = $_REQUEST['jitmModule']; - - // User went to WordPress.com, track this - $this->stat( 'jitm', $module_slug.'-wordpress-tools-' . JETPACK__VERSION ); - $this->do_stats( 'server_side' ); - - wp_send_json_success(); - } - if ( isset( $_REQUEST['jitmActionToTake'] ) && 'viewed' == $_REQUEST['jitmActionToTake'] ) { - $track = $_REQUEST['jitmModule']; - - // User is viewing JITM, track it. - $this->stat( 'jitm', $track . '-viewed-' . JETPACK__VERSION ); - $this->do_stats( 'server_side' ); - - wp_send_json_success(); - } + _deprecated_function( __METHOD__, 'jetpack-7.9' ); } /** @@ -961,10 +941,11 @@ class Jetpack { } function jetpack_custom_caps( $caps, $cap, $user_id, $args ) { - switch( $cap ) { - case 'jetpack_connect' : - case 'jetpack_reconnect' : - if ( Jetpack::is_development_mode() ) { + $is_development_mode = ( new Status() )->is_development_mode(); + switch ( $cap ) { + case 'jetpack_connect': + case 'jetpack_reconnect': + if ( $is_development_mode ) { $caps = array( 'do_not_allow' ); break; } @@ -972,7 +953,7 @@ class Jetpack { * Pass through. If it's not development mode, these should match disconnect. * Let users disconnect if it's development mode, just in case things glitch. */ - case 'jetpack_disconnect' : + case 'jetpack_disconnect': /** * In multisite, can individual site admins manage their own connection? * @@ -993,15 +974,15 @@ class Jetpack { $caps = array( 'manage_options' ); break; - case 'jetpack_manage_modules' : - case 'jetpack_activate_modules' : - case 'jetpack_deactivate_modules' : + case 'jetpack_manage_modules': + case 'jetpack_activate_modules': + case 'jetpack_deactivate_modules': $caps = array( 'manage_options' ); break; - case 'jetpack_configure_modules' : + case 'jetpack_configure_modules': $caps = array( 'manage_options' ); break; - case 'jetpack_manage_autoupdates' : + case 'jetpack_manage_autoupdates': $caps = array( 'manage_options', 'update_plugins', @@ -1014,16 +995,16 @@ class Jetpack { case 'jetpack_network_sites_page': $caps = array( 'manage_sites' ); break; - case 'jetpack_admin_page' : - if ( Jetpack::is_development_mode() ) { + case 'jetpack_admin_page': + if ( $is_development_mode ) { $caps = array( 'manage_options' ); break; } else { $caps = array( 'read' ); } break; - case 'jetpack_connect_user' : - if ( Jetpack::is_development_mode() ) { + case 'jetpack_connect_user': + if ( $is_development_mode ) { $caps = array( 'do_not_allow' ); break; } @@ -1033,20 +1014,20 @@ class Jetpack { return $caps; } - function require_jetpack_authentication() { - // Don't let anyone authenticate - $_COOKIE = array(); - remove_all_filters( 'authenticate' ); - remove_all_actions( 'wp_login_failed' ); - - if ( Jetpack::is_active() ) { - // Allow Jetpack authentication - add_filter( 'authenticate', array( $this, 'authenticate_jetpack' ), 10, 3 ); - } + /** + * Require a Jetpack authentication. + * + * @deprecated since 7.7.0 + * @see Automattic\Jetpack\Connection\Manager::require_jetpack_authentication() + */ + public function require_jetpack_authentication() { + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::require_jetpack_authentication' ); + $this->connection_manager->require_jetpack_authentication(); } /** * Load language files + * * @action plugins_loaded */ public static function plugin_textdomain() { @@ -1065,7 +1046,7 @@ class Jetpack { if ( ! wp_script_is( 'spin', 'registered' ) ) { wp_register_script( 'spin', - self::get_file_url_for_environment( '_inc/build/spin.min.js', '_inc/spin.js' ), + Assets::get_file_url_for_environment( '_inc/build/spin.min.js', '_inc/spin.js' ), false, '1.3' ); @@ -1074,7 +1055,7 @@ class Jetpack { if ( ! wp_script_is( 'jquery.spin', 'registered' ) ) { wp_register_script( 'jquery.spin', - self::get_file_url_for_environment( '_inc/build/jquery.spin.min.js', '_inc/jquery.spin.js' ), + Assets::get_file_url_for_environment( '_inc/build/jquery.spin.min.js', '_inc/jquery.spin.js' ), array( 'jquery', 'spin' ), '1.3' ); @@ -1083,7 +1064,7 @@ class Jetpack { if ( ! wp_script_is( 'jetpack-gallery-settings', 'registered' ) ) { wp_register_script( 'jetpack-gallery-settings', - self::get_file_url_for_environment( '_inc/build/gallery-settings.min.js', '_inc/gallery-settings.js' ), + Assets::get_file_url_for_environment( '_inc/build/gallery-settings.min.js', '_inc/gallery-settings.js' ), array( 'media-views' ), '20121225' ); @@ -1092,7 +1073,7 @@ class Jetpack { if ( ! wp_script_is( 'jetpack-twitter-timeline', 'registered' ) ) { wp_register_script( 'jetpack-twitter-timeline', - self::get_file_url_for_environment( '_inc/build/twitter-timeline.min.js', '_inc/twitter-timeline.js' ), + Assets::get_file_url_for_environment( '_inc/build/twitter-timeline.min.js', '_inc/twitter-timeline.js' ), array( 'jquery' ), '4.0.0', true @@ -1102,7 +1083,7 @@ class Jetpack { if ( ! wp_script_is( 'jetpack-facebook-embed', 'registered' ) ) { wp_register_script( 'jetpack-facebook-embed', - self::get_file_url_for_environment( '_inc/build/facebook-embed.min.js', '_inc/facebook-embed.js' ), + Assets::get_file_url_for_environment( '_inc/build/facebook-embed.min.js', '_inc/facebook-embed.js' ), array( 'jquery' ), null, true @@ -1117,7 +1098,7 @@ class Jetpack { 'jetpack-facebook-embed', 'jpfbembed', array( - 'appid' => $fb_app_id, + 'appid' => $fb_app_id, 'locale' => $this->get_locale(), ) ); @@ -1128,17 +1109,18 @@ class Jetpack { * the hook may have already fired by this point. * So, let's just trigger it manually. */ - require_once( JETPACK__PLUGIN_DIR . '_inc/genericons.php' ); + require_once JETPACK__PLUGIN_DIR . '_inc/genericons.php'; jetpack_register_genericons(); /** * Register the social logos */ - require_once( JETPACK__PLUGIN_DIR . '_inc/social-logos.php' ); + require_once JETPACK__PLUGIN_DIR . '_inc/social-logos.php'; jetpack_register_social_logos(); - if ( ! wp_style_is( 'jetpack-icons', 'registered' ) ) + if ( ! wp_style_is( 'jetpack-icons', 'registered' ) ) { wp_register_style( 'jetpack-icons', plugins_url( 'css/jetpack-icons.min.css', JETPACK__PLUGIN_FILE ), false, JETPACK__VERSION ); + } } /** @@ -1207,13 +1189,14 @@ class Jetpack { * This improves the resolution of gravatars and wordpress.com uploads on hi-res and zoomed browsers. */ function devicepx() { - if ( Jetpack::is_active() && ! Jetpack_AMP_Support::is_amp_request() ) { + if ( self::is_active() && ! Jetpack_AMP_Support::is_amp_request() ) { wp_enqueue_script( 'devicepx', 'https://s0.wp.com/wp-content/js/devicepx-jetpack.js', array(), gmdate( 'oW' ), true ); } } /** * Return the network_site_url so that .com knows what network this site is a part of. + * * @param bool $option * @return string */ @@ -1229,13 +1212,15 @@ class Jetpack { } /** * Does the network allow new user and site registrations. + * * @return string */ static function network_allow_new_registrations( $option = null ) { - return ( in_array( get_site_option( 'registration' ), array('none', 'user', 'blog', 'all' ) ) ? get_site_option( 'registration') : 'none' ); + return ( in_array( get_site_option( 'registration' ), array( 'none', 'user', 'blog', 'all' ) ) ? get_site_option( 'registration' ) : 'none' ); } /** * Does the network allow admins to add new users. + * * @return boolian */ static function network_add_new_users( $option = null ) { @@ -1244,6 +1229,7 @@ class Jetpack { /** * File upload psace left per site in MB. * -1 means NO LIMIT. + * * @return number */ static function network_site_upload_space( $option = null ) { @@ -1253,6 +1239,7 @@ class Jetpack { /** * Network allowed file types. + * * @return string */ static function network_upload_file_types( $option = null ) { @@ -1261,6 +1248,7 @@ class Jetpack { /** * Maximum file upload size set by the network. + * * @return number */ static function network_max_upload_file_size( $option = null ) { @@ -1270,6 +1258,7 @@ class Jetpack { /** * Lets us know if a site allows admins to manage the network. + * * @return array */ static function network_enable_administration_menus( $option = null ) { @@ -1312,7 +1301,7 @@ class Jetpack { if ( count( $admins ) > 1 ) { $available = array(); foreach ( $admins as $admin ) { - if ( Jetpack::is_user_connected( $admin->ID ) ) { + if ( self::is_user_connected( $admin->ID ) ) { $available[] = $admin->ID; } } @@ -1339,19 +1328,20 @@ class Jetpack { * the result is false since when is_main_network_option return false it cases * the rest the get_option( 'jetpack_is_multi_network' ); to return the value that is set in the * database which could be set to anything as opposed to what this function returns. - * @param bool $option + * + * @param bool $option * * @return boolean */ public function is_main_network_option( $option ) { // return '1' or '' - return (string) (bool) Jetpack::is_multi_network(); + return (string) (bool) self::is_multi_network(); } /** * Return true if we are with multi-site or multi-network false if we are dealing with single site. * - * @param string $option + * @param string $option * @return boolean */ public function is_multisite( $option ) { @@ -1383,6 +1373,7 @@ class Jetpack { /** * Trigger an update to the main_network_site when we update the siteurl of a site. + * * @return null */ function update_jetpack_main_network_site_option() { @@ -1390,7 +1381,6 @@ class Jetpack { } /** * Triggered after a user updates the network settings via Network Settings Admin Page - * */ function update_jetpack_network_settings() { _deprecated_function( __METHOD__, 'jetpack-4.2' ); @@ -1414,14 +1404,15 @@ class Jetpack { /** * Returns true if the site has file write access false otherwise. + * * @return string ( '1' | '0' ) **/ public static function file_system_write_access() { if ( ! function_exists( 'get_filesystem_method' ) ) { - require_once( ABSPATH . 'wp-admin/includes/file.php' ); + require_once ABSPATH . 'wp-admin/includes/file.php'; } - require_once( ABSPATH . 'wp-admin/includes/template.php' ); + require_once ABSPATH . 'wp-admin/includes/template.php'; $filesystem_method = get_filesystem_method(); if ( $filesystem_method === 'direct' ) { @@ -1439,15 +1430,17 @@ class Jetpack { /** * Finds out if a site is using a version control system. + * * @return string ( '1' | '0' ) **/ public static function is_version_controlled() { - _deprecated_function( __METHOD__, 'jetpack-4.2', 'Jetpack_Sync_Functions::is_version_controlled' ); - return (string) (int) Jetpack_Sync_Functions::is_version_controlled(); + _deprecated_function( __METHOD__, 'jetpack-4.2', 'Functions::is_version_controlled' ); + return (string) (int) Functions::is_version_controlled(); } /** * Determines whether the current theme supports featured images or not. + * * @return string ( '1' | '0' ) */ public static function featured_images_enabled() { @@ -1460,19 +1453,22 @@ class Jetpack { * * @deprecated 4.7 use get_avatar_url instead. * @param int|string|object $id_or_email A user ID, email address, or comment object - * @param int $size Size of the avatar image - * @param string $default URL to a default image to use if no avatar is available - * @param bool $force_display Whether to force it to return an avatar even if show_avatars is disabled + * @param int $size Size of the avatar image + * @param string $default URL to a default image to use if no avatar is available + * @param bool $force_display Whether to force it to return an avatar even if show_avatars is disabled * * @return array */ public static function get_avatar_url( $id_or_email, $size = 96, $default = '', $force_display = false ) { _deprecated_function( __METHOD__, 'jetpack-4.7', 'get_avatar_url' ); - return get_avatar_url( $id_or_email, array( - 'size' => $size, - 'default' => $default, - 'force_default' => $force_display, - ) ); + return get_avatar_url( + $id_or_email, + array( + 'size' => $size, + 'default' => $default, + 'force_default' => $force_display, + ) + ); } /** @@ -1481,11 +1477,12 @@ class Jetpack { * array ( * 'plugins' => (int) Number of plugin updates available. * 'themes' => (int) Number of theme updates available. - * 'wordpress' => (int) Number of WordPress core updates available. + * 'wordpress' => (int) Number of WordPress core updates available. // phpcs:ignore WordPress.WP.CapitalPDangit.Misspelled * 'translations' => (int) Number of translation updates available. * 'total' => (int) Total of all available updates. * 'wp_update_version' => (string) The latest available version of WordPress, only present if a WordPress update is needed. * ) + * * @return array */ public static function get_updates() { @@ -1508,9 +1505,9 @@ class Jetpack { public static function get_update_details() { $update_details = array( - 'update_core' => get_site_transient( 'update_core' ), + 'update_core' => get_site_transient( 'update_core' ), 'update_plugins' => get_site_transient( 'update_plugins' ), - 'update_themes' => get_site_transient( 'update_themes' ), + 'update_themes' => get_site_transient( 'update_themes' ), ); return $update_details; } @@ -1566,28 +1563,17 @@ class Jetpack { } /** - * Is Jetpack in development (offline) mode? + * Deprecated: Is Jetpack in development (offline) mode? + * + * This static method is being left here intentionally without the use of _deprecated_function(), as other plugins + * and themes still use it, and we do not want to flood them with notices. + * + * Please use Automattic\Jetpack\Status()->is_development_mode() instead. + * + * @deprecated since 8.0. */ public static function is_development_mode() { - $development_mode = false; - - if ( defined( 'JETPACK_DEV_DEBUG' ) ) { - $development_mode = JETPACK_DEV_DEBUG; - } elseif ( $site_url = site_url() ) { - $development_mode = false === strpos( $site_url, '.' ); - } - - /** - * Filters Jetpack's development mode. - * - * @see https://jetpack.com/support/development-mode/ - * - * @since 2.2.1 - * - * @param bool $development_mode Is Jetpack's development mode active. - */ - $development_mode = ( bool ) apply_filters( 'jetpack_development_mode', $development_mode ); - return $development_mode; + return ( new Status() )->is_development_mode(); } /** @@ -1609,12 +1595,12 @@ class Jetpack { * Determines reason for Jetpack development mode. */ public static function development_mode_trigger_text() { - if ( ! Jetpack::is_development_mode() ) { + if ( ! ( new Status() )->is_development_mode() ) { return __( 'Jetpack is not in Development Mode.', 'jetpack' ); } if ( defined( 'JETPACK_DEV_DEBUG' ) && JETPACK_DEV_DEBUG ) { - $notice = __( 'The JETPACK_DEV_DEBUG constant is defined in wp-config.php or elsewhere.', 'jetpack' ); + $notice = __( 'The JETPACK_DEV_DEBUG constant is defined in wp-config.php or elsewhere.', 'jetpack' ); } elseif ( site_url() && false === strpos( site_url(), '.' ) ) { $notice = __( 'The site URL lacking a dot (e.g. http://localhost).', 'jetpack' ); } else { @@ -1625,33 +1611,32 @@ class Jetpack { } /** - * Get Jetpack development mode notice text and notice class. - * - * Mirrors the checks made in Jetpack::is_development_mode - * - */ + * Get Jetpack development mode notice text and notice class. + * + * Mirrors the checks made in Automattic\Jetpack\Status->is_development_mode + */ public static function show_development_mode_notice() { - if ( Jetpack::is_development_mode() ) { + if ( ( new Status() )->is_development_mode() ) { $notice = sprintf( - /* translators: %s is a URL */ + /* translators: %s is a URL */ __( 'In <a href="%s" target="_blank">Development Mode</a>:', 'jetpack' ), 'https://jetpack.com/support/development-mode/' ); - $notice .= ' ' . Jetpack::development_mode_trigger_text(); + $notice .= ' ' . self::development_mode_trigger_text(); echo '<div class="updated" style="border-color: #f0821e;"><p>' . $notice . '</p></div>'; } // Throw up a notice if using a development version and as for feedback. - if ( Jetpack::is_development_version() ) { + if ( self::is_development_version() ) { /* translators: %s is a URL */ $notice = sprintf( __( 'You are currently running a development version of Jetpack. <a href="%s" target="_blank">Submit your feedback</a>', 'jetpack' ), 'https://jetpack.com/contact-support/beta-group/' ); echo '<div class="updated" style="border-color: #f0821e;"><p>' . $notice . '</p></div>'; } // Throw up a notice if using staging mode - if ( Jetpack::is_staging_site() ) { + if ( self::is_staging_site() ) { /* translators: %s is a URL */ $notice = sprintf( __( 'You are running Jetpack on a <a href="%s" target="_blank">staging server</a>.', 'jetpack' ), 'https://jetpack.com/support/staging-sites/' ); @@ -1674,7 +1659,7 @@ class Jetpack { */ return (bool) apply_filters( 'jetpack_development_version', - ! preg_match( '/^\d+(\.\d+)+$/', Jetpack_Constants::get_constant( 'JETPACK__VERSION' ) ) + ! preg_match( '/^\d+(\.\d+)+$/', Constants::get_constant( 'JETPACK__VERSION' ) ) ); } @@ -1682,18 +1667,14 @@ class Jetpack { * Is a given user (or the current user if none is specified) linked to a WordPress.com user? */ public static function is_user_connected( $user_id = false ) { - $user_id = false === $user_id ? get_current_user_id() : absint( $user_id ); - if ( ! $user_id ) { - return false; - } - - return (bool) Jetpack_Data::get_access_token( $user_id ); + return self::connection()->is_user_connected( $user_id ); } /** * Get the wpcom user data of the current|specified connected user. */ public static function get_connected_user_data( $user_id = null ) { + // TODO: remove in favor of Connection_Manager->get_connected_user_data if ( ! $user_id ) { $user_id = get_current_user_id(); } @@ -1704,10 +1685,11 @@ class Jetpack { return $cached_user_data; } - Jetpack::load_xml_rpc_client(); - $xml = new Jetpack_IXR_Client( array( - 'user_id' => $user_id, - ) ); + $xml = new Jetpack_IXR_Client( + array( + 'user_id' => $user_id, + ) + ); $xml->query( 'wpcom.getUser' ); if ( ! $xml->isError() ) { $user_data = $xml->getResponse(); @@ -1725,10 +1707,12 @@ class Jetpack { if ( ! $user_id ) { $user_id = get_current_user_id(); } - Jetpack::load_xml_rpc_client(); - $xml = new Jetpack_IXR_Client( array( - 'user_id' => $user_id, - ) ); + + $xml = new Jetpack_IXR_Client( + array( + 'user_id' => $user_id, + ) + ); $xml->query( 'wpcom.getUserEmail' ); if ( ! $xml->isError() ) { return $xml->getResponse(); @@ -1747,9 +1731,16 @@ class Jetpack { return ''; } - function current_user_is_connection_owner() { - $user_token = Jetpack_Data::get_access_token( JETPACK_MASTER_USER ); - return $user_token && is_object( $user_token ) && isset( $user_token->external_user_id ) && get_current_user_id() === $user_token->external_user_id; + /** + * Whether the current user is the connection owner. + * + * @deprecated since 7.7 + * + * @return bool Whether the current user is the connection owner. + */ + public function current_user_is_connection_owner() { + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::is_connection_owner' ); + return self::connection()->is_connection_owner(); } /** @@ -1785,29 +1776,31 @@ class Jetpack { */ function extra_oembed_providers() { // Cloudup: https://dev.cloudup.com/#oembed - wp_oembed_add_provider( 'https://cloudup.com/*' , 'https://cloudup.com/oembed' ); + wp_oembed_add_provider( 'https://cloudup.com/*', 'https://cloudup.com/oembed' ); wp_oembed_add_provider( 'https://me.sh/*', 'https://me.sh/oembed?format=json' ); wp_oembed_add_provider( '#https?://(www\.)?gfycat\.com/.*#i', 'https://api.gfycat.com/v1/oembed', true ); wp_oembed_add_provider( '#https?://[^.]+\.(wistia\.com|wi\.st)/(medias|embed)/.*#', 'https://fast.wistia.com/oembed', true ); wp_oembed_add_provider( '#https?://sketchfab\.com/.*#i', 'https://sketchfab.com/oembed', true ); wp_oembed_add_provider( '#https?://(www\.)?icloud\.com/keynote/.*#i', 'https://iwmb.icloud.com/iwmb/oembed', true ); + wp_oembed_add_provider( 'https://song.link/*', 'https://song.link/oembed', false ); } /** * Synchronize connected user role changes */ function user_role_change( $user_id ) { - _deprecated_function( __METHOD__, 'jetpack-4.2', 'Jetpack_Sync_Users::user_role_change()' ); - Jetpack_Sync_Users::user_role_change( $user_id ); + _deprecated_function( __METHOD__, 'jetpack-4.2', 'Users::user_role_change()' ); + Users::user_role_change( $user_id ); } /** * Loads the currently active modules. */ public static function load_modules() { + $is_development_mode = ( new Status() )->is_development_mode(); if ( ! self::is_active() - && ! self::is_development_mode() + && ! $is_development_mode && ! self::is_onboarding() && ( ! is_multisite() @@ -1826,7 +1819,7 @@ class Jetpack { } list( $version ) = explode( ':', $version ); - $modules = array_filter( Jetpack::get_active_modules(), array( 'Jetpack', 'is_module' ) ); + $modules = array_filter( self::get_active_modules(), array( 'Jetpack', 'is_module' ) ); $modules_data = array(); @@ -1834,7 +1827,7 @@ class Jetpack { if ( version_compare( $version, JETPACK__VERSION, '<' ) ) { $updated_modules = array(); foreach ( $modules as $module ) { - $modules_data[ $module ] = Jetpack::get_module( $module ); + $modules_data[ $module ] = self::get_module( $module ); if ( ! isset( $modules_data[ $module ]['changed'] ) ) { continue; } @@ -1849,14 +1842,12 @@ class Jetpack { $modules = array_diff( $modules, $updated_modules ); } - $is_development_mode = Jetpack::is_development_mode(); - foreach ( $modules as $index => $module ) { // If we're in dev mode, disable modules requiring a connection if ( $is_development_mode ) { // Prime the pump if we need to if ( empty( $modules_data[ $module ] ) ) { - $modules_data[ $module ] = Jetpack::get_module( $module ); + $modules_data[ $module ] = self::get_module( $module ); } // If the module requires a connection, but we're in local mode, don't include it. if ( $modules_data[ $module ]['requires_connection'] ) { @@ -1868,7 +1859,7 @@ class Jetpack { continue; } - if ( ! include_once( Jetpack::get_module_path( $module ) ) ) { + if ( ! include_once self::get_module_path( $module ) ) { unset( $modules[ $index ] ); self::update_active_modules( array_values( $modules ) ); continue; @@ -1891,11 +1882,12 @@ class Jetpack { do_action( 'jetpack_modules_loaded' ); // Load module-specific code that is needed even when a module isn't active. Loaded here because code contained therein may need actions such as setup_theme. - require_once( JETPACK__PLUGIN_DIR . 'modules/module-extras.php' ); + require_once JETPACK__PLUGIN_DIR . 'modules/module-extras.php'; } /** * Check if Jetpack's REST API compat file should be included + * * @action plugins_loaded * @return null */ @@ -1909,11 +1901,13 @@ class Jetpack { */ $_jetpack_rest_api_compat_includes = apply_filters( 'jetpack_rest_api_compat', array() ); - if ( function_exists( 'bbpress' ) ) + if ( function_exists( 'bbpress' ) ) { $_jetpack_rest_api_compat_includes[] = JETPACK__PLUGIN_DIR . 'class.jetpack-bbpress-json-api-compat.php'; + } - foreach ( $_jetpack_rest_api_compat_includes as $_jetpack_rest_api_compat_include ) + foreach ( $_jetpack_rest_api_compat_includes as $_jetpack_rest_api_compat_include ) { require_once $_jetpack_rest_api_compat_include; + } } /** @@ -1948,20 +1942,20 @@ class Jetpack { */ public static function get_parsed_plugin_data() { if ( ! function_exists( 'get_plugins' ) ) { - require_once( ABSPATH . 'wp-admin/includes/plugin.php' ); + require_once ABSPATH . 'wp-admin/includes/plugin.php'; } /** This filter is documented in wp-admin/includes/class-wp-plugins-list-table.php */ $all_plugins = apply_filters( 'all_plugins', get_plugins() ); - $active_plugins = Jetpack::get_active_plugins(); + $active_plugins = self::get_active_plugins(); $plugins = array(); foreach ( $all_plugins as $path => $plugin_data ) { $plugins[ $path ] = array( - 'is_active' => in_array( $path, $active_plugins ), - 'file' => $path, - 'name' => $plugin_data['Name'], - 'version' => $plugin_data['Version'], - 'author' => $plugin_data['Author'], + 'is_active' => in_array( $path, $active_plugins ), + 'file' => $path, + 'name' => $plugin_data['Name'], + 'version' => $plugin_data['Version'], + 'author' => $plugin_data['Author'], ); } @@ -1976,7 +1970,7 @@ class Jetpack { * @return array Array of theme data */ public static function get_parsed_theme_data() { - $all_themes = wp_get_themes( array( 'allowed' => true ) ); + $all_themes = wp_get_themes( array( 'allowed' => true ) ); $header_keys = array( 'Name', 'Author', 'Version', 'ThemeURI', 'AuthorURI', 'Status', 'Tags' ); $themes = array(); @@ -1987,11 +1981,11 @@ class Jetpack { } $themes[ $slug ] = array( - 'is_active_theme' => $slug == wp_get_theme()->get_template(), - 'slug' => $slug, - 'theme_root' => $theme_data->get_theme_root_uri(), - 'parent' => $theme_data->parent(), - 'headers' => $theme_headers + 'is_active_theme' => $slug == wp_get_theme()->get_template(), + 'slug' => $slug, + 'theme_root' => $theme_data->get_theme_root_uri(), + 'parent' => $theme_data->parent(), + 'headers' => $theme_headers, ); } @@ -2017,7 +2011,7 @@ class Jetpack { * @return null */ public function check_open_graph() { - if ( in_array( 'publicize', Jetpack::get_active_modules() ) || in_array( 'sharedaddy', Jetpack::get_active_modules() ) ) { + if ( in_array( 'publicize', self::get_active_modules() ) || in_array( 'sharedaddy', self::get_active_modules() ) ) { add_filter( 'jetpack_enable_open_graph', '__return_true', 0 ); } @@ -2079,16 +2073,16 @@ class Jetpack { /** * Allows plugins to submit security reports. - * - * @param string $type Report type (login_form, backup, file_scanning, spam) - * @param string $plugin_file Plugin __FILE__, so that we can pull plugin data - * @param array $args See definitions above + * + * @param string $type Report type (login_form, backup, file_scanning, spam) + * @param string $plugin_file Plugin __FILE__, so that we can pull plugin data + * @param array $args See definitions above */ public static function submit_security_report( $type = '', $plugin_file = '', $args = array() ) { _deprecated_function( __FUNCTION__, 'jetpack-4.2', null ); } -/* Jetpack Options API */ + /* Jetpack Options API */ public static function get_option_names( $type = 'compact' ) { return Jetpack_Options::get_option_names( $type ); @@ -2096,7 +2090,7 @@ class Jetpack { /** * Returns the requested option. Looks in jetpack_options or jetpack_$name as appropriate. - * + * * @param string $name Option name * @param mixed $default (optional) */ @@ -2106,7 +2100,7 @@ class Jetpack { /** * Updates the single given option. Updates jetpack_options or jetpack_$name as appropriate. - * + * * @deprecated 3.4 use Jetpack_Options::update_option() instead. * @param string $name Option name * @param mixed $value Option value @@ -2118,7 +2112,7 @@ class Jetpack { /** * Updates the multiple given options. Updates jetpack_options and/or jetpack_$name as appropriate. - * + * * @deprecated 3.4 use Jetpack_Options::update_options() instead. * @param array $array array( option name => option value, ... ) */ @@ -2140,25 +2134,18 @@ class Jetpack { } /** + * @deprecated 8.0 Use Automattic\Jetpack\Connection\Utils::update_user_token() instead. + * * Enters a user token into the user_tokens option * - * @param int $user_id - * @param string $token - * return bool + * @param int $user_id The user id. + * @param string $token The user token. + * @param bool $is_master_user Whether the user is the master user. + * @return bool */ public static function update_user_token( $user_id, $token, $is_master_user ) { - // not designed for concurrent updates - $user_tokens = Jetpack_Options::get_option( 'user_tokens' ); - if ( ! is_array( $user_tokens ) ) - $user_tokens = array(); - $user_tokens[$user_id] = $token; - if ( $is_master_user ) { - $master_user = $user_id; - $options = compact( 'user_tokens', 'master_user' ); - } else { - $options = compact( 'user_tokens' ); - } - return Jetpack_Options::update_options( $options ); + _deprecated_function( __METHOD__, 'jetpack-8.0', 'Automattic\\Jetpack\\Connection\\Utils::update_user_token' ); + return Connection_Utils::update_user_token( $user_id, $token, $is_master_user ); } /** @@ -2174,7 +2161,7 @@ class Jetpack { } $absolute_path = untrailingslashit( $absolute_path ); - $files = array(); + $files = array(); if ( ! $dir = @opendir( $absolute_path ) ) { return $files; } @@ -2199,7 +2186,7 @@ class Jetpack { } public static function activate_new_modules( $redirect = false ) { - if ( ! Jetpack::is_active() && ! Jetpack::is_development_mode() ) { + if ( ! self::is_active() && ! ( new Status() )->is_development_mode() ) { return; } @@ -2217,10 +2204,10 @@ class Jetpack { return; } - $active_modules = Jetpack::get_active_modules(); + $active_modules = self::get_active_modules(); $reactivate_modules = array(); foreach ( $active_modules as $active_module ) { - $module = Jetpack::get_module( $active_module ); + $module = self::get_module( $active_module ); if ( ! isset( $module['changed'] ) ) { continue; } @@ -2230,7 +2217,7 @@ class Jetpack { } $reactivate_modules[] = $active_module; - Jetpack::deactivate_module( $active_module ); + self::deactivate_module( $active_module ); } $new_version = JETPACK__VERSION . ':' . time(); @@ -2243,8 +2230,8 @@ class Jetpack { ) ); - Jetpack::state( 'message', 'modules_activated' ); - Jetpack::activate_default_modules( $jetpack_version, JETPACK__VERSION, $reactivate_modules ); + self::state( 'message', 'modules_activated' ); + self::activate_default_modules( $jetpack_version, JETPACK__VERSION, $reactivate_modules, $redirect ); if ( $redirect ) { $page = 'jetpack'; // make sure we redirect to either settings or the jetpack page @@ -2252,7 +2239,7 @@ class Jetpack { $page = $_GET['page']; } - wp_safe_redirect( Jetpack::admin_url( 'page=' . $page ) ); + wp_safe_redirect( self::admin_url( 'page=' . $page ) ); exit; } } @@ -2270,21 +2257,24 @@ class Jetpack { if ( ! is_admin() && ! empty( $available_modules_option[ JETPACK__VERSION ] ) ) { $modules = $available_modules_option[ JETPACK__VERSION ]; } else { - $files = Jetpack::glob_php( JETPACK__PLUGIN_DIR . 'modules' ); + $files = self::glob_php( JETPACK__PLUGIN_DIR . 'modules' ); $modules = array(); foreach ( $files as $file ) { - if ( ! $headers = Jetpack::get_module( $file ) ) { + if ( ! $headers = self::get_module( $file ) ) { continue; } - $modules[ Jetpack::get_module_slug( $file ) ] = $headers['introduced']; + $modules[ self::get_module_slug( $file ) ] = $headers['introduced']; } - Jetpack_Options::update_option( 'available_modules', array( - JETPACK__VERSION => $modules, - ) ); + Jetpack_Options::update_option( + 'available_modules', + array( + JETPACK__VERSION => $modules, + ) + ); } } @@ -2325,20 +2315,20 @@ class Jetpack { public static function get_default_modules( $min_version = false, $max_version = false ) { $return = array(); - foreach ( Jetpack::get_available_modules( $min_version, $max_version ) as $module ) { - $module_data = Jetpack::get_module( $module ); + foreach ( self::get_available_modules( $min_version, $max_version ) as $module ) { + $module_data = self::get_module( $module ); switch ( strtolower( $module_data['auto_activate'] ) ) { - case 'yes' : + case 'yes': $return[] = $module; break; - case 'public' : + case 'public': if ( Jetpack_Options::get_option( 'public' ) ) { $return[] = $module; } break; - case 'no' : - default : + case 'no': + default: break; } } @@ -2379,7 +2369,7 @@ class Jetpack { ); // Don't activate SSO if they never completed activating WPCC. - if ( Jetpack::is_module_active( 'wpcc' ) ) { + if ( self::is_module_active( 'wpcc' ) ) { $wpcc_options = Jetpack_Options::get_option( 'wpcc_options' ); if ( empty( $wpcc_options ) || empty( $wpcc_options['client_id'] ) || empty( $wpcc_options['client_id'] ) ) { $deprecated_modules['wpcc'] = null; @@ -2387,7 +2377,7 @@ class Jetpack { } foreach ( $deprecated_modules as $module => $replacement ) { - if ( Jetpack::is_module_active( $module ) ) { + if ( self::is_module_active( $module ) ) { self::deactivate_module( $module ); if ( $replacement ) { $modules[] = $replacement; @@ -2445,7 +2435,15 @@ class Jetpack { * Generate a module's path from its slug. */ public static function get_module_path( $slug ) { - return JETPACK__PLUGIN_DIR . "modules/$slug.php"; + /** + * Filters the path of a modules. + * + * @since 7.4.0 + * + * @param array $return The absolute path to a module's root php file + * @param string $slug The module slug + */ + return apply_filters( 'jetpack_get_module_path', JETPACK__PLUGIN_DIR . "modules/$slug.php", $slug ); } /** @@ -2457,7 +2455,6 @@ class Jetpack { $headers = array( 'name' => 'Module Name', 'description' => 'Module Description', - 'jumpstart_desc' => 'Jumpstart Description', 'sort' => 'Sort Order', 'recommendation_order' => 'Recommendation Order', 'introduced' => 'First Introduced', @@ -2472,18 +2469,18 @@ class Jetpack { 'plan_classes' => 'Plans', ); - $file = Jetpack::get_module_path( Jetpack::get_module_slug( $module ) ); + $file = self::get_module_path( self::get_module_slug( $module ) ); - $mod = Jetpack::get_file_data( $file, $headers ); + $mod = self::get_file_data( $file, $headers ); if ( empty( $mod['name'] ) ) { return false; } - $mod['sort'] = empty( $mod['sort'] ) ? 10 : (int) $mod['sort']; - $mod['recommendation_order'] = empty( $mod['recommendation_order'] ) ? 20 : (int) $mod['recommendation_order']; - $mod['deactivate'] = empty( $mod['deactivate'] ); - $mod['free'] = empty( $mod['free'] ); - $mod['requires_connection'] = ( ! empty( $mod['requires_connection'] ) && 'No' == $mod['requires_connection'] ) ? false : true; + $mod['sort'] = empty( $mod['sort'] ) ? 10 : (int) $mod['sort']; + $mod['recommendation_order'] = empty( $mod['recommendation_order'] ) ? 20 : (int) $mod['recommendation_order']; + $mod['deactivate'] = empty( $mod['deactivate'] ); + $mod['free'] = empty( $mod['free'] ); + $mod['requires_connection'] = ( ! empty( $mod['requires_connection'] ) && 'No' == $mod['requires_connection'] ) ? false : true; if ( empty( $mod['auto_activate'] ) || ! in_array( strtolower( $mod['auto_activate'] ), array( 'yes', 'no', 'public' ) ) ) { $mod['auto_activate'] = 'No'; @@ -2517,12 +2514,11 @@ class Jetpack { * Filters the feature array on a module. * * This filter allows you to control where each module is filtered: Recommended, - * Jumpstart, and the default "Other" listing. + * and the default "Other" listing. * * @since 3.5.0 * * @param array $mod['feature'] The areas to feature this module: - * 'Jumpstart' adds to the "Jumpstart" option to activate many modules at once. * 'Recommended' shows on the main Jetpack admin screen. * 'Other' should be the default if no other value is in the array. * @param string $module The slug of the module, e.g. sharedaddy. @@ -2549,13 +2545,18 @@ class Jetpack { * Like core's get_file_data implementation, but caches the result. */ public static function get_file_data( $file, $headers ) { - //Get just the filename from $file (i.e. exclude full path) so that a consistent hash is generated + // Get just the filename from $file (i.e. exclude full path) so that a consistent hash is generated $file_name = basename( $file ); $cache_key = 'jetpack_file_data_' . JETPACK__VERSION; $file_data_option = get_transient( $cache_key ); + if ( ! is_array( $file_data_option ) ) { + delete_transient( $cache_key ); + $file_data_option = false; + } + if ( false === $file_data_option ) { $file_data_option = array(); } @@ -2641,7 +2642,7 @@ class Jetpack { $script_added = true; wp_add_inline_script( 'wp-i18n', - 'wp.i18n.setLocaleData( ' . Jetpack::get_i18n_data_json() . ', \'jetpack\' );' + 'wp.i18n.setLocaleData( ' . self::get_i18n_data_json() . ', \'jetpack\' );' ); } } @@ -2662,7 +2663,7 @@ class Jetpack { $modules[ $index ]['name'] = $i18n_module['name']; } if ( isset( $module['description'] ) ) { - $modules[ $index ]['description'] = $i18n_module['description']; + $modules[ $index ]['description'] = $i18n_module['description']; $modules[ $index ]['short_description'] = $i18n_module['description']; } } @@ -2685,7 +2686,7 @@ class Jetpack { $active = array_diff( $active, array( 'vaultpress' ) ); } - //If protect is active on the main site of a multisite, it should be active on all sites. + // If protect is active on the main site of a multisite, it should be active on all sites. if ( ! in_array( 'protect', $active ) && is_multisite() && get_site_option( 'jetpack_protect_active' ) ) { $active[] = 'protect'; } @@ -2718,7 +2719,7 @@ class Jetpack { } public static function is_module( $module ) { - return ! empty( $module ) && ! validate_file( $module, Jetpack::get_available_modules() ); + return ! empty( $module ) && ! validate_file( $module, self::get_available_modules() ); } /** @@ -2746,7 +2747,7 @@ class Jetpack { * Saves any generated PHP errors in ::state( 'php_errors', {errors} ) */ public static function catch_errors_on_shutdown() { - Jetpack::state( 'php_errors', self::alias_directories( ob_get_clean() ) ); + self::state( 'php_errors', self::alias_directories( ob_get_clean() ) ); } /** @@ -2771,20 +2772,44 @@ class Jetpack { $min_version = false, $max_version = false, $other_modules = array(), - $redirect = true, - $send_state_messages = true + $redirect = null, + $send_state_messages = null ) { - $jetpack = Jetpack::init(); + $jetpack = self::init(); - $modules = Jetpack::get_default_modules( $min_version, $max_version ); + if ( is_null( $redirect ) ) { + if ( + ( defined( 'REST_REQUEST' ) && REST_REQUEST ) + || + ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) + || + ( defined( 'WP_CLI' ) && WP_CLI ) + || + ( defined( 'DOING_CRON' ) && DOING_CRON ) + || + ( defined( 'DOING_AJAX' ) && DOING_AJAX ) + ) { + $redirect = false; + } elseif ( is_admin() ) { + $redirect = true; + } else { + $redirect = false; + } + } + + if ( is_null( $send_state_messages ) ) { + $send_state_messages = current_user_can( 'jetpack_activate_modules' ); + } + + $modules = self::get_default_modules( $min_version, $max_version ); $modules = array_merge( $other_modules, $modules ); // Look for standalone plugins and disable if active. $to_deactivate = array(); foreach ( $modules as $module ) { - if ( isset( $jetpack->plugins_to_deactivate[$module] ) ) { - $to_deactivate[$module] = $jetpack->plugins_to_deactivate[$module]; + if ( isset( $jetpack->plugins_to_deactivate[ $module ] ) ) { + $to_deactivate[ $module ] = $jetpack->plugins_to_deactivate[ $module ]; } } @@ -2796,18 +2821,22 @@ class Jetpack { } } - if ( $deactivated && $redirect ) { - Jetpack::state( 'deactivated_plugins', join( ',', $deactivated ) ); + if ( $deactivated ) { + if ( $send_state_messages ) { + self::state( 'deactivated_plugins', join( ',', $deactivated ) ); + } - $url = add_query_arg( - array( - 'action' => 'activate_default_modules', - '_wpnonce' => wp_create_nonce( 'activate_default_modules' ), - ), - add_query_arg( compact( 'min_version', 'max_version', 'other_modules' ), Jetpack::admin_url( 'page=jetpack' ) ) - ); - wp_safe_redirect( $url ); - exit; + if ( $redirect ) { + $url = add_query_arg( + array( + 'action' => 'activate_default_modules', + '_wpnonce' => wp_create_nonce( 'activate_default_modules' ), + ), + add_query_arg( compact( 'min_version', 'max_version', 'other_modules' ), self::admin_url( 'page=jetpack' ) ) + ); + wp_safe_redirect( $url ); + exit; + } } /** @@ -2823,11 +2852,11 @@ class Jetpack { // Check each module for fatal errors, a la wp-admin/plugins.php::activate before activating if ( $send_state_messages ) { - Jetpack::restate(); - Jetpack::catch_errors( true ); + self::restate(); + self::catch_errors( true ); } - $active = Jetpack::get_active_modules(); + $active = self::get_active_modules(); foreach ( $modules as $module ) { if ( did_action( "jetpack_module_loaded_$module" ) ) { @@ -2837,33 +2866,33 @@ class Jetpack { } if ( $send_state_messages && in_array( $module, $active ) ) { - $module_info = Jetpack::get_module( $module ); + $module_info = self::get_module( $module ); if ( ! $module_info['deactivate'] ) { $state = in_array( $module, $other_modules ) ? 'reactivated_modules' : 'activated_modules'; - if ( $active_state = Jetpack::state( $state ) ) { + if ( $active_state = self::state( $state ) ) { $active_state = explode( ',', $active_state ); } else { $active_state = array(); } $active_state[] = $module; - Jetpack::state( $state, implode( ',', $active_state ) ); + self::state( $state, implode( ',', $active_state ) ); } continue; } - $file = Jetpack::get_module_path( $module ); + $file = self::get_module_path( $module ); if ( ! file_exists( $file ) ) { continue; } // we'll override this later if the plugin can be included without fatal error if ( $redirect ) { - wp_safe_redirect( Jetpack::admin_url( 'page=jetpack' ) ); + wp_safe_redirect( self::admin_url( 'page=jetpack' ) ); } if ( $send_state_messages ) { - Jetpack::state( 'error', 'module_activation_failed' ); - Jetpack::state( 'module', $module ); + self::state( 'error', 'module_activation_failed' ); + self::state( 'module', $module ); } ob_start(); @@ -2873,27 +2902,27 @@ class Jetpack { if ( $send_state_messages ) { - $state = in_array( $module, $other_modules ) ? 'reactivated_modules' : 'activated_modules'; - if ( $active_state = Jetpack::state( $state ) ) { + $state = in_array( $module, $other_modules ) ? 'reactivated_modules' : 'activated_modules'; + if ( $active_state = self::state( $state ) ) { $active_state = explode( ',', $active_state ); } else { $active_state = array(); } $active_state[] = $module; - Jetpack::state( $state, implode( ',', $active_state ) ); + self::state( $state, implode( ',', $active_state ) ); } - Jetpack::update_active_modules( $active ); + self::update_active_modules( $active ); ob_end_clean(); } if ( $send_state_messages ) { - Jetpack::state( 'error', false ); - Jetpack::state( 'module', false ); + self::state( 'error', false ); + self::state( 'module', false ); } - Jetpack::catch_errors( false ); + self::catch_errors( false ); /** * Fires when default modules are activated. * @@ -2918,30 +2947,36 @@ class Jetpack { */ do_action( 'jetpack_pre_activate_module', $module, $exit, $redirect ); - $jetpack = Jetpack::init(); + $jetpack = self::init(); - if ( ! strlen( $module ) ) + if ( ! strlen( $module ) ) { return false; + } - if ( ! Jetpack::is_module( $module ) ) + if ( ! self::is_module( $module ) ) { return false; + } // If it's already active, then don't do it again - $active = Jetpack::get_active_modules(); + $active = self::get_active_modules(); foreach ( $active as $act ) { - if ( $act == $module ) + if ( $act == $module ) { return true; + } } - $module_data = Jetpack::get_module( $module ); + $module_data = self::get_module( $module ); - if ( ! Jetpack::is_active() ) { - if ( ! Jetpack::is_development_mode() && ! Jetpack::is_onboarding() ) + $is_development_mode = ( new Status() )->is_development_mode(); + if ( ! self::is_active() ) { + if ( ! $is_development_mode && ! self::is_onboarding() ) { return false; + } // If we're not connected but in development mode, make sure the module doesn't require a connection - if ( Jetpack::is_development_mode() && $module_data['requires_connection'] ) + if ( $is_development_mode && $module_data['requires_connection'] ) { return false; + } } // Check and see if the old plugin is active @@ -2950,7 +2985,7 @@ class Jetpack { if ( Jetpack_Client_Server::deactivate_plugin( $jetpack->plugins_to_deactivate[ $module ][0], $jetpack->plugins_to_deactivate[ $module ][1] ) ) { // If we deactivated the old plugin, remembere that with ::state() and redirect back to this page to activate the module // We can't activate the module on this page load since the newly deactivated old plugin is still loaded on this page load. - Jetpack::state( 'deactivated_plugins', $module ); + self::state( 'deactivated_plugins', $module ); wp_safe_redirect( add_query_arg( 'jetpack_restate', 1 ) ); exit; } @@ -2960,7 +2995,7 @@ class Jetpack { if ( 'protect' === $module ) { include_once JETPACK__PLUGIN_DIR . 'modules/protect/shared-functions.php'; if ( ! jetpack_protect_get_ip() ) { - Jetpack::state( 'message', 'protect_misconfigured_ip' ); + self::state( 'message', 'protect_misconfigured_ip' ); return false; } } @@ -2970,23 +3005,23 @@ class Jetpack { } // Check the file for fatal errors, a la wp-admin/plugins.php::activate - Jetpack::state( 'module', $module ); - Jetpack::state( 'error', 'module_activation_failed' ); // we'll override this later if the plugin can be included without fatal error + self::state( 'module', $module ); + self::state( 'error', 'module_activation_failed' ); // we'll override this later if the plugin can be included without fatal error - Jetpack::catch_errors( true ); + self::catch_errors( true ); ob_start(); - require Jetpack::get_module_path( $module ); + require self::get_module_path( $module ); /** This action is documented in class.jetpack.php */ do_action( 'jetpack_activate_module', $module ); $active[] = $module; - Jetpack::update_active_modules( $active ); + self::update_active_modules( $active ); - Jetpack::state( 'error', false ); // the override + self::state( 'error', false ); // the override ob_end_clean(); - Jetpack::catch_errors( false ); + self::catch_errors( false ); if ( $redirect ) { - wp_safe_redirect( Jetpack::admin_url( 'page=jetpack' ) ); + wp_safe_redirect( self::admin_url( 'page=jetpack' ) ); } if ( $exit ) { exit; @@ -3008,16 +3043,16 @@ class Jetpack { */ do_action( 'jetpack_pre_deactivate_module', $module ); - $jetpack = Jetpack::init(); + $jetpack = self::init(); - $active = Jetpack::get_active_modules(); + $active = self::get_active_modules(); $new = array_filter( array_diff( $active, (array) $module ) ); return self::update_active_modules( $new ); } public static function enable_module_configurable( $module ) { - $module = Jetpack::get_module_slug( $module ); + $module = self::get_module_slug( $module ); add_filter( 'jetpack_module_configurable_' . $module, '__return_true' ); } @@ -3029,8 +3064,8 @@ class Jetpack { * @return string $url module configuration URL */ public static function module_configuration_url( $module ) { - $module = Jetpack::get_module_slug( $module ); - $default_url = Jetpack::admin_url() . "#/settings?term=$module"; + $module = self::get_module_slug( $module ); + $default_url = self::admin_url() . "#/settings?term=$module"; /** * Allows to modify configure_url of specific module to be able to redirect to some custom location. * @@ -3043,9 +3078,9 @@ class Jetpack { return $url; } -/* Installation */ + /* Installation */ public static function bail_on_activation( $message, $deactivate = true ) { -?> + ?> <!doctype html> <html> <head> @@ -3066,15 +3101,15 @@ p { <p><?php echo esc_html( $message ); ?></p> </body> </html> -<?php + <?php if ( $deactivate ) { $plugins = get_option( 'active_plugins' ); $jetpack = plugin_basename( JETPACK__PLUGIN_DIR . 'jetpack.php' ); $update = false; foreach ( $plugins as $i => $plugin ) { if ( $plugin === $jetpack ) { - $plugins[$i] = false; - $update = true; + $plugins[ $i ] = false; + $update = true; } } @@ -3087,24 +3122,26 @@ p { /** * Attached to activate_{ plugin_basename( __FILES__ ) } by register_activation_hook() + * * @static */ public static function plugin_activation( $network_wide ) { Jetpack_Options::update_option( 'activated', 1 ); if ( version_compare( $GLOBALS['wp_version'], JETPACK__MINIMUM_WP_VERSION, '<' ) ) { - Jetpack::bail_on_activation( sprintf( __( 'Jetpack requires WordPress version %s or later.', 'jetpack' ), JETPACK__MINIMUM_WP_VERSION ) ); + self::bail_on_activation( sprintf( __( 'Jetpack requires WordPress version %s or later.', 'jetpack' ), JETPACK__MINIMUM_WP_VERSION ) ); } - if ( $network_wide ) - Jetpack::state( 'network_nag', true ); + if ( $network_wide ) { + self::state( 'network_nag', true ); + } // For firing one-off events (notices) immediately after activation set_transient( 'activated_jetpack', true, .1 * MINUTE_IN_SECONDS ); update_option( 'jetpack_activation_source', self::get_activation_source( wp_get_referer() ) ); - Jetpack::plugin_initialize(); + self::plugin_initialize(); } public static function get_activation_source( $referer_url ) { @@ -3113,17 +3150,17 @@ p { return array( 'wp-cli', null ); } - $referer = parse_url( $referer_url ); + $referer = wp_parse_url( $referer_url ); - $source_type = 'unknown'; + $source_type = 'unknown'; $source_query = null; if ( ! is_array( $referer ) ) { return array( $source_type, $source_query ); } - $plugins_path = parse_url( admin_url( 'plugins.php' ), PHP_URL_PATH ); - $plugins_install_path = parse_url( admin_url( 'plugin-install.php' ), PHP_URL_PATH );// /wp-admin/plugin-install.php + $plugins_path = wp_parse_url( admin_url( 'plugins.php' ), PHP_URL_PATH ); + $plugins_install_path = wp_parse_url( admin_url( 'plugin-install.php' ), PHP_URL_PATH );// /wp-admin/plugin-install.php if ( isset( $referer['query'] ) ) { parse_str( $referer['query'], $query_parts ); @@ -3135,7 +3172,7 @@ p { $source_type = 'list'; } elseif ( $plugins_install_path === $referer['path'] ) { $tab = isset( $query_parts['tab'] ) ? $query_parts['tab'] : 'featured'; - switch( $tab ) { + switch ( $tab ) { case 'popular': $source_type = 'popular'; break; @@ -3146,7 +3183,7 @@ p { $source_type = 'favorites'; break; case 'search': - $source_type = 'search-' . ( isset( $query_parts['type'] ) ? $query_parts['type'] : 'term' ); + $source_type = 'search-' . ( isset( $query_parts['type'] ) ? $query_parts['type'] : 'term' ); $source_query = isset( $query_parts['s'] ) ? $query_parts['s'] : null; break; default: @@ -3159,6 +3196,7 @@ p { /** * Runs before bumping version numbers up to a new version + * * @param string $version Version:timestamp * @param string $old_version Old Version:timestamp or false if not set yet. * @return null [description] @@ -3171,6 +3209,7 @@ p { /** * Sets the internal version number and activation state. + * * @static */ public static function plugin_initialize() { @@ -3185,7 +3224,7 @@ p { Jetpack_Options::update_options( compact( 'version', 'old_version' ) ); } - Jetpack::load_modules(); + self::load_modules(); Jetpack_Options::delete_option( 'do_activate' ); Jetpack_Options::delete_option( 'dismissed_connection_banner' ); @@ -3193,49 +3232,41 @@ p { /** * Removes all connection options + * * @static */ - public static function plugin_deactivation( ) { - require_once( ABSPATH . '/wp-admin/includes/plugin.php' ); - if( is_plugin_active_for_network( 'jetpack/jetpack.php' ) ) { + public static function plugin_deactivation() { + require_once ABSPATH . '/wp-admin/includes/plugin.php'; + if ( is_plugin_active_for_network( 'jetpack/jetpack.php' ) ) { Jetpack_Network::init()->deactivate(); } else { - Jetpack::disconnect( false ); - //Jetpack_Heartbeat::init()->deactivate(); + self::disconnect( false ); + // Jetpack_Heartbeat::init()->deactivate(); } } /** * Disconnects from the Jetpack servers. * Forgets all connection details and tells the Jetpack servers to do the same. + * * @static */ public static function disconnect( $update_activated_state = true ) { wp_clear_scheduled_hook( 'jetpack_clean_nonces' ); - Jetpack::clean_nonces( true ); + $connection = self::connection(); + $connection->clean_nonces( true ); // If the site is in an IDC because sync is not allowed, // let's make sure to not disconnect the production site. if ( ! self::validate_sync_error_idc_option() ) { - JetpackTracking::record_user_event( 'disconnect_site', array() ); - Jetpack::load_xml_rpc_client(); - $xml = new Jetpack_IXR_Client(); - $xml->query( 'jetpack.deregister' ); - } + $tracking = new Tracking(); + $tracking->record_user_event( 'disconnect_site', array() ); - Jetpack_Options::delete_option( - array( - 'blog_token', - 'user_token', - 'user_tokens', - 'master_user', - 'time_diff', - 'fallback_no_verify_ssl_certs', - ) - ); + $connection->disconnect_site_wpcom(); + } + $connection->delete_all_connection_tokens(); Jetpack_IDC::clear_all_idc_options(); - Jetpack_Options::delete_raw_option( 'jetpack_secrets' ); if ( $update_activated_state ) { Jetpack_Options::update_option( 'activated', 4 ); @@ -3247,8 +3278,8 @@ p { $jetpack_unique_connection['disconnected'] = 1; } else { if ( 0 == $jetpack_unique_connection['disconnected'] ) { - //track unique disconnect - $jetpack = Jetpack::init(); + // track unique disconnect + $jetpack = self::init(); $jetpack->stat( 'connections', 'unique-disconnect' ); $jetpack->do_stats( 'server_side' ); @@ -3260,76 +3291,53 @@ p { Jetpack_Options::update_option( 'unique_connection', $jetpack_unique_connection ); } - // Delete cached connected user data - $transient_key = "jetpack_connected_user_data_" . get_current_user_id(); - delete_transient( $transient_key ); - // Delete all the sync related data. Since it could be taking up space. - require_once JETPACK__PLUGIN_DIR . 'sync/class.jetpack-sync-sender.php'; - Jetpack_Sync_Sender::get_instance()->uninstall(); + Sender::get_instance()->uninstall(); // Disable the Heartbeat cron Jetpack_Heartbeat::init()->deactivate(); } /** - * Unlinks the current user from the linked WordPress.com user + * Unlinks the current user from the linked WordPress.com user. + * + * @deprecated since 7.7 + * @see Automattic\Jetpack\Connection\Manager::disconnect_user() + * + * @param Integer $user_id the user identifier. + * @return Boolean Whether the disconnection of the user was successful. */ public static function unlink_user( $user_id = null ) { - if ( ! $tokens = Jetpack_Options::get_option( 'user_tokens' ) ) - return false; - - $user_id = empty( $user_id ) ? get_current_user_id() : intval( $user_id ); - - if ( Jetpack_Options::get_option( 'master_user' ) == $user_id ) - return false; - - if ( ! isset( $tokens[ $user_id ] ) ) - return false; - - Jetpack::load_xml_rpc_client(); - $xml = new Jetpack_IXR_Client( compact( 'user_id' ) ); - $xml->query( 'jetpack.unlink_user', $user_id ); - - unset( $tokens[ $user_id ] ); - - Jetpack_Options::update_option( 'user_tokens', $tokens ); - - /** - * Fires after the current user has been unlinked from WordPress.com. - * - * @since 4.1.0 - * - * @param int $user_id The current user's ID. - */ - do_action( 'jetpack_unlinked_user', $user_id ); - - return true; + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::disconnect_user' ); + return Connection_Manager::disconnect_user( $user_id ); } /** * Attempts Jetpack registration. If it fail, a state flag is set: @see ::admin_page_load() */ public static function try_registration() { + $terms_of_service = new Terms_Of_Service(); // The user has agreed to the TOS at some point by now. - Jetpack_Options::update_option( 'tos_agreed', true ); + $terms_of_service->agree(); // Let's get some testing in beta versions and such. if ( self::is_development_version() && defined( 'PHP_URL_HOST' ) ) { // Before attempting to connect, let's make sure that the domains are viable. - $domains_to_check = array_unique( array( - 'siteurl' => parse_url( get_site_url(), PHP_URL_HOST ), - 'homeurl' => parse_url( get_home_url(), PHP_URL_HOST ), - ) ); + $domains_to_check = array_unique( + array( + 'siteurl' => wp_parse_url( get_site_url(), PHP_URL_HOST ), + 'homeurl' => wp_parse_url( get_home_url(), PHP_URL_HOST ), + ) + ); foreach ( $domains_to_check as $domain ) { - $result = Jetpack_Data::is_usable_domain( $domain ); + $result = self::connection()->is_usable_domain( $domain ); if ( is_wp_error( $result ) ) { return $result; } } } - $result = Jetpack::register(); + $result = self::register(); // If there was an error with registration and the site was not registered, record this so we can show a message. if ( ! $result || is_wp_error( $result ) ) { @@ -3373,13 +3381,13 @@ p { * @since 3.0.0 * * @param array $log_entry { - * Array of details about the log entry. + * Array of details about the log entry. * - * @param string time Time of the event. - * @param int user_id ID of the user who trigerred the event. - * @param int blog_id Jetpack Blog ID. - * @param string code Unique name for the event. - * @param string data Data about the event. + * @param string time Time of the event. + * @param int user_id ID of the user who trigerred the event. + * @param int blog_id Jetpack Blog ID. + * @param string code Unique name for the event. + * @param string data Data about the event. * } */ do_action( 'jetpack_log_entry', $log_entry ); @@ -3415,7 +3423,7 @@ p { if ( $event ) { foreach ( $entire_log as $log_event ) { - if ( $event == $log_event[ 'code' ] ) { + if ( $event == $log_event['code'] ) { $custom_log_output[] = $log_event; } } @@ -3434,7 +3442,7 @@ p { * Log modification of important settings. */ public static function log_settings_change( $option, $old_value, $value ) { - switch( $option ) { + switch ( $option ) { case 'jetpack_sync_non_public_post_stati': self::log( $option, $value ); break; @@ -3449,7 +3457,7 @@ p { if ( $extended ) { $additional_data = self::get_additional_stat_data(); - $data = array_merge( $data, $additional_data ); + $data = array_merge( $data, $additional_data ); } if ( $encode ) { @@ -3463,13 +3471,13 @@ p { * Get additional stat data to sync to WPCOM */ public static function get_additional_stat_data( $prefix = '' ) { - $return["{$prefix}themes"] = Jetpack::get_parsed_theme_data(); - $return["{$prefix}plugins-extra"] = Jetpack::get_parsed_plugin_data(); - $return["{$prefix}users"] = (int) Jetpack::get_site_user_count(); - $return["{$prefix}site-count"] = 0; + $return[ "{$prefix}themes" ] = self::get_parsed_theme_data(); + $return[ "{$prefix}plugins-extra" ] = self::get_parsed_plugin_data(); + $return[ "{$prefix}users" ] = (int) self::get_site_user_count(); + $return[ "{$prefix}site-count" ] = 0; if ( function_exists( 'get_blog_count' ) ) { - $return["{$prefix}site-count"] = get_blog_count(); + $return[ "{$prefix}site-count" ] = get_blog_count(); } return $return; } @@ -3501,17 +3509,19 @@ p { // the plugin is active, but was never activated. Probably came from a site-wide network activation ! Jetpack_Options::get_option( 'activated' ) ) { - Jetpack::plugin_initialize(); + self::plugin_initialize(); } - if ( ! Jetpack::is_active() && ! Jetpack::is_development_mode() ) { + $is_development_mode = ( new Status() )->is_development_mode(); + if ( ! self::is_active() && ! $is_development_mode ) { Jetpack_Connection_Banner::init(); } elseif ( false === Jetpack_Options::get_option( 'fallback_no_verify_ssl_certs' ) ) { // Upgrade: 1.1 -> 1.1.1 // Check and see if host can verify the Jetpack servers' SSL certificate - $args = array(); - Jetpack_Client::_wp_remote_request( - Jetpack::fix_url_for_bad_hosts( Jetpack::api_url( 'test' ) ), + $args = array(); + $connection = self::connection(); + Client::_wp_remote_request( + Connection_Utils::fix_url_for_bad_hosts( $connection->api_url( 'test' ) ), $args, true ); @@ -3525,15 +3535,15 @@ p { add_action( 'admin_enqueue_scripts', array( $this, 'admin_menu_css' ) ); add_filter( 'plugin_action_links_' . plugin_basename( JETPACK__PLUGIN_DIR . 'jetpack.php' ), array( $this, 'plugin_action_links' ) ); - if ( Jetpack::is_active() || Jetpack::is_development_mode() ) { + if ( self::is_active() || $is_development_mode ) { // Artificially throw errors in certain whitelisted cases during plugin activation add_action( 'activate_plugin', array( $this, 'throw_error_on_activate_plugin' ) ); } // Add custom column in wp-admin/users.php to show whether user is linked. - add_filter( 'manage_users_columns', array( $this, 'jetpack_icon_user_connected' ) ); + add_filter( 'manage_users_columns', array( $this, 'jetpack_icon_user_connected' ) ); add_action( 'manage_users_custom_column', array( $this, 'jetpack_show_user_connected_icon' ), 10, 3 ); - add_action( 'admin_print_styles', array( $this, 'jetpack_user_col_style' ) ); + add_action( 'admin_print_styles', array( $this, 'jetpack_user_col_style' ) ); } function admin_body_class( $admin_body_class = '' ) { @@ -3556,7 +3566,7 @@ p { * @param string $plugin The activated plugin. */ function throw_error_on_activate_plugin( $plugin ) { - $active_modules = Jetpack::get_active_modules(); + $active_modules = self::get_active_modules(); // The Shortlinks module and the Stats plugin conflict, but won't cause errors on activation because of some function_exists() checks. if ( function_exists( 'stats_get_api_key' ) && in_array( 'shortlinks', $active_modules ) ) { @@ -3591,30 +3601,61 @@ p { foreach ( $this->plugins_to_deactivate as $deactivate_me ) { if ( "plugin-activation-error_{$deactivate_me[0]}" == $action ) { - Jetpack::bail_on_activation( sprintf( __( 'Jetpack contains the most recent version of the old “%1$s” plugin.', 'jetpack' ), $deactivate_me[1] ), false ); + self::bail_on_activation( sprintf( __( 'Jetpack contains the most recent version of the old “%1$s” plugin.', 'jetpack' ), $deactivate_me[1] ), false ); } } } - function add_remote_request_handlers() { - add_action( 'wp_ajax_nopriv_jetpack_upload_file', array( $this, 'remote_request_handlers' ) ); - add_action( 'wp_ajax_nopriv_jetpack_update_file', array( $this, 'remote_request_handlers' ) ); + /** + * Register the remote file upload request handlers, if needed. + * + * @access public + */ + public function add_remote_request_handlers() { + // Remote file uploads are allowed only via AJAX requests. + if ( ! is_admin() || ! Constants::get_constant( 'DOING_AJAX' ) ) { + return; + } + + // Remote file uploads are allowed only for a set of specific AJAX actions. + $remote_request_actions = array( + 'jetpack_upload_file', + 'jetpack_update_file', + ); + + // phpcs:ignore WordPress.Security.NonceVerification + if ( ! isset( $_POST['action'] ) || ! in_array( $_POST['action'], $remote_request_actions, true ) ) { + return; + } + + // Require Jetpack authentication for the remote file upload AJAX requests. + $this->connection_manager->require_jetpack_authentication(); + + // Register the remote file upload AJAX handlers. + foreach ( $remote_request_actions as $action ) { + add_action( "wp_ajax_nopriv_{$action}", array( $this, 'remote_request_handlers' ) ); + } } - function remote_request_handlers() { + /** + * Handler for Jetpack remote file uploads. + * + * @access public + */ + public function remote_request_handlers() { $action = current_filter(); switch ( current_filter() ) { - case 'wp_ajax_nopriv_jetpack_upload_file' : - $response = $this->upload_handler(); - break; + case 'wp_ajax_nopriv_jetpack_upload_file': + $response = $this->upload_handler(); + break; - case 'wp_ajax_nopriv_jetpack_update_file' : - $response = $this->upload_handler( true ); - break; - default : - $response = new Jetpack_Error( 'unknown_handler', 'Unknown Handler', 400 ); - break; + case 'wp_ajax_nopriv_jetpack_update_file': + $response = $this->upload_handler( true ); + break; + default: + $response = new Jetpack_Error( 'unknown_handler', 'Unknown Handler', 400 ); + break; } if ( ! $response ) { @@ -3672,7 +3713,7 @@ p { } foreach ( array_keys( $_FILES ) as $files_key ) { - if ( ! isset( $_POST["_jetpack_file_hmac_{$files_key}"] ) ) { + if ( ! isset( $_POST[ "_jetpack_file_hmac_{$files_key}" ] ) ) { return new Jetpack_Error( 'missing_hmac', 'An HMAC for one or more files is missing', 400 ); } } @@ -3690,19 +3731,22 @@ p { foreach ( $_FILES['media']['name'] as $index => $name ) { $file = array(); foreach ( $media_keys as $media_key ) { - $file[$media_key] = $_FILES['media'][$media_key][$index]; + $file[ $media_key ] = $_FILES['media'][ $media_key ][ $index ]; } - list( $hmac_provided, $salt ) = explode( ':', $_POST['_jetpack_file_hmac_media'][$index] ); + list( $hmac_provided, $salt ) = explode( ':', $_POST['_jetpack_file_hmac_media'][ $index ] ); $hmac_file = hash_hmac_file( 'sha1', $file['tmp_name'], $salt . $token->secret ); if ( $hmac_provided !== $hmac_file ) { - $uploaded_files[$index] = (object) array( 'error' => 'invalid_hmac', 'error_description' => 'The corresponding HMAC for this file does not match' ); + $uploaded_files[ $index ] = (object) array( + 'error' => 'invalid_hmac', + 'error_description' => 'The corresponding HMAC for this file does not match', + ); continue; } $_FILES['.jetpack.upload.'] = $file; - $post_id = isset( $_POST['post_id'][$index] ) ? absint( $_POST['post_id'][$index] ) : 0; + $post_id = isset( $_POST['post_id'][ $index ] ) ? absint( $_POST['post_id'][ $index ] ) : 0; if ( ! current_user_can( 'edit_post', $post_id ) ) { $post_id = 0; } @@ -3714,11 +3758,11 @@ p { $media_array = $_FILES['media']; - $file_array['name'] = $media_array['name'][0]; - $file_array['type'] = $media_array['type'][0]; + $file_array['name'] = $media_array['name'][0]; + $file_array['type'] = $media_array['type'][0]; $file_array['tmp_name'] = $media_array['tmp_name'][0]; - $file_array['error'] = $media_array['error'][0]; - $file_array['size'] = $media_array['size'][0]; + $file_array['error'] = $media_array['error'][0]; + $file_array['size'] = $media_array['size'][0]; $edited_media_item = Jetpack_Media::edit_media_file( $post_id, $file_array ); @@ -3747,12 +3791,18 @@ p { ); if ( ! $attachment_id ) { - $uploaded_files[$index] = (object) array( 'error' => 'unknown', 'error_description' => 'An unknown problem occurred processing the upload on the Jetpack site' ); + $uploaded_files[ $index ] = (object) array( + 'error' => 'unknown', + 'error_description' => 'An unknown problem occurred processing the upload on the Jetpack site', + ); } elseif ( is_wp_error( $attachment_id ) ) { - $uploaded_files[$index] = (object) array( 'error' => 'attachment_' . $attachment_id->get_error_code(), 'error_description' => $attachment_id->get_error_message() ); + $uploaded_files[ $index ] = (object) array( + 'error' => 'attachment_' . $attachment_id->get_error_code(), + 'error_description' => $attachment_id->get_error_message(), + ); } else { - $attachment = get_post( $attachment_id ); - $uploaded_files[$index] = (object) array( + $attachment = get_post( $attachment_id ); + $uploaded_files[ $index ] = (object) array( 'id' => (string) $attachment_id, 'file' => $attachment->post_title, 'url' => wp_get_attachment_url( $attachment_id ), @@ -3786,9 +3836,9 @@ p { // Overview $current_screen->add_help_tab( array( - 'id' => 'home', - 'title' => __( 'Home', 'jetpack' ), - 'content' => + 'id' => 'home', + 'title' => __( 'Home', 'jetpack' ), + 'content' => '<p><strong>' . __( 'Jetpack by WordPress.com', 'jetpack' ) . '</strong></p>' . '<p>' . __( 'Jetpack supercharges your self-hosted WordPress site with the awesome cloud power of WordPress.com.', 'jetpack' ) . '</p>' . '<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>', @@ -3799,16 +3849,16 @@ p { if ( current_user_can( 'manage_options' ) ) { $current_screen->add_help_tab( array( - 'id' => 'settings', - 'title' => __( 'Settings', 'jetpack' ), - 'content' => - '<p><strong>' . __( 'Jetpack by WordPress.com', 'jetpack' ) . '</strong></p>' . + 'id' => 'settings', + 'title' => __( 'Settings', 'jetpack' ), + 'content' => + '<p><strong>' . __( 'Jetpack by WordPress.com', 'jetpack' ) . '</strong></p>' . '<p>' . __( 'You can activate or deactivate individual Jetpack modules to suit your needs.', 'jetpack' ) . '</p>' . '<ol>' . - '<li>' . __( 'Each module has an Activate or Deactivate link so you can toggle one individually.', 'jetpack' ) . '</li>' . - '<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>' . + '<li>' . __( 'Each module has an Activate or Deactivate link so you can toggle one individually.', 'jetpack' ) . '</li>' . + '<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>' . '</ol>' . - '<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>' + '<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>', ) ); } @@ -3816,9 +3866,9 @@ p { // Help Sidebar $current_screen->set_help_sidebar( '<p><strong>' . __( 'For more information:', 'jetpack' ) . '</strong></p>' . - '<p><a href="https://jetpack.com/faq/" target="_blank">' . __( 'Jetpack FAQ', 'jetpack' ) . '</a></p>' . + '<p><a href="https://jetpack.com/faq/" target="_blank">' . __( 'Jetpack FAQ', 'jetpack' ) . '</a></p>' . '<p><a href="https://jetpack.com/support/" target="_blank">' . __( 'Jetpack Support', 'jetpack' ) . '</a></p>' . - '<p><a href="' . Jetpack::admin_url( array( 'page' => 'jetpack-debugger' ) ) .'">' . __( 'Jetpack Debugging Center', 'jetpack' ) . '</a></p>' + '<p><a href="' . self::admin_url( array( 'page' => 'jetpack-debugger' ) ) . '">' . __( 'Jetpack Debugging Center', 'jetpack' ) . '</a></p>' ); } @@ -3852,7 +3902,7 @@ p { if ( ! wp_style_is( 'jetpack-dops-style' ) ) { wp_register_style( 'jetpack-dops-style', - plugins_url( '_inc/build/admin.dops-style.css', JETPACK__PLUGIN_FILE ), + plugins_url( '_inc/build/admin.css', JETPACK__PLUGIN_FILE ), array(), JETPACK__VERSION ); @@ -3862,7 +3912,7 @@ p { 'jetpack', plugins_url( "css/jetpack-banners{$min}.css", JETPACK__PLUGIN_FILE ), array( 'jetpack-dops-style' ), - JETPACK__VERSION . '-20121016' + JETPACK__VERSION . '-20121016' ); wp_style_add_data( 'jetpack', 'rtl', 'replace' ); wp_style_add_data( 'jetpack', 'suffix', $min ); @@ -3870,16 +3920,16 @@ p { function plugin_action_links( $actions ) { - $jetpack_home = array( 'jetpack-home' => sprintf( '<a href="%s">%s</a>', Jetpack::admin_url( 'page=jetpack' ), 'Jetpack' ) ); + $jetpack_home = array( 'jetpack-home' => sprintf( '<a href="%s">%s</a>', self::admin_url( 'page=jetpack' ), 'Jetpack' ) ); - if( current_user_can( 'jetpack_manage_modules' ) && ( Jetpack::is_active() || Jetpack::is_development_mode() ) ) { + if ( current_user_can( 'jetpack_manage_modules' ) && ( self::is_active() || ( new Status() )->is_development_mode() ) ) { return array_merge( $jetpack_home, - array( 'settings' => sprintf( '<a href="%s">%s</a>', Jetpack::admin_url( 'page=jetpack#/settings' ), __( 'Settings', 'jetpack' ) ) ), - array( 'support' => sprintf( '<a href="%s">%s</a>', Jetpack::admin_url( 'page=jetpack-debugger '), __( 'Support', 'jetpack' ) ) ), + array( 'settings' => sprintf( '<a href="%s">%s</a>', self::admin_url( 'page=jetpack#/settings' ), __( 'Settings', 'jetpack' ) ) ), + array( 'support' => sprintf( '<a href="%s">%s</a>', self::admin_url( 'page=jetpack-debugger ' ), __( 'Support', 'jetpack' ) ) ), $actions - ); - } + ); + } return array_merge( $jetpack_home, $actions ); } @@ -3901,12 +3951,12 @@ p { * 4 - redirect to https://wordpress.com/start/jetpack-connect * 5 - user logs in with WP.com account * 6 - remote request to this site's xmlrpc.php with action remoteAuthorize, Jetpack_XMLRPC_Server->remote_authorize - * - Jetpack_Client_Server::authorize() - * - Jetpack_Client_Server::get_token() + * - Manager::authorize() + * - Manager::get_token() * - GET https://jetpack.wordpress.com/jetpack.token/1/ with * client_id, client_secret, grant_type, code, redirect_uri:action=authorize, state, scope, user_email, user_login * - which responds with access_token, token_type, scope - * - Jetpack_Client_Server::authorize() stores jetpack_options: user_token => access_token.$user_id + * - Manager::authorize() stores jetpack_options: user_token => access_token.$user_id * - Jetpack::activate_default_modules() * - Deactivates deprecated plugins * - Activates all default modules @@ -3923,34 +3973,36 @@ p { $error = false; // Make sure we have the right body class to hook stylings for subpages off of. - add_filter( 'admin_body_class', array( __CLASS__, 'add_jetpack_pagestyles' ) ); + add_filter( 'admin_body_class', array( __CLASS__, 'add_jetpack_pagestyles' ), 20 ); if ( ! empty( $_GET['jetpack_restate'] ) ) { // Should only be used in intermediate redirects to preserve state across redirects - Jetpack::restate(); + self::restate(); } if ( isset( $_GET['connect_url_redirect'] ) ) { + // @todo: Add validation against a known whitelist + $from = ! empty( $_GET['from'] ) ? $_GET['from'] : 'iframe'; // User clicked in the iframe to link their accounts - if ( ! Jetpack::is_user_connected() ) { - $from = ! empty( $_GET['from'] ) ? $_GET['from'] : 'iframe'; + if ( ! self::is_user_connected() ) { $redirect = ! empty( $_GET['redirect_after_auth'] ) ? $_GET['redirect_after_auth'] : false; add_filter( 'allowed_redirect_hosts', array( &$this, 'allow_wpcom_environments' ) ); $connect_url = $this->build_connect_url( true, $redirect, $from ); remove_filter( 'allowed_redirect_hosts', array( &$this, 'allow_wpcom_environments' ) ); - if ( isset( $_GET['notes_iframe'] ) ) + if ( isset( $_GET['notes_iframe'] ) ) { $connect_url .= '¬es_iframe'; + } wp_redirect( $connect_url ); exit; } else { if ( ! isset( $_GET['calypso_env'] ) ) { - Jetpack::state( 'message', 'already_authorized' ); - wp_safe_redirect( Jetpack::admin_url() ); + self::state( 'message', 'already_authorized' ); + wp_safe_redirect( self::admin_url() ); exit; } else { - $connect_url = $this->build_connect_url( true, false, 'iframe' ); + $connect_url = $this->build_connect_url( true, false, $from ); $connect_url .= '&already_authorized=true'; wp_redirect( $connect_url ); exit; @@ -3958,196 +4010,206 @@ p { } } - if ( isset( $_GET['action'] ) ) { switch ( $_GET['action'] ) { - case 'authorize': - if ( Jetpack::is_active() && Jetpack::is_user_connected() ) { - Jetpack::state( 'message', 'already_authorized' ); - wp_safe_redirect( Jetpack::admin_url() ); + case 'authorize': + if ( self::is_active() && self::is_user_connected() ) { + self::state( 'message', 'already_authorized' ); + wp_safe_redirect( self::admin_url() ); + exit; + } + self::log( 'authorize' ); + $client_server = new Jetpack_Client_Server(); + $client_server->client_authorize(); exit; - } - Jetpack::log( 'authorize' ); - $client_server = new Jetpack_Client_Server; - $client_server->client_authorize(); - exit; - case 'register' : - if ( ! current_user_can( 'jetpack_connect' ) ) { - $error = 'cheatin'; - break; - } - check_admin_referer( 'jetpack-register' ); - Jetpack::log( 'register' ); - Jetpack::maybe_set_version_option(); - $registered = Jetpack::try_registration(); - if ( is_wp_error( $registered ) ) { - $error = $registered->get_error_code(); - Jetpack::state( 'error', $error ); - Jetpack::state( 'error', $registered->get_error_message() ); - JetpackTracking::record_user_event( 'jpc_register_fail', array( - 'error_code' => $error, - 'error_message' => $registered->get_error_message() - ) ); - break; - } - - $from = isset( $_GET['from'] ) ? $_GET['from'] : false; - $redirect = isset( $_GET['redirect'] ) ? $_GET['redirect'] : false; + case 'register': + if ( ! current_user_can( 'jetpack_connect' ) ) { + $error = 'cheatin'; + break; + } + check_admin_referer( 'jetpack-register' ); + self::log( 'register' ); + self::maybe_set_version_option(); + $registered = self::try_registration(); + if ( is_wp_error( $registered ) ) { + $error = $registered->get_error_code(); + self::state( 'error', $error ); + self::state( 'error', $registered->get_error_message() ); - JetpackTracking::record_user_event( 'jpc_register_success', array( - 'from' => $from - ) ); + /** + * Jetpack registration Error. + * + * @since 7.5.0 + * + * @param string|int $error The error code. + * @param \WP_Error $registered The error object. + */ + do_action( 'jetpack_connection_register_fail', $error, $registered ); + break; + } - $url = $this->build_connect_url( true, $redirect, $from ); + $from = isset( $_GET['from'] ) ? $_GET['from'] : false; + $redirect = isset( $_GET['redirect'] ) ? $_GET['redirect'] : false; - if ( ! empty( $_GET['onboarding'] ) ) { - $url = add_query_arg( 'onboarding', $_GET['onboarding'], $url ); - } + /** + * Jetpack registration Success. + * + * @since 7.5.0 + * + * @param string $from 'from' GET parameter; + */ + do_action( 'jetpack_connection_register_success', $from ); - if ( ! empty( $_GET['auth_approved'] ) && 'true' === $_GET['auth_approved'] ) { - $url = add_query_arg( 'auth_approved', 'true', $url ); - } + $url = $this->build_connect_url( true, $redirect, $from ); - wp_redirect( $url ); - exit; - case 'activate' : - if ( ! current_user_can( 'jetpack_activate_modules' ) ) { - $error = 'cheatin'; - break; - } + if ( ! empty( $_GET['onboarding'] ) ) { + $url = add_query_arg( 'onboarding', $_GET['onboarding'], $url ); + } - $module = stripslashes( $_GET['module'] ); - check_admin_referer( "jetpack_activate-$module" ); - Jetpack::log( 'activate', $module ); - if ( ! Jetpack::activate_module( $module ) ) { - Jetpack::state( 'error', sprintf( __( 'Could not activate %s', 'jetpack' ), $module ) ); - } - // The following two lines will rarely happen, as Jetpack::activate_module normally exits at the end. - wp_safe_redirect( Jetpack::admin_url( 'page=jetpack' ) ); - exit; - case 'activate_default_modules' : - check_admin_referer( 'activate_default_modules' ); - Jetpack::log( 'activate_default_modules' ); - Jetpack::restate(); - $min_version = isset( $_GET['min_version'] ) ? $_GET['min_version'] : false; - $max_version = isset( $_GET['max_version'] ) ? $_GET['max_version'] : false; - $other_modules = isset( $_GET['other_modules'] ) && is_array( $_GET['other_modules'] ) ? $_GET['other_modules'] : array(); - Jetpack::activate_default_modules( $min_version, $max_version, $other_modules ); - wp_safe_redirect( Jetpack::admin_url( 'page=jetpack' ) ); - exit; - case 'disconnect' : - if ( ! current_user_can( 'jetpack_disconnect' ) ) { - $error = 'cheatin'; - break; - } + if ( ! empty( $_GET['auth_approved'] ) && 'true' === $_GET['auth_approved'] ) { + $url = add_query_arg( 'auth_approved', 'true', $url ); + } - check_admin_referer( 'jetpack-disconnect' ); - Jetpack::log( 'disconnect' ); - Jetpack::disconnect(); - wp_safe_redirect( Jetpack::admin_url( 'disconnected=true' ) ); - exit; - case 'reconnect' : - if ( ! current_user_can( 'jetpack_reconnect' ) ) { - $error = 'cheatin'; - break; - } + wp_redirect( $url ); + exit; + case 'activate': + if ( ! current_user_can( 'jetpack_activate_modules' ) ) { + $error = 'cheatin'; + break; + } - check_admin_referer( 'jetpack-reconnect' ); - Jetpack::log( 'reconnect' ); - $this->disconnect(); - wp_redirect( $this->build_connect_url( true, false, 'reconnect' ) ); - exit; - case 'deactivate' : - if ( ! current_user_can( 'jetpack_deactivate_modules' ) ) { - $error = 'cheatin'; - break; - } + $module = stripslashes( $_GET['module'] ); + check_admin_referer( "jetpack_activate-$module" ); + self::log( 'activate', $module ); + if ( ! self::activate_module( $module ) ) { + self::state( 'error', sprintf( __( 'Could not activate %s', 'jetpack' ), $module ) ); + } + // The following two lines will rarely happen, as Jetpack::activate_module normally exits at the end. + wp_safe_redirect( self::admin_url( 'page=jetpack' ) ); + exit; + case 'activate_default_modules': + check_admin_referer( 'activate_default_modules' ); + self::log( 'activate_default_modules' ); + self::restate(); + $min_version = isset( $_GET['min_version'] ) ? $_GET['min_version'] : false; + $max_version = isset( $_GET['max_version'] ) ? $_GET['max_version'] : false; + $other_modules = isset( $_GET['other_modules'] ) && is_array( $_GET['other_modules'] ) ? $_GET['other_modules'] : array(); + self::activate_default_modules( $min_version, $max_version, $other_modules ); + wp_safe_redirect( self::admin_url( 'page=jetpack' ) ); + exit; + case 'disconnect': + if ( ! current_user_can( 'jetpack_disconnect' ) ) { + $error = 'cheatin'; + break; + } - $modules = stripslashes( $_GET['module'] ); - check_admin_referer( "jetpack_deactivate-$modules" ); - foreach ( explode( ',', $modules ) as $module ) { - Jetpack::log( 'deactivate', $module ); - Jetpack::deactivate_module( $module ); - Jetpack::state( 'message', 'module_deactivated' ); - } - Jetpack::state( 'module', $modules ); - wp_safe_redirect( Jetpack::admin_url( 'page=jetpack' ) ); - exit; - case 'unlink' : - $redirect = isset( $_GET['redirect'] ) ? $_GET['redirect'] : ''; - check_admin_referer( 'jetpack-unlink' ); - Jetpack::log( 'unlink' ); - $this->unlink_user(); - Jetpack::state( 'message', 'unlinked' ); - if ( 'sub-unlink' == $redirect ) { - wp_safe_redirect( admin_url() ); - } else { - wp_safe_redirect( Jetpack::admin_url( array( 'page' => $redirect ) ) ); - } - exit; - case 'onboard' : - if ( ! current_user_can( 'manage_options' ) ) { - wp_safe_redirect( Jetpack::admin_url( 'page=jetpack' ) ); - } else { - Jetpack::create_onboarding_token(); - $url = $this->build_connect_url( true ); + check_admin_referer( 'jetpack-disconnect' ); + self::log( 'disconnect' ); + self::disconnect(); + wp_safe_redirect( self::admin_url( 'disconnected=true' ) ); + exit; + case 'reconnect': + if ( ! current_user_can( 'jetpack_reconnect' ) ) { + $error = 'cheatin'; + break; + } - if ( false !== ( $token = Jetpack_Options::get_option( 'onboarding' ) ) ) { - $url = add_query_arg( 'onboarding', $token, $url ); + check_admin_referer( 'jetpack-reconnect' ); + self::log( 'reconnect' ); + $this->disconnect(); + wp_redirect( $this->build_connect_url( true, false, 'reconnect' ) ); + exit; + case 'deactivate': + if ( ! current_user_can( 'jetpack_deactivate_modules' ) ) { + $error = 'cheatin'; + break; } - $calypso_env = ! empty( $_GET[ 'calypso_env' ] ) ? $_GET[ 'calypso_env' ] : false; - if ( $calypso_env ) { - $url = add_query_arg( 'calypso_env', $calypso_env, $url ); + $modules = stripslashes( $_GET['module'] ); + check_admin_referer( "jetpack_deactivate-$modules" ); + foreach ( explode( ',', $modules ) as $module ) { + self::log( 'deactivate', $module ); + self::deactivate_module( $module ); + self::state( 'message', 'module_deactivated' ); + } + self::state( 'module', $modules ); + wp_safe_redirect( self::admin_url( 'page=jetpack' ) ); + exit; + case 'unlink': + $redirect = isset( $_GET['redirect'] ) ? $_GET['redirect'] : ''; + check_admin_referer( 'jetpack-unlink' ); + self::log( 'unlink' ); + Connection_Manager::disconnect_user(); + self::state( 'message', 'unlinked' ); + if ( 'sub-unlink' == $redirect ) { + wp_safe_redirect( admin_url() ); + } else { + wp_safe_redirect( self::admin_url( array( 'page' => $redirect ) ) ); } + exit; + case 'onboard': + if ( ! current_user_can( 'manage_options' ) ) { + wp_safe_redirect( self::admin_url( 'page=jetpack' ) ); + } else { + self::create_onboarding_token(); + $url = $this->build_connect_url( true ); - wp_redirect( $url ); + if ( false !== ( $token = Jetpack_Options::get_option( 'onboarding' ) ) ) { + $url = add_query_arg( 'onboarding', $token, $url ); + } + + $calypso_env = $this->get_calypso_env(); + if ( ! empty( $calypso_env ) ) { + $url = add_query_arg( 'calypso_env', $calypso_env, $url ); + } + + wp_redirect( $url ); + exit; + } exit; - } - exit; - default: - /** - * Fires when a Jetpack admin page is loaded with an unrecognized parameter. - * - * @since 2.6.0 - * - * @param string sanitize_key( $_GET['action'] ) Unrecognized URL parameter. - */ - do_action( 'jetpack_unrecognized_action', sanitize_key( $_GET['action'] ) ); + default: + /** + * Fires when a Jetpack admin page is loaded with an unrecognized parameter. + * + * @since 2.6.0 + * + * @param string sanitize_key( $_GET['action'] ) Unrecognized URL parameter. + */ + do_action( 'jetpack_unrecognized_action', sanitize_key( $_GET['action'] ) ); } } - if ( ! $error = $error ? $error : Jetpack::state( 'error' ) ) { + if ( ! $error = $error ? $error : self::state( 'error' ) ) { self::activate_new_modules( true ); } - $message_code = Jetpack::state( 'message' ); - if ( Jetpack::state( 'optin-manage' ) ) { + $message_code = self::state( 'message' ); + if ( self::state( 'optin-manage' ) ) { $activated_manage = $message_code; - $message_code = 'jetpack-manage'; + $message_code = 'jetpack-manage'; } switch ( $message_code ) { - case 'jetpack-manage': - $this->message = '<strong>' . sprintf( __( 'You are all set! Your site can now be managed from <a href="%s" target="_blank">wordpress.com/sites</a>.', 'jetpack' ), 'https://wordpress.com/sites' ) . '</strong>'; - if ( $activated_manage ) { - $this->message .= '<br /><strong>' . __( 'Manage has been activated for you!', 'jetpack' ) . '</strong>'; - } - break; + case 'jetpack-manage': + $this->message = '<strong>' . sprintf( __( 'You are all set! Your site can now be managed from <a href="%s" target="_blank">wordpress.com/sites</a>.', 'jetpack' ), 'https://wordpress.com/sites' ) . '</strong>'; + if ( $activated_manage ) { + $this->message .= '<br /><strong>' . __( 'Manage has been activated for you!', 'jetpack' ) . '</strong>'; + } + break; } - $deactivated_plugins = Jetpack::state( 'deactivated_plugins' ); + $deactivated_plugins = self::state( 'deactivated_plugins' ); if ( ! empty( $deactivated_plugins ) ) { $deactivated_plugins = explode( ',', $deactivated_plugins ); $deactivated_titles = array(); foreach ( $deactivated_plugins as $deactivated_plugin ) { - if ( ! isset( $this->plugins_to_deactivate[$deactivated_plugin] ) ) { + if ( ! isset( $this->plugins_to_deactivate[ $deactivated_plugin ] ) ) { continue; } - $deactivated_titles[] = '<strong>' . str_replace( ' ', ' ', $this->plugins_to_deactivate[$deactivated_plugin][1] ) . '</strong>'; + $deactivated_titles[] = '<strong>' . str_replace( ' ', ' ', $this->plugins_to_deactivate[ $deactivated_plugin ][1] ) . '</strong>'; } if ( $deactivated_titles ) { @@ -4176,7 +4238,7 @@ p { } } - $this->privacy_checks = Jetpack::state( 'privacy_checks' ); + $this->privacy_checks = self::state( 'privacy_checks' ); if ( $this->message || $this->error || $this->privacy_checks ) { add_action( 'jetpack_notices', array( $this, 'admin_notices' ) ); @@ -4188,26 +4250,51 @@ p { function admin_notices() { if ( $this->error ) { -?> + ?> <div id="message" class="jetpack-message jetpack-err"> <div class="squeezer"> - <h2><?php echo wp_kses( $this->error, array( 'a' => array( 'href' => array() ), 'small' => true, 'code' => true, 'strong' => true, 'br' => true, 'b' => true ) ); ?></h2> -<?php if ( $desc = Jetpack::state( 'error_description' ) ) : ?> + <h2> + <?php + echo wp_kses( + $this->error, + array( + 'a' => array( 'href' => array() ), + 'small' => true, + 'code' => true, + 'strong' => true, + 'br' => true, + 'b' => true, + ) + ); + ?> + </h2> + <?php if ( $desc = self::state( 'error_description' ) ) : ?> <p><?php echo esc_html( stripslashes( $desc ) ); ?></p> <?php endif; ?> </div> </div> -<?php + <?php } if ( $this->message ) { -?> + ?> <div id="message" class="jetpack-message"> <div class="squeezer"> - <h2><?php echo wp_kses( $this->message, array( 'strong' => array(), 'a' => array( 'href' => true ), 'br' => true ) ); ?></h2> + <h2> + <?php + echo wp_kses( + $this->message, + array( + 'strong' => array(), + 'a' => array( 'href' => true ), + 'br' => true, + ) + ); + ?> + </h2> </div> </div> -<?php + <?php } if ( $this->privacy_checks ) : @@ -4216,7 +4303,7 @@ p { $privacy_checks = explode( ',', $this->privacy_checks ); $privacy_checks = array_filter( $privacy_checks, array( 'Jetpack', 'is_module' ) ); foreach ( $privacy_checks as $module_slug ) { - $module = Jetpack::get_module( $module_slug ); + $module = self::get_module( $module_slug ); if ( ! $module ) { continue; } @@ -4226,11 +4313,12 @@ p { } $module_slugs = join( ',', $module_slugs ); -?> + ?> <div id="message" class="jetpack-message jetpack-err"> <div class="squeezer"> <h2><strong><?php esc_html_e( 'Is this site private?', 'jetpack' ); ?></strong></h2><br /> - <p><?php + <p> + <?php echo wp_kses( wptexturize( wp_sprintf( @@ -4259,7 +4347,7 @@ p { 'jetpack' ), wp_nonce_url( - Jetpack::admin_url( + self::admin_url( array( 'page' => 'jetpack', 'action' => 'deactivate', @@ -4270,20 +4358,57 @@ p { ), esc_attr( wp_kses( wp_sprintf( _x( 'Deactivate %l', '%l = list of Jetpack module/feature names', 'jetpack' ), $module_names ), array() ) ) ), - array( 'a' => array( 'href' => true, 'title' => true ) ) + array( + 'a' => array( + 'href' => true, + 'title' => true, + ), + ) ); - ?></p> + ?> + </p> </div> </div> -<?php endif; + <?php +endif; + } + + /** + * We can't always respond to a signed XML-RPC request with a + * helpful error message. In some circumstances, doing so could + * leak information. + * + * Instead, track that the error occurred via a Jetpack_Option, + * and send that data back in the heartbeat. + * All this does is increment a number, but it's enough to find + * trends. + * + * @param WP_Error $xmlrpc_error The error produced during + * signature validation. + */ + function track_xmlrpc_error( $xmlrpc_error ) { + $code = is_wp_error( $xmlrpc_error ) + ? $xmlrpc_error->get_error_code() + : 'should-not-happen'; + + $xmlrpc_errors = Jetpack_Options::get_option( 'xmlrpc_errors', array() ); + if ( isset( $xmlrpc_errors[ $code ] ) && $xmlrpc_errors[ $code ] ) { + // No need to update the option if we already have + // this code stored. + return; + } + $xmlrpc_errors[ $code ] = true; + + Jetpack_Options::update_option( 'xmlrpc_errors', $xmlrpc_errors, false ); } /** * Record a stat for later output. This will only currently output in the admin_footer. */ function stat( $group, $detail ) { - if ( ! isset( $this->stats[ $group ] ) ) + if ( ! isset( $this->stats[ $group ] ) ) { $this->stats[ $group ] = array(); + } $this->stats[ $group ][] = $detail; } @@ -4315,11 +4440,13 @@ p { */ static function do_server_side_stat( $args ) { $response = wp_remote_get( esc_url_raw( self::build_stats_url( $args ) ) ); - if ( is_wp_error( $response ) ) + if ( is_wp_error( $response ) ) { return false; + } - if ( 200 !== wp_remote_retrieve_response_code( $response ) ) + if ( 200 !== wp_remote_retrieve_response_code( $response ) ) { return false; + } return true; } @@ -4352,71 +4479,97 @@ p { return $url; } - static function translate_current_user_to_role() { - foreach ( self::$capability_translations as $role => $cap ) { - if ( current_user_can( $role ) || current_user_can( $cap ) ) { - return $role; - } - } + /** + * Get the role of the current user. + * + * @deprecated 7.6 Use Automattic\Jetpack\Roles::translate_current_user_to_role() instead. + * + * @access public + * @static + * + * @return string|boolean Current user's role, false if not enough capabilities for any of the roles. + */ + public static function translate_current_user_to_role() { + _deprecated_function( __METHOD__, 'jetpack-7.6.0' ); - return false; + $roles = new Roles(); + return $roles->translate_current_user_to_role(); } - static function translate_user_to_role( $user ) { - foreach ( self::$capability_translations as $role => $cap ) { - if ( user_can( $user, $role ) || user_can( $user, $cap ) ) { - return $role; - } - } - - return false; - } - - static function translate_role_to_cap( $role ) { - if ( ! isset( self::$capability_translations[$role] ) ) { - return false; - } + /** + * Get the role of a particular user. + * + * @deprecated 7.6 Use Automattic\Jetpack\Roles::translate_user_to_role() instead. + * + * @access public + * @static + * + * @param \WP_User $user User object. + * @return string|boolean User's role, false if not enough capabilities for any of the roles. + */ + public static function translate_user_to_role( $user ) { + _deprecated_function( __METHOD__, 'jetpack-7.6.0' ); - return self::$capability_translations[$role]; + $roles = new Roles(); + return $roles->translate_user_to_role( $user ); } - static function sign_role( $role, $user_id = null ) { - if ( empty( $user_id ) ) { - $user_id = (int) get_current_user_id(); - } - - if ( ! $user_id ) { - return false; - } - - $token = Jetpack_Data::get_access_token(); - if ( ! $token || is_wp_error( $token ) ) { - return false; - } + /** + * Get the minimum capability for a role. + * + * @deprecated 7.6 Use Automattic\Jetpack\Roles::translate_role_to_cap() instead. + * + * @access public + * @static + * + * @param string $role Role name. + * @return string|boolean Capability, false if role isn't mapped to any capabilities. + */ + public static function translate_role_to_cap( $role ) { + _deprecated_function( __METHOD__, 'jetpack-7.6.0' ); - return $role . ':' . hash_hmac( 'md5', "{$role}|{$user_id}", $token->secret ); + $roles = new Roles(); + return $roles->translate_role_to_cap( $role ); } + /** + * Sign a user role with the master access token. + * If not specified, will default to the current user. + * + * @deprecated since 7.7 + * @see Automattic\Jetpack\Connection\Manager::sign_role() + * + * @access public + * @static + * + * @param string $role User role. + * @param int $user_id ID of the user. + * @return string Signed user role. + */ + public static function sign_role( $role, $user_id = null ) { + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::sign_role' ); + return self::connection()->sign_role( $role, $user_id ); + } /** * Builds a URL to the Jetpack connection auth page * * @since 3.9.5 * - * @param bool $raw If true, URL will not be escaped. + * @param bool $raw If true, URL will not be escaped. * @param bool|string $redirect If true, will redirect back to Jetpack wp-admin landing page after connection. * If string, will be a custom redirect. * @param bool|string $from If not false, adds 'from=$from' param to the connect URL. - * @param bool $register If true, will generate a register URL regardless of the existing token, since 4.9.0 + * @param bool $register If true, will generate a register URL regardless of the existing token, since 4.9.0 * * @return string Connect URL */ function build_connect_url( $raw = false, $redirect = false, $from = false, $register = false ) { - $site_id = Jetpack_Options::get_option( 'id' ); - $token = Jetpack_Options::get_option( 'blog_token' ); + $site_id = Jetpack_Options::get_option( 'id' ); + $blog_token = Jetpack_Data::get_access_token(); - if ( $register || ! $token || ! $site_id ) { - $url = Jetpack::nonce_url_no_esc( Jetpack::admin_url( 'action=register' ), 'jetpack-register' ); + if ( $register || ! $blog_token || ! $site_id ) { + $url = self::nonce_url_no_esc( self::admin_url( 'action=register' ), 'jetpack-register' ); if ( ! empty( $redirect ) ) { $url = add_query_arg( @@ -4426,9 +4579,15 @@ p { ); } - if( is_network_admin() ) { + if ( is_network_admin() ) { $url = add_query_arg( 'is_multisite', network_admin_url( 'admin.php?page=jetpack-settings' ), $url ); } + + $calypso_env = self::get_calypso_env(); + + if ( ! empty( $calypso_env ) ) { + $url = add_query_arg( 'calypso_env', $calypso_env, $url ); + } } else { // Let's check the existing blog token to see if we need to re-register. We only check once per minute @@ -4437,103 +4596,210 @@ p { if ( ! $last_connect_url_check || ( time() - $last_connect_url_check ) > MINUTE_IN_SECONDS ) { Jetpack_Options::update_raw_option( 'jetpack_last_connect_url_check', time() ); - $response = Jetpack_Client::wpcom_json_api_request_as_blog( - sprintf( '/sites/%d', $site_id ) .'?force=wpcom', + $response = Client::wpcom_json_api_request_as_blog( + sprintf( '/sites/%d', $site_id ) . '?force=wpcom', '1.1' ); if ( 200 !== wp_remote_retrieve_response_code( $response ) ) { + // Generating a register URL instead to refresh the existing token return $this->build_connect_url( $raw, $redirect, $from, true ); } } - if ( defined( 'JETPACK__GLOTPRESS_LOCALES_PATH' ) && include_once JETPACK__GLOTPRESS_LOCALES_PATH ) { - $gp_locale = GP_Locales::by_field( 'wp_locale', get_locale() ); - } + $url = $this->build_authorize_url( $redirect ); + } - $role = self::translate_current_user_to_role(); - $signed_role = self::sign_role( $role ); + if ( $from ) { + $url = add_query_arg( 'from', $from, $url ); + } + + // Ensure that class to get the affiliate code is loaded + if ( ! class_exists( 'Jetpack_Affiliate' ) ) { + require_once JETPACK__PLUGIN_DIR . 'class.jetpack-affiliate.php'; + } + // Get affiliate code and add it to the URL + $url = Jetpack_Affiliate::init()->add_code_as_query_arg( $url ); - $user = wp_get_current_user(); + return $raw ? esc_url_raw( $url ) : esc_url( $url ); + } - $jetpack_admin_page = esc_url_raw( admin_url( 'admin.php?page=jetpack' ) ); - $redirect = $redirect - ? wp_validate_redirect( esc_url_raw( $redirect ), $jetpack_admin_page ) - : $jetpack_admin_page; + public static function build_authorize_url( $redirect = false, $iframe = false ) { - if( isset( $_REQUEST['is_multisite'] ) ) { - $redirect = Jetpack_Network::init()->get_url( 'network_admin_page' ); - } + add_filter( 'jetpack_connect_request_body', array( __CLASS__, 'filter_connect_request_body' ) ); + add_filter( 'jetpack_connect_redirect_url', array( __CLASS__, 'filter_connect_redirect_url' ) ); + add_filter( 'jetpack_connect_processing_url', array( __CLASS__, 'filter_connect_processing_url' ) ); - $secrets = Jetpack::generate_secrets( 'authorize', false, 2 * HOUR_IN_SECONDS ); + if ( $iframe ) { + add_filter( 'jetpack_api_url', array( __CLASS__, 'filter_connect_api_iframe_url' ), 10, 2 ); + } - /** - * Filter the type of authorization. - * 'calypso' completes authorization on wordpress.com/jetpack/connect - * while 'jetpack' ( or any other value ) completes the authorization at jetpack.wordpress.com. - * - * @since 4.3.3 - * - * @param string $auth_type Defaults to 'calypso', can also be 'jetpack'. - */ - $auth_type = apply_filters( 'jetpack_auth_type', 'calypso' ); + $c8n = self::connection(); + $url = $c8n->get_authorization_url( wp_get_current_user(), $redirect ); - $tracks_identity = jetpack_tracks_get_identity( get_current_user_id() ); + remove_filter( 'jetpack_connect_request_body', array( __CLASS__, 'filter_connect_request_body' ) ); + remove_filter( 'jetpack_connect_redirect_url', array( __CLASS__, 'filter_connect_redirect_url' ) ); + remove_filter( 'jetpack_connect_processing_url', array( __CLASS__, 'filter_connect_processing_url' ) ); - $args = urlencode_deep( - array( - 'response_type' => 'code', - 'client_id' => Jetpack_Options::get_option( 'id' ), - 'redirect_uri' => add_query_arg( - array( - 'action' => 'authorize', - '_wpnonce' => wp_create_nonce( "jetpack-authorize_{$role}_{$redirect}" ), - 'redirect' => urlencode( $redirect ), - ), - esc_url( admin_url( 'admin.php?page=jetpack' ) ) - ), - 'state' => $user->ID, - 'scope' => $signed_role, - 'user_email' => $user->user_email, - 'user_login' => $user->user_login, - 'is_active' => Jetpack::is_active(), - 'jp_version' => JETPACK__VERSION, - 'auth_type' => $auth_type, - 'secret' => $secrets['secret_1'], - 'locale' => ( isset( $gp_locale ) && isset( $gp_locale->slug ) ) ? $gp_locale->slug : '', - 'blogname' => get_option( 'blogname' ), - 'site_url' => site_url(), - 'home_url' => home_url(), - 'site_icon' => get_site_icon_url(), - 'site_lang' => get_locale(), - '_ui' => $tracks_identity['_ui'], - '_ut' => $tracks_identity['_ut'], - 'site_created' => Jetpack::get_assumed_site_creation_date(), - ) - ); + if ( $iframe ) { + remove_filter( 'jetpack_api_url', array( __CLASS__, 'filter_connect_api_iframe_url' ) ); + } - self::apply_activation_source_to_args( $args ); + return $url; + } - $url = add_query_arg( $args, Jetpack::api_url( 'authorize' ) ); + /** + * Filters the connection URL parameter array. + * + * @param Array $args default URL parameters used by the package. + * @return Array the modified URL arguments array. + */ + public static function filter_connect_request_body( $args ) { + if ( + Constants::is_defined( 'JETPACK__GLOTPRESS_LOCALES_PATH' ) + && include_once Constants::get_constant( 'JETPACK__GLOTPRESS_LOCALES_PATH' ) + ) { + $gp_locale = GP_Locales::by_field( 'wp_locale', get_locale() ); + $args['locale'] = isset( $gp_locale ) && isset( $gp_locale->slug ) + ? $gp_locale->slug + : ''; } - if ( $from ) { - $url = add_query_arg( 'from', $from, $url ); + $tracking = new Tracking(); + $tracks_identity = $tracking->tracks_get_identity( $args['state'] ); + + $args = array_merge( + $args, + array( + '_ui' => $tracks_identity['_ui'], + '_ut' => $tracks_identity['_ut'], + ) + ); + + $calypso_env = self::get_calypso_env(); + + if ( ! empty( $calypso_env ) ) { + $args['calypso_env'] = $calypso_env; } - // Ensure that class to get the affiliate code is loaded - if ( ! class_exists( 'Jetpack_Affiliate' ) ) { - require_once JETPACK__PLUGIN_DIR . 'class.jetpack-affiliate.php'; + return $args; + } + + /** + * Filters the URL that will process the connection data. It can be different from the URL + * that we send the user to after everything is done. + * + * @param String $processing_url the default redirect URL used by the package. + * @return String the modified URL. + */ + public static function filter_connect_processing_url( $processing_url ) { + $processing_url = admin_url( 'admin.php?page=jetpack' ); // Making PHPCS happy. + return $processing_url; + } + + /** + * Filters the redirection URL that is used for connect requests. The redirect + * URL should return the user back to the Jetpack console. + * + * @param String $redirect the default redirect URL used by the package. + * @return String the modified URL. + */ + public static function filter_connect_redirect_url( $redirect ) { + $jetpack_admin_page = esc_url_raw( admin_url( 'admin.php?page=jetpack' ) ); + $redirect = $redirect + ? wp_validate_redirect( esc_url_raw( $redirect ), $jetpack_admin_page ) + : $jetpack_admin_page; + + if ( isset( $_REQUEST['is_multisite'] ) ) { + $redirect = Jetpack_Network::init()->get_url( 'network_admin_page' ); } - // Get affiliate code and add it to the URL - $url = Jetpack_Affiliate::init()->add_code_as_query_arg( $url ); - if ( isset( $_GET['calypso_env'] ) ) { - $url = add_query_arg( 'calypso_env', sanitize_key( $_GET['calypso_env'] ), $url ); + return $redirect; + } + + /** + * Filters the API URL that is used for connect requests. The method + * intercepts only the authorize URL and replaces it with another if needed. + * + * @param String $api_url the default redirect API URL used by the package. + * @param String $relative_url the path of the URL that's being used. + * @return String the modified URL. + */ + public static function filter_connect_api_iframe_url( $api_url, $relative_url ) { + + // Short-circuit on anything that is not related to connect requests. + if ( 'authorize' !== $relative_url ) { + return $api_url; } - return $raw ? $url : esc_url( $url ); + $c8n = self::connection(); + + return $c8n->api_url( 'authorize_iframe' ); + } + + /** + * This action fires at the beginning of the Manager::authorize method. + */ + public static function authorize_starting() { + $jetpack_unique_connection = Jetpack_Options::get_option( 'unique_connection' ); + // Checking if site has been active/connected previously before recording unique connection. + if ( ! $jetpack_unique_connection ) { + // jetpack_unique_connection option has never been set. + $jetpack_unique_connection = array( + 'connected' => 0, + 'disconnected' => 0, + 'version' => '3.6.1', + ); + + update_option( 'jetpack_unique_connection', $jetpack_unique_connection ); + + // Track unique connection. + $jetpack = self::init(); + + $jetpack->stat( 'connections', 'unique-connection' ); + $jetpack->do_stats( 'server_side' ); + } + + // Increment number of times connected. + $jetpack_unique_connection['connected'] += 1; + Jetpack_Options::update_option( 'unique_connection', $jetpack_unique_connection ); + } + + /** + * This action fires at the end of the Manager::authorize method when a secondary user is + * linked. + */ + public static function authorize_ending_linked() { + // Don't activate anything since we are just connecting a user. + self::state( 'message', 'linked' ); + } + + /** + * This action fires at the end of the Manager::authorize method when the master user is + * authorized. + * + * @param array $data The request data. + */ + public static function authorize_ending_authorized( $data ) { + // If this site has been through the Jetpack Onboarding flow, delete the onboarding token. + self::invalidate_onboarding_token(); + + // If redirect_uri is SSO, ensure SSO module is enabled. + parse_str( wp_parse_url( $data['redirect_uri'], PHP_URL_QUERY ), $redirect_options ); + + /** This filter is documented in class.jetpack-cli.php */ + $jetpack_start_enable_sso = apply_filters( 'jetpack_start_enable_sso', true ); + + $activate_sso = ( + isset( $redirect_options['action'] ) && + 'jetpack-sso' === $redirect_options['action'] && + $jetpack_start_enable_sso + ); + + $do_redirect_on_error = ( 'client' === $data['auth_type'] ); + + self::handle_post_authorization_actions( $activate_sso, $do_redirect_on_error ); } /** @@ -4543,35 +4809,13 @@ p { * - Earliest date of post of any post type. * * @since 7.2.0 + * @deprecated since 7.8.0 * * @return string Assumed site creation date and time. */ public static function get_assumed_site_creation_date() { - $earliest_registered_users = get_users( array( - 'role' => 'administrator', - 'orderby' => 'user_registered', - 'order' => 'ASC', - 'fields' => array( 'user_registered' ), - 'number' => 1, - ) ); - $earliest_registration_date = $earliest_registered_users[0]->user_registered; - - $earliest_posts = get_posts( array( - 'posts_per_page' => 1, - 'post_type' => 'any', - 'post_status' => 'any', - 'orderby' => 'date', - 'order' => 'ASC', - ) ); - - // If there are no posts at all, we'll count only on user registration date. - if ( $earliest_posts ) { - $earliest_post_date = $earliest_posts[0]->post_date; - } else { - $earliest_post_date = PHP_INT_MAX; - } - - return min( $earliest_registration_date, $earliest_post_date ); + _deprecated_function( __METHOD__, 'jetpack-7.8', 'Automattic\\Jetpack\\Connection\\Manager' ); + return self::connection()->get_assumed_site_creation_date(); } public static function apply_activation_source_to_args( &$args ) { @@ -4587,13 +4831,13 @@ p { } function build_reconnect_url( $raw = false ) { - $url = wp_nonce_url( Jetpack::admin_url( 'action=reconnect' ), 'jetpack-reconnect' ); + $url = wp_nonce_url( self::admin_url( 'action=reconnect' ), 'jetpack-reconnect' ); return $raw ? $url : esc_url( $url ); } public static function admin_url( $args = null ) { $args = wp_parse_args( $args, array( 'page' => 'jetpack' ) ); - $url = add_query_arg( $args, admin_url( 'admin.php' ) ); + $url = add_query_arg( $args, admin_url( 'admin.php' ) ); return $url; } @@ -4608,7 +4852,7 @@ p { return; } - switch( $_GET['jetpack-notice'] ) { + switch ( $_GET['jetpack-notice'] ) { case 'dismiss': if ( check_admin_referer( 'jetpack-deactivate' ) && ! is_plugin_active_for_network( plugin_basename( JETPACK__PLUGIN_DIR . 'jetpack.php' ) ) ) { @@ -4617,69 +4861,96 @@ p { wp_safe_redirect( admin_url() . 'plugins.php?deactivate=true&plugin_status=all&paged=1&s=' ); } break; - case 'jetpack-protect-multisite-opt-out': - - if ( check_admin_referer( 'jetpack_protect_multisite_banner_opt_out' ) ) { - // Don't show the banner again - - update_site_option( 'jetpack_dismissed_protect_multisite_banner', true ); - // redirect back to the page that had the notice - if ( wp_get_referer() ) { - wp_safe_redirect( wp_get_referer() ); - } else { - // Take me to Jetpack - wp_safe_redirect( admin_url( 'admin.php?page=jetpack' ) ); - } - } - break; } } public static function sort_modules( $a, $b ) { - if ( $a['sort'] == $b['sort'] ) + if ( $a['sort'] == $b['sort'] ) { return 0; + } return ( $a['sort'] < $b['sort'] ) ? -1 : 1; } function ajax_recheck_ssl() { check_ajax_referer( 'recheck-ssl', 'ajax-nonce' ); - $result = Jetpack::permit_ssl( true ); - wp_send_json( array( - 'enabled' => $result, - 'message' => get_transient( 'jetpack_https_test_message' ) - ) ); + $result = self::permit_ssl( true ); + wp_send_json( + array( + 'enabled' => $result, + 'message' => get_transient( 'jetpack_https_test_message' ), + ) + ); } -/* Client API */ + /* Client API */ /** * Returns the requested Jetpack API URL * + * @deprecated since 7.7 * @return string */ public static function api_url( $relative_url ) { - return trailingslashit( JETPACK__API_BASE . $relative_url ) . JETPACK__API_VERSION . '/'; + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::api_url' ); + $connection = self::connection(); + return $connection->api_url( $relative_url ); } /** + * @deprecated 8.0 Use Automattic\Jetpack\Connection\Utils::fix_url_for_bad_hosts() instead. + * * Some hosts disable the OpenSSL extension and so cannot make outgoing HTTPS requsets */ public static function fix_url_for_bad_hosts( $url ) { - if ( 0 !== strpos( $url, 'https://' ) ) { - return $url; - } + _deprecated_function( __METHOD__, 'jetpack-8.0', 'Automattic\\Jetpack\\Connection\\Utils::fix_url_for_bad_hosts' ); + return Connection_Utils::fix_url_for_bad_hosts( $url ); + } - switch ( JETPACK_CLIENT__HTTPS ) { - case 'ALWAYS' : - return $url; - case 'NEVER' : - return set_url_scheme( $url, 'http' ); - // default : case 'AUTO' : + public static function verify_onboarding_token( $token_data, $token, $request_data ) { + // Default to a blog token. + $token_type = 'blog'; + + // Let's see if this is onboarding. In such case, use user token type and the provided user id. + if ( isset( $request_data ) || ! empty( $_GET['onboarding'] ) ) { + if ( ! empty( $_GET['onboarding'] ) ) { + $jpo = $_GET; + } else { + $jpo = json_decode( $request_data, true ); + } + + $jpo_token = ! empty( $jpo['onboarding']['token'] ) ? $jpo['onboarding']['token'] : null; + $jpo_user = ! empty( $jpo['onboarding']['jpUser'] ) ? $jpo['onboarding']['jpUser'] : null; + + if ( + isset( $jpo_user ) + && isset( $jpo_token ) + && is_email( $jpo_user ) + && ctype_alnum( $jpo_token ) + && isset( $_GET['rest_route'] ) + && self::validate_onboarding_token_action( + $jpo_token, + $_GET['rest_route'] + ) + ) { + $jp_user = get_user_by( 'email', $jpo_user ); + if ( is_a( $jp_user, 'WP_User' ) ) { + wp_set_current_user( $jp_user->ID ); + $user_can = is_multisite() + ? current_user_can_for_blog( get_current_blog_id(), 'manage_options' ) + : current_user_can( 'manage_options' ); + if ( $user_can ) { + $token_type = 'user'; + $token->external_user_id = $jp_user->ID; + } + } + } + + $token_data['type'] = $token_type; + $token_data['user_id'] = $token->external_user_id; } - // we now return the unmodified SSL URL by default, as a security precaution - return $url; + return $token_data; } /** @@ -4744,7 +5015,7 @@ p { } else { switch ( JETPACK_CLIENT__HTTPS ) { case 'NEVER': - $ssl = 0; + $ssl = 0; $message = __( 'JETPACK_CLIENT__HTTPS is set to NEVER', 'jetpack' ); break; case 'ALWAYS': @@ -4757,15 +5028,15 @@ p { // If it's not 'NEVER', test to see if ( $ssl ) { if ( ! wp_http_supports( array( 'ssl' => true ) ) ) { - $ssl = 0; + $ssl = 0; $message = __( 'WordPress reports no SSL support', 'jetpack' ); } else { $response = wp_remote_get( JETPACK__API_BASE . 'test/1/' ); if ( is_wp_error( $response ) ) { - $ssl = 0; + $ssl = 0; $message = __( 'WordPress reports no SSL support', 'jetpack' ); } elseif ( 'OK' !== wp_remote_retrieve_body( $response ) ) { - $ssl = 0; + $ssl = 0; $message = __( 'Response was not OK: ', 'jetpack' ) . wp_remote_retrieve_body( $response ); } } @@ -4782,8 +5053,9 @@ p { * Displays an admin_notice, alerting the user to their JETPACK_CLIENT__HTTPS constant being 'AUTO' but SSL isn't working. */ public function alert_auto_ssl_fail() { - if ( ! current_user_can( 'manage_options' ) ) + if ( ! current_user_can( 'manage_options' ) ) { return; + } $ajax_nonce = wp_create_nonce( 'recheck-ssl' ); ?> @@ -4798,9 +5070,13 @@ p { <span id="jetpack-recheck-ssl-output"><?php echo get_transient( 'jetpack_https_test_message' ); ?></span> </p> <p> - <?php printf( __( 'For more help, try our <a href="%1$s">connection debugger</a> or <a href="%2$s" target="_blank">troubleshooting tips</a>.', 'jetpack' ), - esc_url( Jetpack::admin_url( array( 'page' => 'jetpack-debugger' ) ) ), - esc_url( 'https://jetpack.com/support/getting-started-with-jetpack/troubleshooting-tips/' ) ); ?> + <?php + printf( + __( 'For more help, try our <a href="%1$s">connection debugger</a> or <a href="%2$s" target="_blank">troubleshooting tips</a>.', 'jetpack' ), + esc_url( self::admin_url( array( 'page' => 'jetpack-debugger' ) ) ), + esc_url( 'https://jetpack.com/support/getting-started-with-jetpack/troubleshooting-tips/' ) + ); + ?> </p> </div> </div> @@ -4817,12 +5093,12 @@ p { var data = { action: 'jetpack-recheck-ssl', 'ajax-nonce': '<?php echo $ajax_nonce; ?>' }; $.post( ajaxurl, data ) .done( function( response ) { - if ( response.enabled ) { - $( '#jetpack-ssl-warning' ).hide(); - } else { - this.html( <?php echo json_encode( __( 'Try again', 'jetpack' ) ); ?> ); - $( '#jetpack-recheck-ssl-output' ).html( 'SSL Failed: ' + response.message ); - } + if ( response.enabled ) { + $( '#jetpack-ssl-warning' ).hide(); + } else { + this.html( <?php echo json_encode( __( 'Try again', 'jetpack' ) ); ?> ); + $( '#jetpack-recheck-ssl-output' ).html( 'SSL Failed: ' + response.message ); + } }.bind( $this ) ); } ); } ); @@ -4834,11 +5110,16 @@ p { /** * Returns the Jetpack XML-RPC API * + * @deprecated 8.0 Use Connection_Manager instead. * @return string */ public static function xmlrpc_api_url() { - $base = preg_replace( '#(https?://[^?/]+)(/?.*)?$#', '\\1', JETPACK__API_BASE ); - return untrailingslashit( $base ) . '/xmlrpc.php'; + _deprecated_function( __METHOD__, 'jetpack-8.0', 'Automattic\\Jetpack\\Connection\\Manager::xmlrpc_api_url()' ); + return self::connection()->xmlrpc_api_url(); + } + + public static function connection() { + return self::init()->connection_manager; } /** @@ -4847,58 +5128,37 @@ p { * Note these tokens are unique per call, NOT static per site for connecting. * * @since 2.6 + * @param String $action The action name. + * @param Integer $user_id The user identifier. + * @param Integer $exp Expiration time in seconds. * @return array */ public static function generate_secrets( $action, $user_id = false, $exp = 600 ) { - if ( ! $user_id ) { - $user_id = get_current_user_id(); - } - - $secret_name = 'jetpack_' . $action . '_' . $user_id; - $secrets = Jetpack_Options::get_raw_option( 'jetpack_secrets', array() ); - - if ( - isset( $secrets[ $secret_name ] ) && - $secrets[ $secret_name ]['exp'] > time() - ) { - return $secrets[ $secret_name ]; - } - - $secret_value = array( - 'secret_1' => wp_generate_password( 32, false ), - 'secret_2' => wp_generate_password( 32, false ), - 'exp' => time() + $exp, - ); - - $secrets[ $secret_name ] = $secret_value; - - Jetpack_Options::update_raw_option( 'jetpack_secrets', $secrets ); - return $secrets[ $secret_name ]; + return self::connection()->generate_secrets( $action, $user_id, $exp ); } public static function get_secrets( $action, $user_id ) { - $secret_name = 'jetpack_' . $action . '_' . $user_id; - $secrets = Jetpack_Options::get_raw_option( 'jetpack_secrets', array() ); + $secrets = self::connection()->get_secrets( $action, $user_id ); - if ( ! isset( $secrets[ $secret_name ] ) ) { + if ( Connection_Manager::SECRETS_MISSING === $secrets ) { return new WP_Error( 'verify_secrets_missing', 'Verification secrets not found' ); } - if ( $secrets[ $secret_name ]['exp'] < time() ) { - self::delete_secrets( $action, $user_id ); + if ( Connection_Manager::SECRETS_EXPIRED === $secrets ) { return new WP_Error( 'verify_secrets_expired', 'Verification took too long' ); } - return $secrets[ $secret_name ]; + return $secrets; } + /** + * @deprecated 7.5 Use Connection_Manager instead. + * + * @param $action + * @param $user_id + */ public static function delete_secrets( $action, $user_id ) { - $secret_name = 'jetpack_' . $action . '_' . $user_id; - $secrets = Jetpack_Options::get_raw_option( 'jetpack_secrets', array() ); - if ( isset( $secrets[ $secret_name ] ) ) { - unset( $secrets[ $secret_name ] ); - Jetpack_Options::update_raw_option( 'jetpack_secrets', $secrets ); - } + return self::connection()->delete_secrets( $action, $user_id ); } /** @@ -4912,7 +5172,7 @@ p { **/ public function get_remote_query_timeout_limit() { _deprecated_function( __METHOD__, 'jetpack-5.4' ); - return Jetpack::get_max_execution_time(); + return self::get_max_execution_time(); } /** @@ -4947,161 +5207,75 @@ p { return $timeout; } - /** * Takes the response from the Jetpack register new site endpoint and * verifies it worked properly. * * @since 2.6 - * @return string|Jetpack_Error A JSON object on success or Jetpack_Error on failures + * @deprecated since 7.7.0 + * @see Automattic\Jetpack\Connection\Manager::validate_remote_register_response() **/ - public function validate_remote_register_response( $response ) { - if ( is_wp_error( $response ) ) { - return new Jetpack_Error( 'register_http_request_failed', $response->get_error_message() ); - } - - $code = wp_remote_retrieve_response_code( $response ); - $entity = wp_remote_retrieve_body( $response ); - if ( $entity ) - $registration_response = json_decode( $entity ); - else - $registration_response = false; - - $code_type = intval( $code / 100 ); - if ( 5 == $code_type ) { - return new Jetpack_Error( 'wpcom_5??', sprintf( __( 'Error Details: %s', 'jetpack' ), $code ), $code ); - } elseif ( 408 == $code ) { - return new Jetpack_Error( 'wpcom_408', sprintf( __( 'Error Details: %s', 'jetpack' ), $code ), $code ); - } elseif ( ! empty( $registration_response->error ) ) { - if ( 'xml_rpc-32700' == $registration_response->error && ! function_exists( 'xml_parser_create' ) ) { - $error_description = __( "PHP's XML extension is not available. Jetpack requires the XML extension to communicate with WordPress.com. Please contact your hosting provider to enable PHP's XML extension.", 'jetpack' ); - } else { - $error_description = isset( $registration_response->error_description ) ? sprintf( __( 'Error Details: %s', 'jetpack' ), (string) $registration_response->error_description ) : ''; - } - - return new Jetpack_Error( (string) $registration_response->error, $error_description, $code ); - } elseif ( 200 != $code ) { - return new Jetpack_Error( 'wpcom_bad_response', sprintf( __( 'Error Details: %s', 'jetpack' ), $code ), $code ); - } - - // Jetpack ID error block - if ( empty( $registration_response->jetpack_id ) ) { - return new Jetpack_Error( 'jetpack_id', sprintf( __( 'Error Details: Jetpack ID is empty. Do not publicly post this error message! %s', 'jetpack' ), $entity ), $entity ); - } elseif ( ! is_scalar( $registration_response->jetpack_id ) ) { - return new Jetpack_Error( 'jetpack_id', sprintf( __( 'Error Details: Jetpack ID is not a scalar. Do not publicly post this error message! %s', 'jetpack' ) , $entity ), $entity ); - } elseif ( preg_match( '/[^0-9]/', $registration_response->jetpack_id ) ) { - return new Jetpack_Error( 'jetpack_id', sprintf( __( 'Error Details: Jetpack ID begins with a numeral. Do not publicly post this error message! %s', 'jetpack' ) , $entity ), $entity ); - } - - return $registration_response; + public function validate_remote_register_response() { + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::validate_remote_register_response' ); } + /** * @return bool|WP_Error */ public static function register() { - JetpackTracking::record_user_event( 'jpc_register_begin' ); - add_action( 'pre_update_jetpack_option_register', array( 'Jetpack_Options', 'delete_option' ) ); - $secrets = Jetpack::generate_secrets( 'register' ); + $tracking = new Tracking(); + $tracking->record_user_event( 'jpc_register_begin' ); - if ( - empty( $secrets['secret_1'] ) || - empty( $secrets['secret_2'] ) || - empty( $secrets['exp'] ) - ) { - return new Jetpack_Error( 'missing_secrets' ); - } - - // better to try (and fail) to set a higher timeout than this system - // supports than to have register fail for more users than it should - $timeout = Jetpack::set_min_time_limit( 60 ) / 2; - - $gmt_offset = get_option( 'gmt_offset' ); - if ( ! $gmt_offset ) { - $gmt_offset = 0; - } - - $stats_options = get_option( 'stats_options' ); - $stats_id = isset($stats_options['blog_id']) ? $stats_options['blog_id'] : null; - - $tracks_identity = jetpack_tracks_get_identity( get_current_user_id() ); - - $args = array( - 'method' => 'POST', - 'body' => array( - 'siteurl' => site_url(), - 'home' => home_url(), - 'gmt_offset' => $gmt_offset, - 'timezone_string' => (string) get_option( 'timezone_string' ), - 'site_name' => (string) get_option( 'blogname' ), - 'secret_1' => $secrets['secret_1'], - 'secret_2' => $secrets['secret_2'], - 'site_lang' => get_locale(), - 'timeout' => $timeout, - 'stats_id' => $stats_id, - 'state' => get_current_user_id(), - '_ui' => $tracks_identity['_ui'], - '_ut' => $tracks_identity['_ut'], - 'site_created' => Jetpack::get_assumed_site_creation_date(), - 'jetpack_version' => JETPACK__VERSION - ), - 'headers' => array( - 'Accept' => 'application/json', - ), - 'timeout' => $timeout, - ); + add_filter( 'jetpack_register_request_body', array( __CLASS__, 'filter_register_request_body' ) ); - self::apply_activation_source_to_args( $args['body'] ); + $connection = self::connection(); + $registration = $connection->register(); - $response = Jetpack_Client::_wp_remote_request( Jetpack::fix_url_for_bad_hosts( Jetpack::api_url( 'register' ) ), $args, true ); + remove_filter( 'jetpack_register_request_body', array( __CLASS__, 'filter_register_request_body' ) ); - // Make sure the response is valid and does not contain any Jetpack errors - $registration_details = Jetpack::init()->validate_remote_register_response( $response ); - if ( is_wp_error( $registration_details ) ) { - return $registration_details; - } elseif ( ! $registration_details ) { - return new Jetpack_Error( 'unknown_error', __( 'Unknown error registering your Jetpack site', 'jetpack' ), wp_remote_retrieve_response_code( $response ) ); + if ( ! $registration || is_wp_error( $registration ) ) { + return $registration; } - if ( empty( $registration_details->jetpack_secret ) || ! is_string( $registration_details->jetpack_secret ) ) { - return new Jetpack_Error( 'jetpack_secret', '', wp_remote_retrieve_response_code( $response ) ); - } + return true; + } - if ( isset( $registration_details->jetpack_public ) ) { - $jetpack_public = (int) $registration_details->jetpack_public; - } else { - $jetpack_public = false; - } + /** + * Filters the registration request body to include tracking properties. + * + * @param Array $properties + * @return Array amended properties. + */ + public static function filter_register_request_body( $properties ) { + $tracking = new Tracking(); + $tracks_identity = $tracking->tracks_get_identity( get_current_user_id() ); - Jetpack_Options::update_options( + return array_merge( + $properties, array( - 'id' => (int) $registration_details->jetpack_id, - 'blog_token' => (string) $registration_details->jetpack_secret, - 'public' => $jetpack_public, + '_ui' => $tracks_identity['_ui'], + '_ut' => $tracks_identity['_ut'], ) ); + } - /** - * Fires when a site is registered on WordPress.com. - * - * @since 3.7.0 - * - * @param int $json->jetpack_id Jetpack Blog ID. - * @param string $json->jetpack_secret Jetpack Blog Token. - * @param int|bool $jetpack_public Is the site public. - */ - do_action( 'jetpack_site_registered', $registration_details->jetpack_id, $registration_details->jetpack_secret, $jetpack_public ); - - // Initialize Jump Start for the first and only time. - if ( ! Jetpack_Options::get_option( 'jumpstart' ) ) { - Jetpack_Options::update_option( 'jumpstart', 'new_connection' ); - - $jetpack = Jetpack::init(); - - $jetpack->stat( 'jumpstart', 'unique-views' ); - $jetpack->do_stats( 'server_side' ); - }; + /** + * Filters the token request body to include tracking properties. + * + * @param Array $properties + * @return Array amended properties. + */ + public static function filter_token_request_body( $properties ) { + $tracking = new Tracking(); + $tracks_identity = $tracking->tracks_get_identity( get_current_user_id() ); - return true; + return array_merge( + $properties, + array( + '_ui' => $tracks_identity['_ui'], + '_ut' => $tracks_identity['_ut'], + ) + ); } /** @@ -5124,180 +5298,68 @@ p { return false; } -/* Client Server API */ + /* Client Server API */ /** - * Loads the Jetpack XML-RPC client + * Loads the Jetpack XML-RPC client. + * No longer necessary, as the XML-RPC client will be automagically loaded. + * + * @deprecated since 7.7.0 */ public static function load_xml_rpc_client() { - require_once ABSPATH . WPINC . '/class-IXR.php'; - require_once JETPACK__PLUGIN_DIR . 'class.jetpack-ixr-client.php'; + // Removed the php notice that shows up in order to give time to Akismet and VaultPress time to update. + // _deprecated_function( __METHOD__, 'jetpack-7.7' ); } /** * Resets the saved authentication state in between testing requests. */ public function reset_saved_auth_state() { - $this->xmlrpc_verification = null; $this->rest_authentication_status = null; + $this->connection_manager->reset_saved_auth_state(); } - function verify_xml_rpc_signature() { - if ( $this->xmlrpc_verification ) { - return $this->xmlrpc_verification; - } - - // It's not for us - if ( ! isset( $_GET['token'] ) || empty( $_GET['signature'] ) ) { - return false; - } - - @list( $token_key, $version, $user_id ) = explode( ':', $_GET['token'] ); - if ( - empty( $token_key ) - || - empty( $version ) || strval( JETPACK__API_VERSION ) !== $version - ) { - return false; - } - - if ( '0' === $user_id ) { - $token_type = 'blog'; - $user_id = 0; - } else { - $token_type = 'user'; - if ( empty( $user_id ) || ! ctype_digit( $user_id ) ) { - return false; - } - $user_id = (int) $user_id; - - $user = new WP_User( $user_id ); - if ( ! $user || ! $user->exists() ) { - return false; - } - } - - $token = Jetpack_Data::get_access_token( $user_id ); - if ( ! $token ) { - return false; - } - - $token_check = "$token_key."; - if ( ! hash_equals( substr( $token->secret, 0, strlen( $token_check ) ), $token_check ) ) { - return false; - } - - require_once JETPACK__PLUGIN_DIR . 'class.jetpack-signature.php'; - - $jetpack_signature = new Jetpack_Signature( $token->secret, (int) Jetpack_Options::get_option( 'time_diff' ) ); - if ( isset( $_POST['_jetpack_is_multipart'] ) ) { - $post_data = $_POST; - $file_hashes = array(); - foreach ( $post_data as $post_data_key => $post_data_value ) { - if ( 0 !== strpos( $post_data_key, '_jetpack_file_hmac_' ) ) { - continue; - } - $post_data_key = substr( $post_data_key, strlen( '_jetpack_file_hmac_' ) ); - $file_hashes[$post_data_key] = $post_data_value; - } - - foreach ( $file_hashes as $post_data_key => $post_data_value ) { - unset( $post_data["_jetpack_file_hmac_{$post_data_key}"] ); - $post_data[$post_data_key] = $post_data_value; - } - - ksort( $post_data ); - - $body = http_build_query( stripslashes_deep( $post_data ) ); - } elseif ( is_null( $this->HTTP_RAW_POST_DATA ) ) { - $body = file_get_contents( 'php://input' ); - } else { - $body = null; - } - - $signature = $jetpack_signature->sign_current_request( - array( 'body' => is_null( $body ) ? $this->HTTP_RAW_POST_DATA : $body, ) - ); - - if ( ! $signature ) { - return false; - } else if ( is_wp_error( $signature ) ) { - return $signature; - } else if ( ! hash_equals( $signature, $_GET['signature'] ) ) { - return false; - } - - $timestamp = (int) $_GET['timestamp']; - $nonce = stripslashes( (string) $_GET['nonce'] ); - - if ( ! $this->add_nonce( $timestamp, $nonce ) ) { - return false; - } - - // Let's see if this is onboarding. In such case, use user token type and the provided user id. - if ( isset( $this->HTTP_RAW_POST_DATA ) || ! empty( $_GET['onboarding'] ) ) { - if ( ! empty( $_GET['onboarding'] ) ) { - $jpo = $_GET; - } else { - $jpo = json_decode( $this->HTTP_RAW_POST_DATA, true ); - } - - $jpo_token = ! empty( $jpo['onboarding']['token'] ) ? $jpo['onboarding']['token'] : null; - $jpo_user = ! empty( $jpo['onboarding']['jpUser'] ) ? $jpo['onboarding']['jpUser'] : null; - - if ( - isset( $jpo_user ) && isset( $jpo_token ) && - is_email( $jpo_user ) && ctype_alnum( $jpo_token ) && - isset( $_GET['rest_route'] ) && - self::validate_onboarding_token_action( $jpo_token, $_GET['rest_route'] ) - ) { - $jpUser = get_user_by( 'email', $jpo_user ); - if ( is_a( $jpUser, 'WP_User' ) ) { - wp_set_current_user( $jpUser->ID ); - $user_can = is_multisite() - ? current_user_can_for_blog( get_current_blog_id(), 'manage_options' ) - : current_user_can( 'manage_options' ); - if ( $user_can ) { - $token_type = 'user'; - $token->external_user_id = $jpUser->ID; - } - } - } - } - - $this->xmlrpc_verification = array( - 'type' => $token_type, - 'user_id' => $token->external_user_id, - ); - - return $this->xmlrpc_verification; + /** + * Verifies the signature of the current request. + * + * @deprecated since 7.7.0 + * @see Automattic\Jetpack\Connection\Manager::verify_xml_rpc_signature() + * + * @return false|array + */ + public function verify_xml_rpc_signature() { + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::verify_xml_rpc_signature' ); + return self::connection()->verify_xml_rpc_signature(); } /** - * Authenticates XML-RPC and other requests from the Jetpack Server + * Verifies the signature of the current request. + * + * This function has side effects and should not be used. Instead, + * use the memoized version `->verify_xml_rpc_signature()`. + * + * @deprecated since 7.7.0 + * @see Automattic\Jetpack\Connection\Manager::internal_verify_xml_rpc_signature() + * @internal */ - function authenticate_jetpack( $user, $username, $password ) { - if ( is_a( $user, 'WP_User' ) ) { - return $user; - } - - $token_details = $this->verify_xml_rpc_signature(); - - if ( ! $token_details || is_wp_error( $token_details ) ) { - return $user; - } - - if ( 'user' !== $token_details['type'] ) { - return $user; - } - - if ( ! $token_details['user_id'] ) { - return $user; - } - - nocache_headers(); + private function internal_verify_xml_rpc_signature() { + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::internal_verify_xml_rpc_signature' ); + } - return new WP_User( $token_details['user_id'] ); + /** + * Authenticates XML-RPC and other requests from the Jetpack Server. + * + * @deprecated since 7.7.0 + * @see Automattic\Jetpack\Connection\Manager::authenticate_jetpack() + * + * @param \WP_User|mixed $user User object if authenticated. + * @param string $username Username. + * @param string $password Password string. + * @return \WP_User|mixed Authenticated user or error. + */ + public function authenticate_jetpack( $user, $username, $password ) { + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::authenticate_jetpack' ); + return $this->connection_manager->authenticate_jetpack( $user, $username, $password ); } // Authenticates requests from Jetpack server to WP REST API endpoints. @@ -5351,12 +5413,7 @@ p { return null; } - $verified = $this->verify_xml_rpc_signature(); - - if ( is_wp_error( $verified ) ) { - $this->rest_authentication_status = $verified; - return null; - } + $verified = $this->connection_manager->verify_xml_rpc_signature(); if ( $verified && @@ -5391,141 +5448,88 @@ p { return $this->rest_authentication_status; } - function add_nonce( $timestamp, $nonce ) { - global $wpdb; - static $nonces_used_this_request = array(); - - if ( isset( $nonces_used_this_request["$timestamp:$nonce"] ) ) { - return $nonces_used_this_request["$timestamp:$nonce"]; - } - - // This should always have gone through Jetpack_Signature::sign_request() first to check $timestamp an $nonce - $timestamp = (int) $timestamp; - $nonce = esc_sql( $nonce ); - - // Raw query so we can avoid races: add_option will also update - $show_errors = $wpdb->show_errors( false ); - - $old_nonce = $wpdb->get_row( - $wpdb->prepare( "SELECT * FROM `$wpdb->options` WHERE option_name = %s", "jetpack_nonce_{$timestamp}_{$nonce}" ) - ); - - if ( is_null( $old_nonce ) ) { - $return = $wpdb->query( - $wpdb->prepare( - "INSERT INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, %s)", - "jetpack_nonce_{$timestamp}_{$nonce}", - time(), - 'no' - ) - ); - } else { - $return = false; - } - - $wpdb->show_errors( $show_errors ); - - $nonces_used_this_request["$timestamp:$nonce"] = $return; - - return $return; + /** + * Add our nonce to this request. + * + * @deprecated since 7.7.0 + * @see Automattic\Jetpack\Connection\Manager::add_nonce() + * + * @param int $timestamp Timestamp of the request. + * @param string $nonce Nonce string. + */ + public function add_nonce( $timestamp, $nonce ) { + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::add_nonce' ); + return $this->connection_manager->add_nonce( $timestamp, $nonce ); } /** * In some setups, $HTTP_RAW_POST_DATA can be emptied during some IXR_Server paths since it is passed by reference to various methods. * Capture it here so we can verify the signature later. + * + * @deprecated since 7.7.0 + * @see Automattic\Jetpack\Connection\Manager::xmlrpc_methods() + * + * @param array $methods XMLRPC methods. + * @return array XMLRPC methods, with the $HTTP_RAW_POST_DATA one. */ - function xmlrpc_methods( $methods ) { - $this->HTTP_RAW_POST_DATA = $GLOBALS['HTTP_RAW_POST_DATA']; - return $methods; + public function xmlrpc_methods( $methods ) { + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::xmlrpc_methods' ); + return $this->connection_manager->xmlrpc_methods( $methods ); } - function public_xmlrpc_methods( $methods ) { - if ( array_key_exists( 'wp.getOptions', $methods ) ) { - $methods['wp.getOptions'] = array( $this, 'jetpack_getOptions' ); - } - return $methods; + /** + * Register additional public XMLRPC methods. + * + * @deprecated since 7.7.0 + * @see Automattic\Jetpack\Connection\Manager::public_xmlrpc_methods() + * + * @param array $methods Public XMLRPC methods. + * @return array Public XMLRPC methods, with the getOptions one. + */ + public function public_xmlrpc_methods( $methods ) { + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::public_xmlrpc_methods' ); + return $this->connection_manager->public_xmlrpc_methods( $methods ); } - function jetpack_getOptions( $args ) { - global $wp_xmlrpc_server; - - $wp_xmlrpc_server->escape( $args ); - - $username = $args[1]; - $password = $args[2]; - - if ( !$user = $wp_xmlrpc_server->login($username, $password) ) { - return $wp_xmlrpc_server->error; - } - - $options = array(); - $user_data = $this->get_connected_user_data(); - if ( is_array( $user_data ) ) { - $options['jetpack_user_id'] = array( - 'desc' => __( 'The WP.com user ID of the connected user', 'jetpack' ), - 'readonly' => true, - 'value' => $user_data['ID'], - ); - $options['jetpack_user_login'] = array( - 'desc' => __( 'The WP.com username of the connected user', 'jetpack' ), - 'readonly' => true, - 'value' => $user_data['login'], - ); - $options['jetpack_user_email'] = array( - 'desc' => __( 'The WP.com user email of the connected user', 'jetpack' ), - 'readonly' => true, - 'value' => $user_data['email'], - ); - $options['jetpack_user_site_count'] = array( - 'desc' => __( 'The number of sites of the connected WP.com user', 'jetpack' ), - 'readonly' => true, - 'value' => $user_data['site_count'], - ); - } - $wp_xmlrpc_server->blog_options = array_merge( $wp_xmlrpc_server->blog_options, $options ); - $args = stripslashes_deep( $args ); - return $wp_xmlrpc_server->wp_getOptions( $args ); + /** + * Handles a getOptions XMLRPC method call. + * + * @deprecated since 7.7.0 + * @see Automattic\Jetpack\Connection\Manager::jetpack_getOptions() + * + * @param array $args method call arguments. + * @return array an amended XMLRPC server options array. + */ + public function jetpack_getOptions( $args ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::jetpack_getOptions' ); + return $this->connection_manager->jetpack_getOptions( $args ); } - function xmlrpc_options( $options ) { - $jetpack_client_id = false; - if ( self::is_active() ) { - $jetpack_client_id = Jetpack_Options::get_option( 'id' ); - } - $options['jetpack_version'] = array( - 'desc' => __( 'Jetpack Plugin Version', 'jetpack' ), - 'readonly' => true, - 'value' => JETPACK__VERSION, - ); - - $options['jetpack_client_id'] = array( - 'desc' => __( 'The Client ID/WP.com Blog ID of this site', 'jetpack' ), - 'readonly' => true, - 'value' => $jetpack_client_id, - ); - return $options; + /** + * Adds Jetpack-specific options to the output of the XMLRPC options method. + * + * @deprecated since 7.7.0 + * @see Automattic\Jetpack\Connection\Manager::xmlrpc_options() + * + * @param array $options Standard Core options. + * @return array Amended options. + */ + public function xmlrpc_options( $options ) { + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::xmlrpc_options' ); + return $this->connection_manager->xmlrpc_options( $options ); } + /** + * Cleans nonces that were saved when calling ::add_nonce. + * + * @deprecated since 7.7.0 + * @see Automattic\Jetpack\Connection\Manager::clean_nonces() + * + * @param bool $all whether to clean even non-expired nonces. + */ public static function clean_nonces( $all = false ) { - global $wpdb; - - $sql = "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE %s"; - $sql_args = array( $wpdb->esc_like( 'jetpack_nonce_' ) . '%' ); - - if ( true !== $all ) { - $sql .= ' AND CAST( `option_value` AS UNSIGNED ) < %d'; - $sql_args[] = time() - 3600; - } - - $sql .= ' ORDER BY `option_id` LIMIT 100'; - - $sql = $wpdb->prepare( $sql, $sql_args ); - - for ( $i = 0; $i < 1000; $i++ ) { - if ( ! $wpdb->query( $sql ) ) { - break; - } - } + _deprecated_function( __METHOD__, 'jetpack-7.7', 'Automattic\\Jetpack\\Connection\\Manager::clean_nonces' ); + return self::connection()->clean_nonces( $all ); } /** @@ -5535,14 +5539,14 @@ p { * * @param string $key * @param string $value - * @param bool $restate private + * @param bool $restate private */ public static function state( $key = null, $value = null, $restate = false ) { static $state = array(); static $path, $domain; if ( ! isset( $path ) ) { - require_once( ABSPATH . 'wp-admin/includes/plugin.php' ); - $admin_url = Jetpack::admin_url(); + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + $admin_url = self::admin_url(); $bits = wp_parse_url( $admin_url ); if ( is_array( $bits ) ) { @@ -5554,12 +5558,13 @@ p { } // Extract state from cookies and delete cookies - if ( isset( $_COOKIE[ 'jetpackState' ] ) && is_array( $_COOKIE[ 'jetpackState' ] ) ) { - $yum = $_COOKIE[ 'jetpackState' ]; - unset( $_COOKIE[ 'jetpackState' ] ); + if ( isset( $_COOKIE['jetpackState'] ) && is_array( $_COOKIE['jetpackState'] ) ) { + $yum = $_COOKIE['jetpackState']; + unset( $_COOKIE['jetpackState'] ); foreach ( $yum as $k => $v ) { - if ( strlen( $v ) ) + if ( strlen( $v ) ) { $state[ $k ] = $v; + } setcookie( "jetpackState[$k]", false, 0, $path, $domain ); } } @@ -5573,14 +5578,15 @@ p { // Get a state variable if ( isset( $key ) && ! isset( $value ) ) { - if ( array_key_exists( $key, $state ) ) + if ( array_key_exists( $key, $state ) ) { return $state[ $key ]; + } return null; } // Set a state variable - if ( isset ( $key ) && isset( $value ) ) { - if( is_array( $value ) && isset( $value[0] ) ) { + if ( isset( $key ) && isset( $value ) ) { + if ( is_array( $value ) && isset( $value[0] ) ) { $value = $value[0]; } $state[ $key ] = $value; @@ -5589,7 +5595,7 @@ p { } public static function restate() { - Jetpack::state( null, null, true ); + self::state( null, null, true ); } public static function check_privacy( $file ) { @@ -5598,7 +5604,6 @@ p { if ( is_null( $is_site_publicly_accessible ) ) { $is_site_publicly_accessible = false; - Jetpack::load_xml_rpc_client(); $rpc = new Jetpack_IXR_Client(); $success = $rpc->query( 'jetpack.isSitePubliclyAccessible', home_url() ); @@ -5618,38 +5623,37 @@ p { $module_slug = self::get_module_slug( $file ); - $privacy_checks = Jetpack::state( 'privacy_checks' ); + $privacy_checks = self::state( 'privacy_checks' ); if ( ! $privacy_checks ) { $privacy_checks = $module_slug; } else { $privacy_checks .= ",$module_slug"; } - Jetpack::state( 'privacy_checks', $privacy_checks ); + self::state( 'privacy_checks', $privacy_checks ); } /** * Helper method for multicall XMLRPC. + * + * @param ...$args Args for the async_call. */ - public static function xmlrpc_async_call() { + public static function xmlrpc_async_call( ...$args ) { global $blog_id; static $clients = array(); $client_blog_id = is_multisite() ? $blog_id : 0; - if ( ! isset( $clients[$client_blog_id] ) ) { - Jetpack::load_xml_rpc_client(); - $clients[$client_blog_id] = new Jetpack_IXR_ClientMulticall( array( 'user_id' => JETPACK_MASTER_USER, ) ); + if ( ! isset( $clients[ $client_blog_id ] ) ) { + $clients[ $client_blog_id ] = new Jetpack_IXR_ClientMulticall( array( 'user_id' => JETPACK_MASTER_USER ) ); if ( function_exists( 'ignore_user_abort' ) ) { ignore_user_abort( true ); } add_action( 'shutdown', array( 'Jetpack', 'xmlrpc_async_call' ) ); } - $args = func_get_args(); - if ( ! empty( $args[0] ) ) { - call_user_func_array( array( $clients[$client_blog_id], 'addCall' ), $args ); + call_user_func_array( array( $clients[ $client_blog_id ], 'addCall' ), $args ); } elseif ( is_multisite() ) { foreach ( $clients as $client_blog_id => $client ) { if ( ! $client_blog_id || empty( $client->calls ) ) { @@ -5677,7 +5681,7 @@ p { public static function staticize_subdomain( $url ) { // Extract hostname from URL - $host = parse_url( $url, PHP_URL_HOST ); + $host = wp_parse_url( $url, PHP_URL_HOST ); // Explode hostname on '.' $exploded_host = explode( '.', $host ); @@ -5685,7 +5689,7 @@ p { // Retrieve the name and TLD if ( count( $exploded_host ) > 1 ) { $name = $exploded_host[ count( $exploded_host ) - 2 ]; - $tld = $exploded_host[ count( $exploded_host ) - 1 ]; + $tld = $exploded_host[ count( $exploded_host ) - 1 ]; // Rebuild domain excluding subdomains $domain = $name . '.' . $tld; } else { @@ -5710,7 +5714,7 @@ p { return preg_replace( '|://[^/]+?/|', "://s$static_counter.wp.com/", $url ); } -/* JSON API Authorization */ + /* JSON API Authorization */ /** * Handles the login action for Authorizing the JSON API @@ -5731,11 +5735,12 @@ p { return $url; } - $parsed_url = parse_url( $url ); - $url = strtok( $url, '?' ); - $url = "$url?{$_SERVER['QUERY_STRING']}"; - if ( ! empty( $parsed_url['query'] ) ) + $parsed_url = wp_parse_url( $url ); + $url = strtok( $url, '?' ); + $url = "$url?{$_SERVER['QUERY_STRING']}"; + if ( ! empty( $parsed_url['query'] ) ) { $url .= "&{$parsed_url['query']}"; + } return $url; } @@ -5797,24 +5802,26 @@ p { * @param null|array $environment */ function verify_json_api_authorization_request( $environment = null ) { - require_once JETPACK__PLUGIN_DIR . 'class.jetpack-signature.php'; - $environment = is_null( $environment ) ? $_REQUEST : $environment; list( $envToken, $envVersion, $envUserId ) = explode( ':', $environment['token'] ); - $token = Jetpack_Data::get_access_token( $envUserId ); + $token = Jetpack_Data::get_access_token( $envUserId, $envToken ); if ( ! $token || empty( $token->secret ) ) { - wp_die( __( 'You must connect your Jetpack plugin to WordPress.com to use this feature.' , 'jetpack' ) ); + wp_die( __( 'You must connect your Jetpack plugin to WordPress.com to use this feature.', 'jetpack' ) ); } $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' ); // Host has encoded the request URL, probably as a result of a bad http => https redirect - if ( Jetpack::is_redirect_encoded( $_GET['redirect_to'] ) ) { - JetpackTracking::record_user_event( 'error_double_encode' ); - + if ( self::is_redirect_encoded( $_GET['redirect_to'] ) ) { + /** + * Jetpack authorisation request Error. + * + * @since 7.5.0 + */ + do_action( 'jetpack_verify_api_authorization_request_error_double_encode' ); $die_error = sprintf( /* translators: %s is a URL */ __( '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' ), @@ -5836,17 +5843,28 @@ p { true ); } else { - $signature = $jetpack_signature->sign_current_request( array( 'body' => null, 'method' => 'GET' ) ); + $signature = $jetpack_signature->sign_current_request( + array( + 'body' => null, + 'method' => 'GET', + ) + ); } if ( ! $signature ) { wp_die( $die_error ); - } else if ( is_wp_error( $signature ) ) { + } elseif ( is_wp_error( $signature ) ) { wp_die( $die_error ); - } else if ( ! hash_equals( $signature, $environment['signature'] ) ) { + } elseif ( ! hash_equals( $signature, $environment['signature'] ) ) { if ( is_ssl() ) { // 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 - $signature = $jetpack_signature->sign_current_request( array( 'scheme' => 'http', 'body' => null, 'method' => 'GET' ) ); + $signature = $jetpack_signature->sign_current_request( + array( + 'scheme' => 'http', + 'body' => null, + 'method' => 'GET', + ) + ); if ( ! $signature || is_wp_error( $signature ) || ! hash_equals( $signature, $environment['signature'] ) ) { wp_die( $die_error ); } @@ -5858,16 +5876,16 @@ p { $timestamp = (int) $environment['timestamp']; $nonce = stripslashes( (string) $environment['nonce'] ); - if ( ! $this->add_nonce( $timestamp, $nonce ) ) { + if ( ! $this->connection_manager->add_nonce( $timestamp, $nonce ) ) { // De-nonce the nonce, at least for 5 minutes. // 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) $old_nonce_time = get_option( "jetpack_nonce_{$timestamp}_{$nonce}" ); if ( $old_nonce_time < time() - 300 ) { - wp_die( __( 'The authorization process expired. Please go back and try again.' , 'jetpack' ) ); + wp_die( __( 'The authorization process expired. Please go back and try again.', 'jetpack' ) ); } } - $data = json_decode( base64_decode( stripslashes( $environment['data'] ) ) ); + $data = json_decode( base64_decode( stripslashes( $environment['data'] ) ) ); $data_filters = array( 'state' => 'opaque', 'client_id' => 'int', @@ -5881,18 +5899,18 @@ p { } switch ( $sanitation ) { - case 'int' : - $this->json_api_authorization_request[$key] = (int) $data->$key; - break; - case 'opaque' : - $this->json_api_authorization_request[$key] = (string) $data->$key; - break; - case 'string' : - $this->json_api_authorization_request[$key] = wp_kses( (string) $data->$key, array() ); - break; - case 'url' : - $this->json_api_authorization_request[$key] = esc_url_raw( (string) $data->$key ); - break; + case 'int': + $this->json_api_authorization_request[ $key ] = (int) $data->$key; + break; + case 'opaque': + $this->json_api_authorization_request[ $key ] = (string) $data->$key; + break; + case 'string': + $this->json_api_authorization_request[ $key ] = wp_kses( (string) $data->$key, array() ); + break; + case 'url': + $this->json_api_authorization_request[ $key ] = esc_url_raw( (string) $data->$key ); + break; } } @@ -5903,7 +5921,7 @@ p { function login_message_json_api_authorization( $message ) { return '<p class="message">' . sprintf( - esc_html__( '%s wants to access your site’s data. Log in to authorize that access.' , 'jetpack' ), + esc_html__( '%s wants to access your site’s data. Log in to authorize that access.', 'jetpack' ), '<strong>' . esc_html( $this->json_api_authorization_request['client_title'] ) . '</strong>' ) . '<img src="' . esc_url( $this->json_api_authorization_request['client_image'] ) . '" /></p>'; } @@ -5912,7 +5930,9 @@ p { * Get $content_width, but with a <s>twist</s> filter. */ public static function get_content_width() { - $content_width = isset( $GLOBALS['content_width'] ) ? $GLOBALS['content_width'] : false; + $content_width = ( isset( $GLOBALS['content_width'] ) && is_numeric( $GLOBALS['content_width'] ) ) + ? $GLOBALS['content_width'] + : false; /** * Filter the Content Width value. * @@ -5933,8 +5953,7 @@ p { public function get_cloud_site_options( $option_names ) { $option_names = array_filter( (array) $option_names, 'is_string' ); - Jetpack::load_xml_rpc_client(); - $xml = new Jetpack_IXR_Client( array( 'user_id' => JETPACK_MASTER_USER, ) ); + $xml = new Jetpack_IXR_Client( array( 'user_id' => JETPACK_MASTER_USER ) ); $xml->query( 'jetpack.fetchSiteOptions', $option_names ); if ( $xml->isError() ) { return array( @@ -5953,7 +5972,7 @@ p { * @return array|bool Array of options that are in a crisis, or false if everything is OK. */ public static function check_identity_crisis() { - if ( ! Jetpack::is_active() || Jetpack::is_development_mode() || ! self::validate_sync_error_idc_option() ) { + if ( ! self::is_active() || ( new Status() )->is_development_mode() || ! self::validate_sync_error_idc_option() ) { return false; } @@ -5972,17 +5991,18 @@ p { $is_staging = false; $known_staging = array( - 'urls' => array( + 'urls' => array( '#\.staging\.wpengine\.com$#i', // WP Engine '#\.staging\.kinsta\.com$#i', // Kinsta.com - ), + '#\.stage\.site$#i', // DreamPress + ), 'constants' => array( 'IS_WPE_SNAPSHOT', // WP Engine 'KINSTA_DEV_ENV', // Kinsta.com 'WPSTAGECOACH_STAGING', // WP Stagecoach 'JETPACK_STAGING_MODE', // Generic - ) - ); + ), + ); /** * Filters the flags of known staging sites. * @@ -5997,7 +6017,7 @@ p { $known_staging = apply_filters( 'jetpack_known_staging', $known_staging ); if ( isset( $known_staging['urls'] ) ) { - foreach ( $known_staging['urls'] as $url ){ + foreach ( $known_staging['urls'] as $url ) { if ( preg_match( $url, site_url() ) ) { $is_staging = true; break; @@ -6043,12 +6063,12 @@ p { if ( false === $idc_allowed ) { $response = wp_remote_get( 'https://jetpack.com/is-idc-allowed/' ); if ( 200 === (int) wp_remote_retrieve_response_code( $response ) ) { - $json = json_decode( wp_remote_retrieve_body( $response ) ); - $idc_allowed = isset( $json, $json->result ) && $json->result ? '1' : '0'; + $json = json_decode( wp_remote_retrieve_body( $response ) ); + $idc_allowed = isset( $json, $json->result ) && $json->result ? '1' : '0'; $transient_duration = HOUR_IN_SECONDS; } else { // If the request failed for some reason, then assume IDC is allowed and set shorter transient. - $idc_allowed = '1'; + $idc_allowed = '1'; $transient_duration = 5 * MINUTE_IN_SECONDS; } @@ -6059,9 +6079,13 @@ p { $sync_error = Jetpack_Options::get_option( 'sync_error_idc' ); if ( $idc_allowed && $sync_error && self::sync_idc_optin() ) { $local_options = self::get_sync_error_idc_option(); - if ( $sync_error['home'] === $local_options['home'] && $sync_error['siteurl'] === $local_options['siteurl'] ) { - $is_valid = true; + // Ensure all values are set. + if ( isset( $sync_error['home'] ) && isset ( $local_options['home'] ) && isset( $sync_error['siteurl'] ) && isset( $local_options['siteurl'] ) ) { + if ( $sync_error['home'] === $local_options['home'] && $sync_error['siteurl'] === $local_options['siteurl'] ) { + $is_valid = true; + } } + } /** @@ -6116,10 +6140,9 @@ p { // in a transient to allow for autoloading and caching on subsequent views. $local_options = get_transient( 'jetpack_idc_local' ); if ( false === $local_options ) { - require_once JETPACK__PLUGIN_DIR . 'sync/class.jetpack-sync-functions.php'; $local_options = array( - 'home' => Jetpack_Sync_Functions::home_url(), - 'siteurl' => Jetpack_Sync_Functions::site_url(), + 'home' => Functions::home_url(), + 'siteurl' => Functions::site_url(), ); set_transient( 'jetpack_idc_local', $local_options, MINUTE_IN_SECONDS ); } @@ -6127,7 +6150,7 @@ p { $options = array_merge( $local_options, $response ); $returned_values = array(); - foreach( $options as $key => $option ) { + foreach ( $options as $key => $option ) { if ( 'error_code' === $key ) { $returned_values[ $key ] = $option; continue; @@ -6153,10 +6176,10 @@ p { * @return bool */ public static function sync_idc_optin() { - if ( Jetpack_Constants::is_defined( 'JETPACK_SYNC_IDC_OPTIN' ) ) { - $default = Jetpack_Constants::get_constant( 'JETPACK_SYNC_IDC_OPTIN' ); + if ( Constants::is_defined( 'JETPACK_SYNC_IDC_OPTIN' ) ) { + $default = Constants::get_constant( 'JETPACK_SYNC_IDC_OPTIN' ); } else { - $default = ! Jetpack_Constants::is_defined( 'SUNRISE' ) && ! is_multisite(); + $default = ! Constants::is_defined( 'SUNRISE' ) && ! is_multisite(); } /** @@ -6210,7 +6233,7 @@ p { $url = preg_replace( "#\.{$extension}$#", ".min.{$extension}", $url ); // If it's a CSS file, stash it so we can set the .min suffix for rtl-ing. if ( 'css' === $extension ) { - $key = str_replace( JETPACK__PLUGIN_DIR, 'jetpack/', $min_full_path ); + $key = str_replace( JETPACK__PLUGIN_DIR, 'jetpack/', $min_full_path ); self::$min_assets[ $key ] = $path; } } @@ -6295,7 +6318,7 @@ p { } $file = JETPACK__PLUGIN_DIR . substr( $href, strlen( $plugins_dir ) ); - $css = Jetpack::absolutize_css_urls( file_get_contents( $file ), $href ); + $css = self::absolutize_css_urls( file_get_contents( $file ), $href ); if ( $css ) { $tag = "<!-- Inline {$item->handle} -->\r\n"; if ( empty( $item->extra['after'] ) ) { @@ -6316,14 +6339,14 @@ p { * template file as $data['value'] * * @param string $template - Template file to load - * @param array $data - Any data to pass along to the template + * @param array $data - Any data to pass along to the template * @return boolean - If template file was found **/ public function load_view( $template, $data = array() ) { $views_dir = JETPACK__PLUGIN_DIR . 'views/'; - if( file_exists( $views_dir . $template ) ) { - require_once( $views_dir . $template ); + if ( file_exists( $views_dir . $template ) ) { + require_once $views_dir . $template; return true; } @@ -6344,53 +6367,57 @@ p { * If there is no replacement, use null for replacement_name */ $deprecated_list = array( - 'jetpack_bail_on_shortcode' => 'jetpack_shortcodes_to_include', - 'wpl_sharing_2014_1' => null, - 'jetpack-tools-to-include' => 'jetpack_tools_to_include', - 'jetpack_identity_crisis_options_to_check' => null, - 'update_option_jetpack_single_user_site' => null, - 'audio_player_default_colors' => null, - 'add_option_jetpack_featured_images_enabled' => null, - 'add_option_jetpack_update_details' => null, - 'add_option_jetpack_updates' => null, - 'add_option_jetpack_network_name' => null, - 'add_option_jetpack_network_allow_new_registrations' => null, - 'add_option_jetpack_network_add_new_users' => null, - 'add_option_jetpack_network_site_upload_space' => null, - 'add_option_jetpack_network_upload_file_types' => null, + 'jetpack_bail_on_shortcode' => 'jetpack_shortcodes_to_include', + 'wpl_sharing_2014_1' => null, + 'jetpack-tools-to-include' => 'jetpack_tools_to_include', + 'jetpack_identity_crisis_options_to_check' => null, + 'update_option_jetpack_single_user_site' => null, + 'audio_player_default_colors' => null, + 'add_option_jetpack_featured_images_enabled' => null, + 'add_option_jetpack_update_details' => null, + 'add_option_jetpack_updates' => null, + 'add_option_jetpack_network_name' => null, + 'add_option_jetpack_network_allow_new_registrations' => null, + 'add_option_jetpack_network_add_new_users' => null, + 'add_option_jetpack_network_site_upload_space' => null, + 'add_option_jetpack_network_upload_file_types' => null, 'add_option_jetpack_network_enable_administration_menus' => null, - 'add_option_jetpack_is_multi_site' => null, - 'add_option_jetpack_is_main_network' => null, - 'add_option_jetpack_main_network_site' => null, - 'jetpack_sync_all_registered_options' => null, - 'jetpack_has_identity_crisis' => 'jetpack_sync_error_idc_validation', - 'jetpack_is_post_mailable' => null, - 'jetpack_seo_site_host' => null, - 'jetpack_installed_plugin' => 'jetpack_plugin_installed', - 'jetpack_holiday_snow_option_name' => null, - 'jetpack_holiday_chance_of_snow' => null, - 'jetpack_holiday_snow_js_url' => null, - 'jetpack_is_holiday_snow_season' => null, - 'jetpack_holiday_snow_option_updated' => null, - 'jetpack_holiday_snowing' => null, - 'jetpack_sso_auth_cookie_expirtation' => 'jetpack_sso_auth_cookie_expiration', - 'jetpack_cache_plans' => null, - 'jetpack_updated_theme' => 'jetpack_updated_themes', - 'jetpack_lazy_images_skip_image_with_atttributes' => 'jetpack_lazy_images_skip_image_with_attributes', - 'jetpack_enable_site_verification' => null, - 'can_display_jetpack_manage_notice' => null, + 'add_option_jetpack_is_multi_site' => null, + 'add_option_jetpack_is_main_network' => null, + 'add_option_jetpack_main_network_site' => null, + 'jetpack_sync_all_registered_options' => null, + 'jetpack_has_identity_crisis' => 'jetpack_sync_error_idc_validation', + 'jetpack_is_post_mailable' => null, + 'jetpack_seo_site_host' => null, + 'jetpack_installed_plugin' => 'jetpack_plugin_installed', + 'jetpack_holiday_snow_option_name' => null, + 'jetpack_holiday_chance_of_snow' => null, + 'jetpack_holiday_snow_js_url' => null, + 'jetpack_is_holiday_snow_season' => null, + 'jetpack_holiday_snow_option_updated' => null, + 'jetpack_holiday_snowing' => null, + 'jetpack_sso_auth_cookie_expirtation' => 'jetpack_sso_auth_cookie_expiration', + 'jetpack_cache_plans' => null, + 'jetpack_updated_theme' => 'jetpack_updated_themes', + 'jetpack_lazy_images_skip_image_with_atttributes' => 'jetpack_lazy_images_skip_image_with_attributes', + 'jetpack_enable_site_verification' => null, + 'can_display_jetpack_manage_notice' => null, // Removed in Jetpack 7.3.0 - 'atd_load_scripts' => null, - 'atd_http_post_timeout' => null, - 'atd_http_post_error' => null, - 'atd_service_domain' => null, + 'atd_load_scripts' => null, + 'atd_http_post_timeout' => null, + 'atd_http_post_error' => null, + 'atd_service_domain' => null, + 'jetpack_widget_authors_exclude' => 'jetpack_widget_authors_params', + // Removed in Jetpack 7.9.0 + 'jetpack_pwa_manifest' => null, + 'jetpack_pwa_background_color' => null, ); // This is a silly loop depth. Better way? - foreach( $deprecated_list AS $hook => $hook_alt ) { + foreach ( $deprecated_list as $hook => $hook_alt ) { if ( has_action( $hook ) ) { - foreach( $wp_filter[ $hook ] AS $func => $values ) { - foreach( $values AS $hooked ) { + foreach ( $wp_filter[ $hook ] as $func => $values ) { + foreach ( $values as $hooked ) { if ( is_callable( $hooked['function'] ) ) { $function_name = 'an anonymous function'; } else { @@ -6421,14 +6448,14 @@ p { public static function absolutize_css_urls( $css, $css_file_url ) { $pattern = '#url\((?P<path>[^)]*)\)#i'; $css_dir = dirname( $css_file_url ); - $p = parse_url( $css_dir ); + $p = wp_parse_url( $css_dir ); $domain = sprintf( - '%1$s//%2$s%3$s%4$s', - isset( $p['scheme'] ) ? "{$p['scheme']}:" : '', - isset( $p['user'], $p['pass'] ) ? "{$p['user']}:{$p['pass']}@" : '', - $p['host'], - isset( $p['port'] ) ? ":{$p['port']}" : '' - ); + '%1$s//%2$s%3$s%4$s', + isset( $p['scheme'] ) ? "{$p['scheme']}:" : '', + isset( $p['user'], $p['pass'] ) ? "{$p['user']}:{$p['pass']}@" : '', + $p['host'], + isset( $p['port'] ) ? ":{$p['port']}" : '' + ); if ( preg_match_all( $pattern, $css, $matches, PREG_SET_ORDER ) ) { $find = $replace = array(); @@ -6476,9 +6503,9 @@ p { * * Cons: * - Loads css for ALL modules. However all selectors are prefixed so it - * should not cause any issues with themes. + * should not cause any issues with themes. * - Plugins/themes dequeuing styles no longer do anything. See - * jetpack_implode_frontend_css filter for a workaround + * jetpack_implode_frontend_css filter for a workaround * * For some situations developers may wish to disable css imploding and * instead operate in legacy mode where each file loads seperately and @@ -6515,7 +6542,7 @@ p { } // We do not want to use the imploded file in dev mode, or if not connected - if ( Jetpack::is_development_mode() || ! self::is_active() ) { + if ( ( new Status() )->is_development_mode() || ! self::is_active() ) { if ( ! $travis_test ) { return; } @@ -6541,7 +6568,7 @@ p { add_filter( 'style_loader_tag', array( $this, 'concat_remove_style_loader_tag' ), 10, 2 ); - $version = Jetpack::is_development_version() ? filemtime( JETPACK__PLUGIN_DIR . 'css/jetpack.css' ) : JETPACK__VERSION; + $version = self::is_development_version() ? filemtime( JETPACK__PLUGIN_DIR . 'css/jetpack.css' ) : JETPACK__VERSION; wp_enqueue_style( 'jetpack_css', plugins_url( 'css/jetpack.css', __FILE__ ), array(), $version ); wp_style_add_data( 'jetpack_css', 'rtl', 'replace' ); @@ -6551,13 +6578,31 @@ p { if ( in_array( $handle, $this->concatenated_style_handles ) ) { $tag = ''; if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { - $tag = "<!-- `" . esc_html( $handle ) . "` is included in the concatenated jetpack.css -->\r\n"; + $tag = '<!-- `' . esc_html( $handle ) . "` is included in the concatenated jetpack.css -->\r\n"; } } return $tag; } + /** + * Add an async attribute to scripts that can be loaded asynchronously. + * https://www.w3schools.com/tags/att_script_async.asp + * + * @since 7.7.0 + * + * @param string $tag The <script> tag for the enqueued script. + * @param string $handle The script's registered handle. + * @param string $src The script's source URL. + */ + public function script_add_async( $tag, $handle, $src ) { + if ( in_array( $handle, $this->async_script_handles, true ) ) { + return preg_replace( '/^<script /i', '<script async ', $tag ); + } + + return $tag; + } + /* * Check the heartbeat data * @@ -6583,7 +6628,7 @@ p { // Check jetpack version if ( 'version' == $stat ) { if ( version_compare( $value, JETPACK__VERSION, '<' ) ) { - $caution[ $stat ] = $value . " - min supported is " . JETPACK__VERSION; + $caution[ $stat ] = $value . ' - min supported is ' . JETPACK__VERSION; continue; } } @@ -6591,15 +6636,15 @@ p { // Check WP version if ( 'wp-version' == $stat ) { if ( version_compare( $value, JETPACK__MINIMUM_WP_VERSION, '<' ) ) { - $caution[ $stat ] = $value . " - min supported is " . JETPACK__MINIMUM_WP_VERSION; + $caution[ $stat ] = $value . ' - min supported is ' . JETPACK__MINIMUM_WP_VERSION; continue; } } // Check PHP version if ( 'php-version' == $stat ) { - if ( version_compare( PHP_VERSION, '5.2.4', '<' ) ) { - $caution[ $stat ] = $value . " - min supported is 5.2.4"; + if ( version_compare( PHP_VERSION, JETPACK__MINIMUM_PHP_VERSION, '<' ) ) { + $caution[ $stat ] = $value . " - min supported is " . JETPACK__MINIMUM_PHP_VERSION; continue; } } @@ -6619,7 +6664,7 @@ p { $filtered_data = array( 'good' => $good, 'caution' => $caution, - 'bad' => $bad + 'bad' => $bad, ); return $filtered_data; @@ -6649,8 +6694,8 @@ p { */ public static function build_raw_urls( $url ) { $strip_http = '/.*?:\/\//i'; - $url = preg_replace( $strip_http, '', $url ); - $url = str_replace( '/', '::', $url ); + $url = preg_replace( $strip_http, '', $url ); + $url = str_replace( '/', '::', $url ); return $url; } @@ -6683,13 +6728,14 @@ p { } if ( has_action( 'jetpack_dashboard_widget' ) ) { + $jetpack_logo = new Jetpack_Logo(); $widget_title = sprintf( wp_kses( /* translators: Placeholder is a Jetpack logo. */ __( 'Stats <span>by %s</span>', 'jetpack' ), array( 'span' => array() ) ), - Jetpack::get_jp_emblem( true ) + $jetpack_logo->get_jp_emblem( true ) ); wp_add_dashboard_widget( @@ -6698,9 +6744,10 @@ p { array( __CLASS__, 'dashboard_widget' ) ); wp_enqueue_style( 'jetpack-dashboard-widget', plugins_url( 'css/dashboard-widget.css', JETPACK__PLUGIN_FILE ), array(), JETPACK__VERSION ); + wp_style_add_data( 'jetpack-dashboard-widget', 'rtl', 'replace' ); // If we're inactive and not in development mode, sort our box to the top. - if ( ! self::is_active() && ! self::is_development_mode() ) { + if ( ! self::is_active() && ! ( new Status() )->is_development_mode() ) { global $wp_meta_boxes; $dashboard = $wp_meta_boxes['dashboard']['normal']['core']; @@ -6727,11 +6774,11 @@ p { } $ids_array = explode( ',', $ids ); - $key = array_search( 'dashboard_stats', $ids_array ); + $key = array_search( 'dashboard_stats', $ids_array ); if ( false !== $key ) { // If we've found that exact value in the option (and not `google_dashboard_stats` for example) - $ids_array[ $key ] = 'jetpack_summary_widget'; + $ids_array[ $key ] = 'jetpack_summary_widget'; $sorted[ $box_context ] = implode( ',', $ids_array ); // We've found it, stop searching, and just return. break; @@ -6755,11 +6802,25 @@ p { <footer> <div class="protect"> - <?php if ( Jetpack::is_module_active( 'protect' ) ) : ?> + <?php if ( self::is_module_active( 'protect' ) ) : ?> <h3><?php echo number_format_i18n( get_site_option( 'jetpack_protect_blocked_attempts', 0 ) ); ?></h3> <p><?php echo esc_html_x( 'Blocked malicious login attempts', '{#} Blocked malicious login attempts -- number is on a prior line, text is a caption.', 'jetpack' ); ?></p> - <?php elseif ( current_user_can( 'jetpack_activate_modules' ) && ! self::is_development_mode() ) : ?> - <a href="<?php echo esc_url( wp_nonce_url( Jetpack::admin_url( array( 'action' => 'activate', 'module' => 'protect' ) ), 'jetpack_activate-protect' ) ); ?>" class="button button-jetpack" title="<?php esc_attr_e( 'Protect helps to keep you secure from brute-force login attacks.', 'jetpack' ); ?>"> + <?php elseif ( current_user_can( 'jetpack_activate_modules' ) && ! ( new Status() )->is_development_mode() ) : ?> + <a href=" + <?php + echo esc_url( + wp_nonce_url( + self::admin_url( + array( + 'action' => 'activate', + 'module' => 'protect', + ) + ), + 'jetpack_activate-protect' + ) + ); + ?> + " class="button button-jetpack" title="<?php esc_attr_e( 'Protect helps to keep you secure from brute-force login attacks.', 'jetpack' ); ?>"> <?php esc_html_e( 'Activate Protect', 'jetpack' ); ?> </a> <?php else : ?> @@ -6772,7 +6833,22 @@ p { <h3><?php echo number_format_i18n( get_option( 'akismet_spam_count', 0 ) ); ?></h3> <p><?php echo esc_html_x( 'Spam comments blocked by Akismet.', '{#} Spam comments blocked by Akismet -- number is on a prior line, text is a caption.', 'jetpack' ); ?></p> <?php elseif ( current_user_can( 'activate_plugins' ) && ! is_wp_error( validate_plugin( 'akismet/akismet.php' ) ) ) : ?> - <a href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'activate', 'plugin' => 'akismet/akismet.php' ), admin_url( 'plugins.php' ) ), 'activate-plugin_akismet/akismet.php' ) ); ?>" class="button button-jetpack"> + <a href=" + <?php + echo esc_url( + wp_nonce_url( + add_query_arg( + array( + 'action' => 'activate', + 'plugin' => 'akismet/akismet.php', + ), + admin_url( 'plugins.php' ) + ), + 'activate-plugin_akismet/akismet.php' + ) + ); + ?> + " class="button button-jetpack"> <?php esc_html_e( 'Activate Akismet', 'jetpack' ); ?> </a> <?php else : ?> @@ -6784,34 +6860,6 @@ p { <?php } - /** - * Return string containing the Jetpack logo. - * - * @since 3.9.0 - * - * @param bool $logotype Should we use the full logotype (logo + text). Default to false. - * - * @return string - */ - public static function get_jp_emblem( $logotype = false ) { - $logo = '<path fill="#00BE28" d="M16,0C7.2,0,0,7.2,0,16s7.2,16,16,16c8.8,0,16-7.2,16-16S24.8,0,16,0z M15.2,18.7h-8l8-15.5V18.7z M16.8,28.8 V13.3h8L16.8,28.8z"/>'; - $text = ' -<path d="M41.3,26.6c-0.5-0.7-0.9-1.4-1.3-2.1c2.3-1.4,3-2.5,3-4.6V8h-3V6h6v13.4C46,22.8,45,24.8,41.3,26.6z" /> -<path d="M65,18.4c0,1.1,0.8,1.3,1.4,1.3c0.5,0,2-0.2,2.6-0.4v2.1c-0.9,0.3-2.5,0.5-3.7,0.5c-1.5,0-3.2-0.5-3.2-3.1V12H60v-2h2.1V7.1 H65V10h4v2h-4V18.4z" /> -<path d="M71,10h3v1.3c1.1-0.8,1.9-1.3,3.3-1.3c2.5,0,4.5,1.8,4.5,5.6s-2.2,6.3-5.8,6.3c-0.9,0-1.3-0.1-2-0.3V28h-3V10z M76.5,12.3 c-0.8,0-1.6,0.4-2.5,1.2v5.9c0.6,0.1,0.9,0.2,1.8,0.2c2,0,3.2-1.3,3.2-3.9C79,13.4,78.1,12.3,76.5,12.3z" /> -<path d="M93,22h-3v-1.5c-0.9,0.7-1.9,1.5-3.5,1.5c-1.5,0-3.1-1.1-3.1-3.2c0-2.9,2.5-3.4,4.2-3.7l2.4-0.3v-0.3c0-1.5-0.5-2.3-2-2.3 c-0.7,0-2.3,0.5-3.7,1.1L84,11c1.2-0.4,3-1,4.4-1c2.7,0,4.6,1.4,4.6,4.7L93,22z M90,16.4l-2.2,0.4c-0.7,0.1-1.4,0.5-1.4,1.6 c0,0.9,0.5,1.4,1.3,1.4s1.5-0.5,2.3-1V16.4z" /> -<path d="M104.5,21.3c-1.1,0.4-2.2,0.6-3.5,0.6c-4.2,0-5.9-2.4-5.9-5.9c0-3.7,2.3-6,6.1-6c1.4,0,2.3,0.2,3.2,0.5V13 c-0.8-0.3-2-0.6-3.2-0.6c-1.7,0-3.2,0.9-3.2,3.6c0,2.9,1.5,3.8,3.3,3.8c0.9,0,1.9-0.2,3.2-0.7V21.3z" /> -<path d="M110,15.2c0.2-0.3,0.2-0.8,3.8-5.2h3.7l-4.6,5.7l5,6.3h-3.7l-4.2-5.8V22h-3V6h3V15.2z" /> -<path d="M58.5,21.3c-1.5,0.5-2.7,0.6-4.2,0.6c-3.6,0-5.8-1.8-5.8-6c0-3.1,1.9-5.9,5.5-5.9s4.9,2.5,4.9,4.9c0,0.8,0,1.5-0.1,2h-7.3 c0.1,2.5,1.5,2.8,3.6,2.8c1.1,0,2.2-0.3,3.4-0.7C58.5,19,58.5,21.3,58.5,21.3z M56,15c0-1.4-0.5-2.9-2-2.9c-1.4,0-2.3,1.3-2.4,2.9 C51.6,15,56,15,56,15z" /> - '; - - return sprintf( - '<svg id="jetpack-logo__icon" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 %1$s 32">%2$s</svg>', - ( true === $logotype ? '118' : '32' ), - ( true === $logotype ? $logo . $text : $logo ) - ); - } - /* * Adds a "blank" column in the user admin table to display indication of user connection. */ @@ -6824,11 +6872,12 @@ p { * Show Jetpack icon if the user is linked. */ function jetpack_show_user_connected_icon( $val, $col, $user_id ) { - if ( 'user_jetpack' == $col && Jetpack::is_user_connected( $user_id ) ) { - $emblem_html = sprintf( + if ( 'user_jetpack' == $col && self::is_user_connected( $user_id ) ) { + $jetpack_logo = new Jetpack_Logo(); + $emblem_html = sprintf( '<a title="%1$s" class="jp-emblem-user-admin">%2$s</a>', esc_attr__( 'This user is linked and ready to fly with Jetpack.', 'jetpack' ), - Jetpack::get_jp_emblem() + $jetpack_logo->get_jp_emblem() ); return $emblem_html; } @@ -6841,7 +6890,8 @@ p { */ function jetpack_user_col_style() { global $current_screen; - if ( ! empty( $current_screen->base ) && 'users' == $current_screen->base ) { ?> + if ( ! empty( $current_screen->base ) && 'users' == $current_screen->base ) { + ?> <style> .fixed .column-user_jetpack { width: 21px; @@ -6854,7 +6904,8 @@ p { fill: #00BE28; } </style> - <?php } + <?php + } } /** @@ -6905,34 +6956,12 @@ p { } /** - * Checks if one or more function names is in debug_backtrace - * - * @param $names Mixed string name of function or array of string names of functions + * @deprecated * - * @return bool + * @see Automattic\Jetpack\Sync\Modules\Users::is_function_in_backtrace */ - public static function is_function_in_backtrace( $names ) { - $backtrace = debug_backtrace( false ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.debug_backtrace_optionsFound - if ( ! is_array( $names ) ) { - $names = array( $names ); - } - $names_as_keys = array_flip( $names ); - - //Do check in constant O(1) time for PHP5.5+ - if ( function_exists( 'array_column' ) ) { - $backtrace_functions = array_column( $backtrace, 'function' ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.array_columnFound - $backtrace_functions_as_keys = array_flip( $backtrace_functions ); - $intersection = array_intersect_key( $backtrace_functions_as_keys, $names_as_keys ); - return ! empty ( $intersection ); - } - - //Do check in linear O(n) time for < PHP5.5 ( using isset at least prevents O(n^2) ) - foreach ( $backtrace as $call ) { - if ( isset( $names_as_keys[ $call['function'] ] ) ) { - return true; - } - } - return false; + public static function is_function_in_backtrace() { + _deprecated_function( __METHOD__, 'jetpack-7.6.0' ); } /** @@ -6949,27 +6978,24 @@ p { * @return string The URL to the file */ public static function get_file_url_for_environment( $min_path, $non_min_path ) { - $path = ( Jetpack_Constants::is_defined( 'SCRIPT_DEBUG' ) && Jetpack_Constants::get_constant( 'SCRIPT_DEBUG' ) ) - ? $non_min_path - : $min_path; - - return plugins_url( $path, JETPACK__PLUGIN_FILE ); + return Assets::get_file_url_for_environment( $min_path, $non_min_path ); } /** * Checks for whether Jetpack Backup & Scan is enabled. * Will return true if the state of Backup & Scan is anything except "unavailable". + * * @return bool|int|mixed */ public static function is_rewind_enabled() { - if ( ! Jetpack::is_active() ) { + if ( ! self::is_active() ) { return false; } $rewind_enabled = get_transient( 'jetpack_rewind_enabled' ); if ( false === $rewind_enabled ) { jetpack_require_lib( 'class.core-rest-api-endpoints' ); - $rewind_data = (array) Jetpack_Core_Json_Api_Endpoints::rewind_data(); + $rewind_data = (array) Jetpack_Core_Json_Api_Endpoints::rewind_data(); $rewind_enabled = ( ! is_wp_error( $rewind_data ) && ! empty( $rewind_data['state'] ) && 'active' === $rewind_data['state'] ) @@ -6982,11 +7008,39 @@ p { } /** + * Return Calypso environment value; used for developing Jetpack and pairing + * it with different Calypso enrionments, such as localhost. + * + * @since 7.4.0 + * + * @return string Calypso environment + */ + public static function get_calypso_env() { + if ( isset( $_GET['calypso_env'] ) ) { + return sanitize_key( $_GET['calypso_env'] ); + } + + if ( getenv( 'CALYPSO_ENV' ) ) { + return sanitize_key( getenv( 'CALYPSO_ENV' ) ); + } + + if ( defined( 'CALYPSO_ENV' ) && CALYPSO_ENV ) { + return sanitize_key( CALYPSO_ENV ); + } + + return ''; + } + + /** * Checks whether or not TOS has been agreed upon. * Will return true if a user has clicked to register, or is already connected. */ public static function jetpack_tos_agreed() { - return Jetpack_Options::get_option( 'tos_agreed' ) || Jetpack::is_active(); + _deprecated_function( 'Jetpack::jetpack_tos_agreed', 'Jetpack 7.9.0', '\Automattic\Jetpack\Terms_Of_Service->has_agreed' ); + + $terms_of_service = new Terms_Of_Service(); + return $terms_of_service->has_agreed(); + } /** @@ -7007,11 +7061,11 @@ p { : array(); if ( $active_modules = Jetpack_Options::get_option( 'active_modules' ) ) { - Jetpack::delete_active_modules(); + self::delete_active_modules(); - Jetpack::activate_default_modules( 999, 1, array_merge( $active_modules, $other_modules ), $redirect_on_activation_error, $send_state_messages ); + self::activate_default_modules( 999, 1, array_merge( $active_modules, $other_modules ), $redirect_on_activation_error, $send_state_messages ); } else { - Jetpack::activate_default_modules( false, false, $other_modules, $redirect_on_activation_error, $send_state_messages ); + self::activate_default_modules( false, false, $other_modules, $redirect_on_activation_error, $send_state_messages ); } // Since this is a fresh connection, be sure to clear out IDC options @@ -7023,7 +7077,7 @@ p { wp_schedule_event( time(), 'hourly', 'jetpack_clean_nonces' ); if ( $send_state_messages ) { - Jetpack::state( 'message', 'authorized' ); + self::state( 'message', 'authorized' ); } } @@ -7040,7 +7094,7 @@ p { * * @param bool $show_backups Should UI for backups be displayed? True by default. */ - return Jetpack::is_plugin_active( 'vaultpress/vaultpress.php' ) || apply_filters( 'jetpack_show_backups', true ); + return self::is_plugin_active( 'vaultpress/vaultpress.php' ) || apply_filters( 'jetpack_show_backups', true ); } /* @@ -7092,4 +7146,18 @@ p { } } } + + /** + * Checks if a Jetpack site is both active and not in development. + * + * This is a DRY function to avoid repeating `Jetpack::is_active && ! Automattic\Jetpack\Status->is_development_mode`. + * + * @return bool True if Jetpack is active and not in development. + */ + public static function is_active_and_not_development_mode() { + if ( ! self::is_active() || ( new Status() )->is_development_mode() ) { + return false; + } + return true; + } } |