diff options
author | Yury German <blueknight@gentoo.org> | 2016-02-12 22:22:00 -0500 |
---|---|---|
committer | Yury German <blueknight@gentoo.org> | 2016-02-12 22:22:00 -0500 |
commit | 657cafe0e955cf88033597f131aa50835140c617 (patch) | |
tree | cf21a30d319cb2a238a6cfb8b4eb3b20b1b5dcff /plugins/jetpack/class.jetpack.php | |
parent | Adding New Mantra version 2.4.1.1 - Bug 574468 (diff) | |
download | blogs-gentoo-657cafe0e955cf88033597f131aa50835140c617.tar.gz blogs-gentoo-657cafe0e955cf88033597f131aa50835140c617.tar.bz2 blogs-gentoo-657cafe0e955cf88033597f131aa50835140c617.zip |
Updating plugins easy-table, jetpack, openid, public-post preview, talbe-of-contents-plus, wordress-mobile-pack - Bug 574468
Diffstat (limited to 'plugins/jetpack/class.jetpack.php')
-rw-r--r-- | plugins/jetpack/class.jetpack.php | 2327 |
1 files changed, 1758 insertions, 569 deletions
diff --git a/plugins/jetpack/class.jetpack.php b/plugins/jetpack/class.jetpack.php index 76bdd135..5c0f846d 100644 --- a/plugins/jetpack/class.jetpack.php +++ b/plugins/jetpack/class.jetpack.php @@ -23,16 +23,16 @@ jetpack_do_activate (bool) */ class Jetpack { - var $xmlrpc_server = null; + public $xmlrpc_server = null; private $xmlrpc_verification = null; - var $HTTP_RAW_POST_DATA = null; // copy of $GLOBALS['HTTP_RAW_POST_DATA'] + public $HTTP_RAW_POST_DATA = null; // copy of $GLOBALS['HTTP_RAW_POST_DATA'] /** * @var array The handles of styles that are concatenated into jetpack.css */ - var $concatenated_style_handles = array( + public $concatenated_style_handles = array( 'jetpack-carousel', 'grunion.css', 'the-neverending-homepage', @@ -49,9 +49,10 @@ class Jetpack { 'widget-grid-and-list', 'jetpack-widgets', 'goodreads-widget', + 'jetpack_social_media_icons_widget', ); - var $plugins_to_deactivate = array( + public $plugins_to_deactivate = array( 'stats' => array( 'stats/stats.php', 'WordPress.com Stats' ), 'shortlinks' => array( 'stats/stats.php', 'WordPress.com Stats' ), 'sharedaddy' => array( 'sharedaddy/sharedaddy.php', 'Sharedaddy' ), @@ -70,7 +71,7 @@ class Jetpack { 'latex' => array( 'wp-latex/wp-latex.php', 'WP LaTeX' ) ); - var $capability_translations = array( + public $capability_translations = array( 'administrator' => 'manage_options', 'editor' => 'edit_others_posts', 'author' => 'publish_posts', @@ -94,73 +95,88 @@ class Jetpack { */ 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', + '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', ), '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', + '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', ), 'minileven' => array( - 'WPtouch' => 'wptouch/wptouch.php', + '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 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', + '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 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', + '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', + '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', ), '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', + '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', ), 'widget-visibility' => array( - 'Widget Logic' => 'widget-logic/widget_logic.php', - 'Dynamic Widgets' => 'dynamic-widgets/dynamic-widgets.php', + 'Widget Logic' => 'widget-logic/widget_logic.php', + 'Dynamic Widgets' => 'dynamic-widgets/dynamic-widgets.php', + ), + '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', + 'XML Sitemap & Google News feeds' => 'xml-sitemap-feed/xml-sitemap.php', + 'Google Sitemap by BestWebSoft' => 'google-sitemap-plugin/google-sitemap-plugin.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', + 'Sitemap' => 'sitemap/sitemap.php', + 'Simple Wp Sitemap' => 'simple-wp-sitemap/simple-wp-sitemap.php', + 'Simple Sitemap' => 'simple-sitemap/simple-sitemap.php', + 'XML Sitemaps' => 'xml-sitemaps/xml-sitemaps.php', + 'MSM Sitemaps' => 'msm-sitemap/msm-sitemap.php', ), ); @@ -178,7 +194,6 @@ class Jetpack { // 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 - 'all-in-one-seo-pack/all_in_one_seo_pack.php', // All in One SEO Pack 'easy-facebook-share-thumbnails/esft.php', // Easy Facebook Share Thumbnail 'facebook/facebook.php', // Facebook (official plugin) 'facebook-awd/AWD_facebook.php', // Facebook AWD All in one @@ -218,6 +233,7 @@ class Jetpack { '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 ); /** @@ -240,26 +256,26 @@ class Jetpack { * Message to display in admin_notice * @var string */ - var $message = ''; + public $message = ''; /** * Error to display in admin_notice * @var string */ - var $error = ''; + public $error = ''; /** * Modules that need more privacy description. * @var string */ - var $privacy_checks = ''; + public $privacy_checks = ''; /** * Stats to record once the page loads * * @var array */ - var $stats = array(); + public $stats = array(); /** * Allows us to build a temporary security report @@ -271,12 +287,12 @@ class Jetpack { /** * Jetpack_Sync object */ - var $sync; + public $sync; /** * Verified data for JSON authorization request */ - var $json_api_authorization_request = array(); + public $json_api_authorization_request = array(); /** * Holds the singleton instance of this class @@ -332,6 +348,14 @@ class Jetpack { // Add missing version and old_version options if ( ! $version = Jetpack_Options::get_option( 'version' ) ) { $version = $old_version = '1.1:' . time(); + /** + * Fires on update, before bumping version numbers up to a new version. + * + * @since 3.4.0 + * + * @param string $version Jetpack version number. + * @param bool false Does an old version exist. Default is false. + */ do_action( 'updating_jetpack_version', $version, false ); Jetpack_Options::update_options( compact( 'version', 'old_version' ) ); } @@ -375,14 +399,32 @@ class Jetpack { list( $version ) = explode( ':', Jetpack_Options::get_option( 'version' ) ); if ( JETPACK__VERSION != $version ) { add_action( 'init', array( __CLASS__, 'activate_new_modules' ) ); + /** + * Fires when synchronizing all registered options and constants. + * + * @since 3.3.0 + */ do_action( 'jetpack_sync_all_registered_options' ); } + + //if Jetpack is connected check if jetpack_unique_connection exists and if not then set it + $jetpack_unique_connection = get_option( 'jetpack_unique_connection' ); + $is_unique_connection = $jetpack_unique_connection && array_key_exists( 'version', $jetpack_unique_connection ); + if ( ! $is_unique_connection ) { + $jetpack_unique_connection = array( + 'connected' => 1, + 'disconnected' => -1, + 'version' => '3.6.1' + ); + update_option( 'jetpack_unique_connection', $jetpack_unique_connection ); + } } if ( get_option( 'jetpack_json_api_full_management' ) ) { delete_option( 'jetpack_json_api_full_management' ); self::activate_manage(); } + } static function activate_manage( ) { @@ -398,7 +440,7 @@ class Jetpack { /** * Constructor. Initializes WordPress hooks */ - private function Jetpack() { + private function __construct() { /* * Check for and alert any deprecated hooks */ @@ -408,7 +450,21 @@ class Jetpack { * Do things that should run even in the network admin * here, before we potentially fail out. */ - add_filter( 'jetpack_require_lib_dir', array( $this, 'require_lib_dir' ) ); + add_filter( 'jetpack_require_lib_dir', array( $this, 'require_lib_dir' ) ); + + /** + * We need sync object even in Multisite mode + */ + $this->sync = new Jetpack_Sync; + + /** + * Trigger a wp_version sync when updating WP versions + **/ + add_action( 'upgrader_process_complete', array( 'Jetpack', 'update_get_wp_version' ), 10, 2 ); + $this->sync->mock_option( 'wp_version', array( 'Jetpack', 'get_wp_version' ) ); + + add_action( 'init', array( $this, 'sync_update_data') ); + add_action( 'init', array( $this, 'sync_theme_data' ) ); /* * Load things that should only be in Network Admin. @@ -420,14 +476,25 @@ class Jetpack { if( is_multisite() ) { Jetpack_Network::init(); - if( is_network_admin() ) - return; // End here to prevent single site actions from firing + // Only sync this info if we are on a multi site + // @since 3.7 + $this->sync->mock_option( 'network_name', array( 'Jetpack', 'network_name' ) ); + $this->sync->mock_option( 'network_allow_new_registrations', array( 'Jetpack', 'network_allow_new_registrations' ) ); + $this->sync->mock_option( 'network_add_new_users', array( 'Jetpack', 'network_add_new_users' ) ); + $this->sync->mock_option( 'network_site_upload_space', array( 'Jetpack', 'network_site_upload_space' ) ); + $this->sync->mock_option( 'network_upload_file_types', array( 'Jetpack', 'network_upload_file_types' ) ); + $this->sync->mock_option( 'network_enable_administration_menus', array( 'Jetpack', 'network_enable_administration_menus' ) ); + + if( is_network_admin() ) { + // Sync network site data if it is updated or not. + add_action( 'update_wpmu_options', array( $this, 'update_jetpack_network_settings' ) ); + return; // End here to prevent single site actions from firing + } } $theme_slug = get_option( 'stylesheet' ); - $this->sync = new Jetpack_Sync; // Modules should do Jetpack_Sync::sync_options( __FILE__, $option, ... ); instead // We access the "internal" method here only because the Jetpack object isn't instantiated yet @@ -442,7 +509,18 @@ class Jetpack { 'stylesheet', "theme_mods_{$theme_slug}", 'jetpack_sync_non_public_post_stati', - 'jetpack_options' + 'jetpack_options', + 'site_icon', // (int) - ID of core's Site Icon attachment ID + 'default_post_format', + 'default_category', + 'large_size_w', + 'large_size_h', + 'thumbnail_size_w', + 'thumbnail_size_h', + 'medium_size_w', + 'medium_size_h', + 'thumbnail_crop', + 'image_default_link_type' ); foreach( Jetpack_Options::get_option_names( 'non-compact' ) as $option ) { @@ -456,8 +534,13 @@ class Jetpack { $this->sync->mock_option( 'is_main_network', array( $this, 'is_main_network_option' ) ); $this->sync->mock_option( 'is_multi_site', array( $this, 'is_multisite' ) ); $this->sync->mock_option( 'main_network_site', array( $this, 'jetpack_main_network_site_option' ) ); - $this->sync->mock_option( 'single_user_site', array( $this, 'is_single_user_site' ) ); + $this->sync->mock_option( 'single_user_site', array( 'Jetpack', 'is_single_user_site' ) ); + $this->sync->mock_option( 'stat_data', array( $this, 'get_stat_data' ) ); + $this->sync->mock_option( 'has_file_system_write_access', array( 'Jetpack', 'file_system_write_access' ) ); + $this->sync->mock_option( 'is_version_controlled', array( 'Jetpack', 'is_version_controlled' ) ); + $this->sync->mock_option( 'max_upload_size', 'wp_max_upload_size' ); + $this->sync->mock_option( 'content_width', array( 'Jetpack', 'get_content_width' ) ); /** * Trigger an update to the main_network_site when we update the blogname of a site. @@ -471,6 +554,10 @@ class Jetpack { add_action( 'user_register', array( $this, 'is_single_user_site_invalidate' ) ); add_action( 'deleted_user', array( $this, 'is_single_user_site_invalidate' ) ); + // 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 ); + 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. @@ -527,16 +614,22 @@ class Jetpack { // Filter the dashboard meta box order to swap the new one in in place of the old one. add_filter( 'get_user_option_meta-box-order_dashboard', array( $this, 'get_user_option_meta_box_order_dashboard' ) ); - add_action( 'wp_ajax_jetpack-check-news-subscription', array( $this, 'check_news_subscription' ) ); - add_action( 'wp_ajax_jetpack-subscribe-to-news', array( $this, 'subscribe_to_news' ) ); - add_action( 'wp_ajax_jetpack-sync-reindex-trigger', array( $this, 'sync_reindex_trigger' ) ); add_action( 'wp_ajax_jetpack-sync-reindex-status', array( $this, 'sync_reindex_status' ) ); // Jump Start AJAX callback function - add_action( 'wp_ajax_jetpack_admin_ajax', array( $this, 'jetpack_jumpstart_ajax_callback' ) ); + add_action( 'wp_ajax_jetpack_jumpstart_ajax', array( $this, 'jetpack_jumpstart_ajax_callback' ) ); add_action( 'update_option', array( $this, 'jumpstart_has_updated_module_option' ) ); + // Identity Crisis AJAX callback function + add_action( 'wp_ajax_jetpack_resolve_identity_crisis', array( $this, 'resolve_identity_crisis_ajax_callback' ) ); + + // JITM AJAX callback function + add_action( 'wp_ajax_jitm_ajax', array( $this, 'jetpack_jitm_ajax_callback' ) ); + + add_action( 'wp_ajax_jetpack_admin_ajax', array( $this, 'jetpack_admin_ajax_callback' ) ); + add_action( 'wp_ajax_jetpack_admin_ajax_refresh', array( $this, 'jetpack_admin_ajax_refresh_data' ) ); + add_action( 'wp_loaded', array( $this, 'register_assets' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'devicepx' ) ); add_action( 'customize_controls_enqueue_scripts', array( $this, 'devicepx' ) ); @@ -564,6 +657,9 @@ class Jetpack { add_filter( 'jetpack_get_default_modules', array( $this, 'filter_default_modules' ) ); 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' ); + /** * This is the hack to concatinate all css files into one. * For description and reasoning see the implode_frontend_css method @@ -574,6 +670,82 @@ class Jetpack { 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` } + + // Sync Core Icon: Detect changes in Core's Site Icon and make it syncable. + add_action( 'add_option_site_icon', array( $this, 'jetpack_sync_core_icon' ) ); + add_action( 'update_option_site_icon', array( $this, 'jetpack_sync_core_icon' ) ); + add_action( 'delete_option_site_icon', array( $this, 'jetpack_sync_core_icon' ) ); + add_action( 'jetpack_heartbeat', array( $this, 'jetpack_sync_core_icon' ) ); + + } + + /* + * Make sure any site icon added to core can get + * synced back to dotcom, so we can display it there. + */ + function jetpack_sync_core_icon() { + if ( function_exists( 'get_site_icon_url' ) ) { + $url = get_site_icon_url(); + } else { + return; + } + + require_once( JETPACK__PLUGIN_DIR . 'modules/site-icon/site-icon-functions.php' ); + // If there's a core icon, maybe update the option. If not, fall back to Jetpack's. + if ( ! empty( $url ) && $url !== jetpack_site_icon_url() ) { + // This is the option that is synced with dotcom + Jetpack_Options::update_option( 'site_icon_url', $url ); + } else if ( empty( $url ) && did_action( 'delete_option_site_icon' ) ) { + Jetpack_Options::delete_option( 'site_icon_url' ); + } + } + + function jetpack_admin_ajax_callback() { + // Check for nonce + if ( ! isset( $_REQUEST['adminNonce'] ) || ! wp_verify_nonce( $_REQUEST['adminNonce'], 'jetpack-admin-nonce' ) || ! current_user_can( 'jetpack_manage_modules' ) ) { + wp_die( 'permissions check failed' ); + } + + if ( isset( $_REQUEST['toggleModule'] ) && 'nux-toggle-module' == $_REQUEST['toggleModule'] ) { + $slug = $_REQUEST['thisModuleSlug']; + + if ( ! in_array( $slug, Jetpack::get_available_modules() ) ) { + wp_die( 'That is not a Jetpack module slug' ); + } + + if ( Jetpack::is_module_active( $slug ) ) { + Jetpack::deactivate_module( $slug ); + } else { + Jetpack::activate_module( $slug, false, false ); + } + + $modules = Jetpack_Admin::init()->get_modules(); + echo json_encode( $modules[ $slug ] ); + + exit; + } + + wp_die(); + } + + /* + * Sometimes we need to refresh the data, + * especially if the page is visited via a 'history' + * event like back/forward + */ + function jetpack_admin_ajax_refresh_data() { + // Check for nonce + if ( ! isset( $_REQUEST['adminNonce'] ) || ! wp_verify_nonce( $_REQUEST['adminNonce'], 'jetpack-admin-nonce' ) ) { + wp_die( 'permissions check failed' ); + } + + if ( isset( $_REQUEST['refreshData'] ) && 'refresh' == $_REQUEST['refreshData'] ) { + $modules = Jetpack_Admin::init()->get_modules(); + echo json_encode( $modules ); + exit; + } + + wp_die(); } /** @@ -671,6 +843,67 @@ class Jetpack { } /** + * The callback for the JITM ajax requests. + */ + 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(); + } + } + + /** * If there are any stats that need to be pushed, but haven't been, push them now. */ function __destruct() { @@ -720,11 +953,35 @@ class Jetpack { case 'jetpack_configure_modules' : $caps = array( 'manage_options' ); break; + case 'jetpack_network_admin_page': + case 'jetpack_network_settings_page': + $caps = array( 'manage_network_plugins' ); + break; + case 'jetpack_network_sites_page': + $caps = array( 'manage_sites' ); + break; case 'jetpack_admin_page' : if ( Jetpack::is_development_mode() ) { $caps = array( 'manage_options' ); break; } + + // Don't ever show to subscribers, but allow access to the page if they're trying to unlink. + if ( ! current_user_can( 'edit_posts' ) ) { + if ( isset( $_GET['redirect'] ) && 'sub-unlink' == $_GET['redirect'] ) { + // We need this in order to unlink the user. + $this->admin_page_load(); + } + if ( ! wp_verify_nonce( 'jetpack-unlink' ) ) { + $caps = array( 'do_not_allow' ); + break; + } + } + + if ( ! self::is_active() && ! current_user_can( 'jetpack_connect' ) ) { + $caps = array( 'do_not_allow' ); + break; + } /** * Pass through. If it's not development mode, these should match the admin page. * Let users disconnect if it's development mode, just in case things glitch. @@ -814,7 +1071,7 @@ class Jetpack { * * @filter require_lib_dir */ - function require_lib_dir( $lib_dir ) { + function require_lib_dir() { return JETPACK__PLUGIN_DIR . '_inc/lib'; } @@ -826,6 +1083,61 @@ class Jetpack { public function jetpack_main_network_site_option( $option ) { return network_site_url(); } + /** + * Network Name. + */ + static function network_name( $option = null ) { + global $current_site; + return $current_site->site_name; + } + /** + * 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' ); + } + /** + * Does the network allow admins to add new users. + * @return boolian + */ + static function network_add_new_users( $option = null ) { + return (bool) get_site_option( 'add_new_users' ); + } + /** + * File upload psace left per site in MB. + * -1 means NO LIMIT. + * @return number + */ + static function network_site_upload_space( $option = null ) { + // value in MB + return ( get_site_option( 'upload_space_check_disabled' ) ? -1 : get_space_allowed() ); + } + + /** + * Network allowed file types. + * @return string + */ + static function network_upload_file_types( $option = null ) { + return get_site_option( 'upload_filetypes', 'jpg jpeg png gif' ); + } + + /** + * Maximum file upload size set by the network. + * @return number + */ + static function network_max_upload_file_size( $option = null ) { + // value in KB + return get_site_option( 'fileupload_maxk', 300 ); + } + + /** + * Lets us know if a site allows admins to manage the network. + * @return array + */ + static function network_enable_administration_menus( $option = null ) { + return get_site_option( 'menu_items' ); + } /** * Return whether we are dealing with a multi network setup or not. @@ -881,17 +1193,58 @@ class Jetpack { */ function update_jetpack_main_network_site_option() { // do_action( 'add_option_$option', '$option', '$value-of-the-option' ); + /** + * Fires when the site URL is updated. + * Determines if the site is the main site of a Mulitiste network. + * + * @since 3.3.0 + * + * @param string jetpack_main_network_site. + * @param string network_site_url() Site URL for the "main" site of the current Multisite network. + */ do_action( 'add_option_jetpack_main_network_site', 'jetpack_main_network_site', network_site_url() ); + /** + * Fires when the site URL is updated. + * Determines if the is part of a multi network. + * + * @since 3.3.0 + * + * @param string jetpack_is_main_network. + * @param bool Jetpack::is_multi_network() Is the site part of a multi network. + */ do_action( 'add_option_jetpack_is_main_network', 'jetpack_is_main_network', (string) (bool) Jetpack::is_multi_network() ); + /** + * Fires when the site URL is updated. + * Determines if the site is part of a multisite network. + * + * @since 3.4.0 + * + * @param string jetpack_is_multi_site. + * @param bool is_multisite() Is the site part of a mutlisite network. + */ do_action( 'add_option_jetpack_is_multi_site', 'jetpack_is_multi_site', (string) (bool) is_multisite() ); } + /** + * Triggered after a user updates the network settings via Network Settings Admin Page + * + */ + function update_jetpack_network_settings() { + // Only sync this info for the main network site. + do_action( 'add_option_jetpack_network_name', 'jetpack_network_name', Jetpack::network_name() ); + do_action( 'add_option_jetpack_network_allow_new_registrations', 'jetpack_network_allow_new_registrations', Jetpack::network_allow_new_registrations() ); + do_action( 'add_option_jetpack_network_add_new_users', 'jetpack_network_add_new_users', Jetpack::network_add_new_users() ); + do_action( 'add_option_jetpack_network_site_upload_space', 'jetpack_network_site_upload_space', Jetpack::network_site_upload_space() ); + do_action( 'add_option_jetpack_network_upload_file_types', 'jetpack_network_upload_file_types', Jetpack::network_upload_file_types() ); + do_action( 'add_option_jetpack_network_enable_administration_menus', 'jetpack_network_enable_administration_menus', Jetpack::network_enable_administration_menus() ); + + } /** * Get back if the current site is single user site. * * @return bool */ - public function is_single_user_site() { + public static function is_single_user_site() { $user_query = new WP_User_Query( array( 'blog_id' => get_current_blog_id(), @@ -902,16 +1255,201 @@ 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/template.php' ); + + $filesystem_method = get_filesystem_method(); + if ( $filesystem_method === 'direct' ) { + return 1; + } + + ob_start(); + $filesystem_credentials_are_stored = request_filesystem_credentials( self_admin_url() ); + ob_end_clean(); + if ( $filesystem_credentials_are_stored ) { + return 1; + } + return 0; + } + + /** + * Finds out if a site is using a version control system. + * @return string ( '1' | '0' ) + **/ + public static function is_version_controlled() { + + if ( !class_exists( 'WP_Automatic_Updater' ) ) { + require_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' ); + } + $updater = new WP_Automatic_Updater(); + $is_version_controlled = strval( $updater->is_vcs_checkout( $context = ABSPATH ) ); + // transients should not be empty + if ( empty( $is_version_controlled ) ) { + $is_version_controlled = '0'; + } + return $is_version_controlled; + } + + /** + * Determines whether the current theme supports featured images or not. + * @return string ( '1' | '0' ) + */ + public static function featured_images_enabled() { + return current_theme_supports( 'post-thumbnails' ) ? '1' : '0'; + } + + /* + * Sync back wp_version + */ + public static function get_wp_version() { + global $wp_version; + return $wp_version; + } + + /** + * Keeps wp_version in sync with .com when WordPress core updates + **/ + public static function update_get_wp_version( $update, $meta_data ) { + if ( 'update' === $meta_data['action'] && 'core' === $meta_data['type'] ) { + /** This action is documented in wp-includes/option.php */ + /** + * This triggers the sync for the jetpack version + * See Jetpack_Sync options method for more info. + */ + do_action( 'add_option_jetpack_wp_version', 'jetpack_wp_version', (string) Jetpack::get_wp_version() ); + } + } + + /** + * Triggers a sync of update counts and update details + */ + function sync_update_data() { + // Anytime WordPress saves update data, we'll want to sync update data + add_action( 'set_site_transient_update_plugins', array( 'Jetpack', 'refresh_update_data' ) ); + add_action( 'set_site_transient_update_themes', array( 'Jetpack', 'refresh_update_data' ) ); + add_action( 'set_site_transient_update_core', array( 'Jetpack', 'refresh_update_data' ) ); + // Anytime a connection to jetpack is made, sync the update data + add_action( 'jetpack_site_registered', array( 'Jetpack', 'refresh_update_data' ) ); + // Anytime the Jetpack Version changes, sync the the update data + add_action( 'updating_jetpack_version', array( 'Jetpack', 'refresh_update_data' ) ); + + if ( current_user_can( 'update_core' ) && current_user_can( 'update_plugins' ) && current_user_can( 'update_themes' ) ) { + $this->sync->mock_option( 'updates', array( 'Jetpack', 'get_updates' ) ); + } + + $this->sync->mock_option( 'update_details', array( 'Jetpack', 'get_update_details' ) ); + } + + /** + * Triggers a sync of information specific to the current theme. + */ + function sync_theme_data() { + add_action( 'switch_theme', array( 'Jetpack', 'refresh_theme_data' ) ); + $this->sync->mock_option( 'featured_images_enabled', array( 'Jetpack', 'featured_images_enabled' ) ); + } + + /** + * jetpack_updates is saved in the following schema: + * + * array ( + * 'plugins' => (int) Number of plugin updates available. + * 'themes' => (int) Number of theme updates available. + * 'wordpress' => (int) Number of WordPress core updates available. + * '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() { + $update_data = wp_get_update_data(); + + // Stores the individual update counts as well as the total count. + if ( isset( $update_data['counts'] ) ) { + $updates = $update_data['counts']; + } + + // If we need to update WordPress core, let's find the latest version number. + if ( ! empty( $updates['wordpress'] ) ) { + $cur = get_preferred_from_update_core(); + if ( isset( $cur->response ) && 'upgrade' === $cur->response ) { + $updates['wp_update_version'] = $cur->current; + } + } + return isset( $updates ) ? $updates : array(); + } + + public static function get_update_details() { + $update_details = array( + 'update_core' => get_site_transient( 'update_core' ), + 'update_plugins' => get_site_transient( 'update_plugins' ), + 'update_themes' => get_site_transient( 'update_themes' ), + ); + return $update_details; + } + + public static function refresh_update_data() { + if ( current_user_can( 'update_core' ) && current_user_can( 'update_plugins' ) && current_user_can( 'update_themes' ) ) { + /** + * Fires whenever the amount of updates needed for a site changes. + * Syncs an array that includes the number of theme, plugin, and core updates available, as well as the latest core version available. + * + * @since 3.7.0 + * + * @param string jetpack_updates + * @param array Update counts calculated by Jetpack::get_updates + */ + do_action( 'add_option_jetpack_updates', 'jetpack_updates', Jetpack::get_updates() ); + } + /** + * Fires whenever the amount of updates needed for a site changes. + * Syncs an array of core, theme, and plugin data, and which of each is out of date + * + * @since 3.7.0 + * + * @param string jetpack_update_details + * @param array Update details calculated by Jetpack::get_update_details + */ + do_action( 'add_option_jetpack_update_details', 'jetpack_update_details', Jetpack::get_update_details() ); + } + + public static function refresh_theme_data() { + /** + * Fires whenever a theme change is made. + * + * @since 3.8.1 + * + * @param string featured_images_enabled + * @param boolean Whether featured images are enabled or not + */ + do_action( 'add_option_jetpack_featured_images_enabled', 'jetpack_featured_images_enabled', Jetpack::featured_images_enabled() ); + } + + /** * Invalides the transient as well as triggers the update of the mock option. * * @return null */ function is_single_user_site_invalidate() { - do_action( 'update_option_jetpack_single_user_site', 'jetpack_single_user_site', (bool) $this->is_single_user_site() ); + /** + * Fires when a user is added or removed from a site. + * Determines if the site is a single user site. + * + * @since 3.4.0 + * + * @param string jetpack_single_user_site. + * @param bool Jetpack::is_single_user_site() Is the current site a single user site. + */ + do_action( 'update_option_jetpack_single_user_site', 'jetpack_single_user_site', (bool) Jetpack::is_single_user_site() ); } - - /** * Is Jetpack active? */ @@ -932,6 +1470,15 @@ class Jetpack { elseif ( site_url() && false === strpos( site_url(), '.' ) ) { $development_mode = true; } + /** + * Filters Jetpack's development mode. + * + * @see http://jetpack.me/support/development-mode/ + * + * @since 2.2.1 + * + * @param bool $development_mode Is Jetpack's development mode active. + */ return apply_filters( 'jetpack_development_mode', $development_mode ); } @@ -944,15 +1491,34 @@ class Jetpack { public static function show_development_mode_notice() { if ( Jetpack::is_development_mode() ) { if ( defined( 'JETPACK_DEV_DEBUG' ) && JETPACK_DEV_DEBUG ) { - $notice = __( 'In Development Mode, via the JETPACK_DEV_DEBUG constant being defined in wp-config.php or elsewhere.', 'jetpack' ); + $notice = sprintf( + /* translators: %s is a URL */ + __( 'In <a href="%s" target="_blank">Development Mode</a>, via the JETPACK_DEV_DEBUG constant being defined in wp-config.php or elsewhere.', 'jetpack' ), + 'http://jetpack.me/support/development-mode/' + ); } elseif ( site_url() && false === strpos( site_url(), '.' ) ) { - $notice = __( 'In Development Mode, via site URL lacking a dot (e.g. http://localhost).', 'jetpack' ); + $notice = sprintf( + /* translators: %s is a URL */ + __( 'In <a href="%s" target="_blank">Development Mode</a>, via site URL lacking a dot (e.g. http://localhost).', 'jetpack' ), + 'http://jetpack.me/support/development-mode/' + ); } else { - $notice = __( 'In Development Mode, via the jetpack_development_mode filter.', 'jetpack' ); + $notice = sprintf( + /* translators: %s is a URL */ + __( 'In <a href="%s" target="_blank">Development Mode</a>, via the jetpack_development_mode filter.', 'jetpack' ), + 'http://jetpack.me/support/development-mode/' + ); } - $output = '<div class="error"><p>' . $notice . '</p></div>'; - echo $output; + 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() ) { + /* 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.me/contact-support/beta-group/' ); + + echo '<div class="updated" style="border-color: #f0821e;"><p>' . $notice . '</p></div>'; } } @@ -1032,6 +1598,9 @@ 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://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 ); } /** @@ -1085,13 +1654,16 @@ class Jetpack { * Loads the currently active modules. */ public static function load_modules() { - if( !self::is_active() && !self::is_development_mode() ) { - return; + if ( ! self::is_active() && !self::is_development_mode() ) { + if ( ! is_multisite() || ! get_site_option( 'jetpack_protect_active' ) ) { + return; + } } $version = Jetpack_Options::get_option( 'version' ); if ( ! $version ) { $version = $old_version = JETPACK__VERSION . ':' . time(); + /** This action is documented in class.jetpack.php */ do_action( 'updating_jetpack_version', $version, false ); Jetpack_Options::update_options( compact( 'version', 'old_version' ) ); } @@ -1140,9 +1712,20 @@ class Jetpack { } require Jetpack::get_module_path( $module ); + /** + * Fires when a specific module is loaded. + * The dynamic part of the hook, $module, is the module slug. + * + * @since 1.1.0 + */ do_action( 'jetpack_module_loaded_' . $module ); } + /** + * Fires when all the modules are loaded. + * + * @since 1.1.0 + */ 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. @@ -1156,6 +1739,13 @@ class Jetpack { * @return null */ public function check_rest_api_compat() { + /** + * Filters the list of REST API compat files to be included. + * + * @since 2.2.5 + * + * @param array $args Array of REST API compat files to include. + */ $_jetpack_rest_api_compat_includes = apply_filters( 'jetpack_rest_api_compat', array() ); if ( function_exists( 'bbpress' ) ) @@ -1185,7 +1775,65 @@ class Jetpack { sort( $active_plugins ); - return $active_plugins; + return array_unique( $active_plugins ); + } + + /** + * Gets and parses additional plugin data to send with the heartbeat data + * + * @since 3.8.1 + * + * @return array Array of plugin data + */ + public static function get_parsed_plugin_data() { + if ( ! function_exists( 'get_plugins' ) ) { + require_once( ABSPATH . 'wp-admin/includes/plugin.php' ); + } + $all_plugins = get_plugins(); + $active_plugins = Jetpack::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'], + ); + } + + return $plugins; + } + + /** + * Gets and parses theme data to send with the heartbeat data + * + * @since 3.8.1 + * + * @return array Array of theme data + */ + public static function get_parsed_theme_data() { + $all_themes = wp_get_themes( array( 'allowed' => true ) ); + $header_keys = array( 'Name', 'Author', 'Version', 'ThemeURI', 'AuthorURI', 'Status', 'Tags' ); + + $themes = array(); + foreach ( $all_themes as $slug => $theme_data ) { + $theme_headers = array(); + foreach ( $header_keys as $header_key ) { + $theme_headers[ $header_key ] = $theme_data->get( $header_key ); + } + + $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 + ); + } + + return $themes; } /** @@ -1222,6 +1870,13 @@ class Jetpack { } } + /** + * Allow the addition of Open Graph Meta Tags to all pages. + * + * @since 2.0.3 + * + * @param bool false Should Open Graph Meta tags be added. Default to false. + */ if ( apply_filters( 'jetpack_enable_open_graph', false ) ) { require_once JETPACK__PLUGIN_DIR . 'functions.opengraph.php'; } @@ -1248,6 +1903,13 @@ class Jetpack { } } + /** + * Allow Twitter Card Meta tags to be disabled. + * + * @since 2.6.0 + * + * @param bool true Should Twitter Card Meta tags be disabled. Default to true. + */ if ( apply_filters( 'jetpack_disable_twitter_cards', true ) ) { require_once JETPACK__PLUGIN_DIR . 'class.jetpack-twitter-cards.php'; } @@ -1289,6 +1951,11 @@ class Jetpack { return; } + /** + * Fires before a security report is created. + * + * @since 3.4.0 + */ do_action( 'jetpack_security_report' ); Jetpack_Options::update_option( 'security_report', self::$security_report ); @@ -1313,7 +1980,7 @@ class Jetpack { } if( !function_exists( 'get_plugin_data' ) ) { - include( ABSPATH . 'wp-admin/includes/plugin.php' ); + include( ABSPATH . 'wp-admin/includes/plugin.php' ); } //Get rid of any non-allowed args @@ -1514,6 +2181,7 @@ class Jetpack { $jetpack_old_version = Jetpack_Options::get_option( 'version' ); // [sic] if ( ! $jetpack_old_version ) { $jetpack_old_version = $version = $old_version = '1.1:' . time(); + /** This action is documented in class.jetpack.php */ do_action( 'updating_jetpack_version', $version, false ); Jetpack_Options::update_options( compact( 'version', 'old_version' ) ); } @@ -1541,6 +2209,7 @@ class Jetpack { } $new_version = JETPACK__VERSION . ':' . time(); + /** This action is documented in class.jetpack.php */ do_action( 'updating_jetpack_version', $new_version, $jetpack_old_version ); Jetpack_Options::update_options( array( @@ -1594,14 +2263,23 @@ class Jetpack { } } - $modules = apply_filters( 'jetpack_get_available_modules', $modules, $min_version, $max_version ); + /** + * Filters the array of modules available to be activated. + * + * @since 2.4.0 + * + * @param array $modules Array of available modules. + * @param string $min_version Minimum version number required to use modules. + * @param string $max_version Maximum version number required to use modules. + */ + $mods = apply_filters( 'jetpack_get_available_modules', $modules, $min_version, $max_version ); if ( ! $min_version && ! $max_version ) { - return array_keys( $modules ); + return array_keys( $mods ); } $r = array(); - foreach ( $modules as $slug => $introduced ) { + foreach ( $mods as $slug => $introduced ) { if ( $min_version && version_compare( $min_version, $introduced, '>=' ) ) { continue; } @@ -1639,6 +2317,15 @@ class Jetpack { break; } } + /** + * Filters the array of default modules. + * + * @since 2.5.0 + * + * @param array $return Array of default modules. + * @param string $min_version Minimum version number required to use modules. + * @param string $max_version Maximum version number required to use modules. + */ return apply_filters( 'jetpack_get_default_modules', $return, $min_version, $max_version ); } @@ -1743,19 +2430,20 @@ class Jetpack { */ public static function get_module( $module ) { $headers = array( - 'name' => 'Module Name', - 'description' => 'Module Description', - 'jumpstart_desc' => 'Jumpstart Description', - 'sort' => 'Sort Order', - 'recommendation_order' => 'Recommendation Order', - 'introduced' => 'First Introduced', - 'changed' => 'Major Changes In', - 'deactivate' => 'Deactivate', - 'free' => 'Free', - 'requires_connection' => 'Requires Connection', - 'auto_activate' => 'Auto Activate', - 'module_tags' => 'Module Tags', - 'feature' => 'Feature', + 'name' => 'Module Name', + 'description' => 'Module Description', + 'jumpstart_desc' => 'Jumpstart Description', + 'sort' => 'Sort Order', + 'recommendation_order' => 'Recommendation Order', + 'introduced' => 'First Introduced', + 'changed' => 'Major Changes In', + 'deactivate' => 'Deactivate', + 'free' => 'Free', + 'requires_connection' => 'Requires Connection', + 'auto_activate' => 'Auto Activate', + 'module_tags' => 'Module Tags', + 'feature' => 'Feature', + 'additional_search_queries' => 'Additional Search Queries', ); $file = Jetpack::get_module_path( Jetpack::get_module_slug( $module ) ); @@ -1765,9 +2453,6 @@ class Jetpack { return false; } - $mod['jumpstart_desc'] = _x( $mod['jumpstart_desc'], 'Jumpstart Description', 'jetpack' ); - $mod['name'] = _x( $mod['name'], 'Module Name', 'jetpack' ); - $mod['description'] = _x( $mod['description'], 'Module Description', 'jetpack' ); $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'] ); @@ -1796,31 +2481,45 @@ class Jetpack { } /** - * Filter the feature array on a module + * 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. * - * @since 3.5 + * @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 - * @param array $mod All the currently assembled module data + * '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. + * @param array $mod All the currently assembled module data. */ $mod['feature'] = apply_filters( 'jetpack_module_feature', $mod['feature'], $module, $mod ); - return $mod; + /** + * Filter the returned data about a module. + * + * This filter allows overriding any info about Jetpack modules. It is dangerous, + * so please be careful. + * + * @since 3.6.0 + * + * @param array $mod The details of the requested module. + * @param string $module The slug of the module, e.g. sharedaddy + * @param string $file The path to the module source file. + */ + return apply_filters( 'jetpack_get_module', $mod, $module, $file ); } /** * 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 + $file_name = basename( $file ); $file_data_option = Jetpack_Options::get_option( 'file_data', array() ); - $key = md5( $file . serialize( $headers ) ); + $key = md5( $file_name . serialize( $headers ) ); $refresh_cache = is_admin() && isset( $_GET['page'] ) && 'jetpack' === substr( $_GET['page'], 0, 7 ); // If we don't need to refresh the cache, and already have the value, short-circuit! @@ -1856,6 +2555,12 @@ class Jetpack { } else { $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 ( ! in_array( 'protect', $active ) && is_multisite() && get_site_option( 'jetpack_protect_active' ) ) { + $active[] = 'protect'; + } + return array_unique( $active ); } @@ -1940,6 +2645,15 @@ class Jetpack { exit; } + /** + * Fires before default modules are activated. + * + * @since 1.9.0 + * + * @param string $min_version Minimum version number required to use modules. + * @param string $max_version Maximum version number required to use modules. + * @param array $other_modules Array of other modules to activate alongside the default modules. + */ do_action( 'jetpack_before_activate_default_modules', $min_version, $max_version, $other_modules ); // Check each module for fatal errors, a la wp-admin/plugins.php::activate before activating @@ -1981,6 +2695,13 @@ class Jetpack { Jetpack::state( 'module', $module ); ob_start(); require $file; + /** + * Fires when a specific module is activated. + * + * @since 1.9.0 + * + * @param string $module Module slug. + */ do_action( 'jetpack_activate_module', $module ); $active[] = $module; $state = in_array( $module, $other_modules ) ? 'reactivated_modules' : 'activated_modules'; @@ -1997,10 +2718,28 @@ class Jetpack { Jetpack::state( 'error', false ); Jetpack::state( 'module', false ); Jetpack::catch_errors( false ); + /** + * Fires when default modules are activated. + * + * @since 1.9.0 + * + * @param string $min_version Minimum version number required to use modules. + * @param string $max_version Maximum version number required to use modules. + * @param array $other_modules Array of other modules to activate alongside the default modules. + */ do_action( 'jetpack_activate_default_modules', $min_version, $max_version, $other_modules ); } public static function activate_module( $module, $exit = true, $redirect = true ) { + /** + * Fires before a module is activated. + * + * @since 2.6.0 + * + * @param string $module Module slug. + * @param bool $exit Should we exit after the module has been activated. Default to true. + * @param bool $redirect Should the user be redirected after module activation? Default to true. + */ do_action( 'jetpack_pre_activate_module', $module, $exit, $redirect ); $jetpack = Jetpack::init(); @@ -2048,6 +2787,7 @@ class Jetpack { Jetpack::catch_errors( true ); ob_start(); require Jetpack::get_module_path( $module ); + /** This action is documented in class.jetpack.php */ do_action( 'jetpack_activate_module', $module ); $active[] = $module; Jetpack_Options::update_option( 'active_modules', array_unique( $active ) ); @@ -2076,12 +2816,27 @@ class Jetpack { } function activate_module_actions( $module ) { + /** + * 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 ); $this->sync->sync_all_module_options( $module ); } public static function deactivate_module( $module ) { + /** + * Fires when a module is deactivated. + * + * @since 1.9.0 + * + * @param string $module Module slug. + */ do_action( 'jetpack_pre_deactivate_module', $module ); $jetpack = Jetpack::init(); @@ -2089,6 +2844,14 @@ class Jetpack { $active = Jetpack::get_active_modules(); $new = array_filter( array_diff( $active, (array) $module ) ); + /** + * 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 ); // A flag for Jump Start so it's not shown again. @@ -2129,6 +2892,11 @@ class Jetpack { add_action( 'jetpack_module_configuration_screen_' . $module, $method ); } + public static function module_configuration_activation_screen( $module, $method ) { + $module = Jetpack::get_module_slug( $module ); + add_action( 'display_activate_module_setting_' . $module, $method ); + } + /* Installation */ public static function bail_on_activation( $message, $deactivate = true ) { @@ -2213,6 +2981,7 @@ p { if ( ! Jetpack_Options::get_option( 'version' ) ) { $version = $old_version = JETPACK__VERSION . ':' . time(); + /** This action is documented in class.jetpack.php */ do_action( 'updating_jetpack_version', $version, false ); Jetpack_Options::update_options( compact( 'version', 'old_version' ) ); } @@ -2265,6 +3034,25 @@ p { Jetpack_Options::update_option( 'activated', 4 ); } + $jetpack_unique_connection = Jetpack_Options::get_option( 'unique_connection' ); + // Check then record unique disconnection if site has never been disconnected previously + if ( -1 == $jetpack_unique_connection['disconnected'] ) { + $jetpack_unique_connection['disconnected'] = 1; + } + else { + if ( 0 == $jetpack_unique_connection['disconnected'] ) { + //track unique disconnect + $jetpack = Jetpack::init(); + + $jetpack->stat( 'connections', 'unique-disconnect' ); + $jetpack->do_stats( 'server_side' ); + } + // increment number of times disconnected + $jetpack_unique_connection['disconnected'] += 1; + } + + Jetpack_Options::update_option( 'unique_connection', $jetpack_unique_connection ); + // Disable the Heartbeat cron Jetpack_Heartbeat::init()->deactivate(); } @@ -2299,6 +3087,21 @@ p { * Attempts Jetpack registration. If it fail, a state flag is set: @see ::admin_page_load() */ public static function try_registration() { + // 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 ), + ) ); + foreach ( $domains_to_check as $domain ) { + $result = Jetpack_Data::is_usable_domain( $domain ); + if ( is_wp_error( $result ) ) { + return $result; + } + } + } + $result = Jetpack::register(); // If there was an error with registration and the site was not registered, record this so we can show a message. @@ -2315,7 +3118,8 @@ p { * [Everyone Loves a Log!](https://www.youtube.com/watch?v=2C7mNr5WMjA) */ public static function log( $code, $data = null ) { - $log = Jetpack_Options::get_option( 'log', array() ); + // only grab the latest 200 entries + $log = array_slice( Jetpack_Options::get_option( 'log', array() ), -199, 199 ); // Append our event to the log $log_entry = array( @@ -2336,14 +3140,67 @@ p { Jetpack_Options::update_option( 'log', $log ); } + /** + * Fires when Jetpack logs an internal event. + * + * @since 3.0.0 + * + * @param array $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. + * } + */ do_action( 'jetpack_log_entry', $log_entry ); } /** * Get the internal event log. + * + * @param $event (string) - only return the specific log events + * @param $num (int) - get specific number of latest results, limited to 200 + * + * @return array of log events || WP_Error for invalid params */ - public static function get_log() { - return Jetpack_Options::get_option( 'log', array() ); + public static function get_log( $event = false, $num = false ) { + if ( $event && ! is_string( $event ) ) { + return new WP_Error( __( 'First param must be string or empty', 'jetpack' ) ); + } + + if ( $num && ! is_numeric( $num ) ) { + return new WP_Error( __( 'Second param must be numeric or empty', 'jetpack' ) ); + } + + $entire_log = Jetpack_Options::get_option( 'log', array() ); + + // If nothing set - act as it did before, otherwise let's start customizing the output + if ( ! $num && ! $event ) { + return $entire_log; + } else { + $entire_log = array_reverse( $entire_log ); + } + + $custom_log_output = array(); + + if ( $event ) { + foreach ( $entire_log as $log_event ) { + if ( $event == $log_event[ 'code' ] ) { + $custom_log_output[] = $log_event; + } + } + } else { + $custom_log_output = $entire_log; + } + + if ( $num ) { + $custom_log_output = array_slice( $custom_log_output, 0, $num ); + } + + return $custom_log_output; } /** @@ -2357,6 +3214,30 @@ p { } } + /** + * Return stat data for WPCOM sync + */ + function get_stat_data() { + $heartbeat_data = Jetpack_Heartbeat::generate_stats_array(); + $additional_data = $this->get_additional_stat_data(); + + return json_encode( array_merge( $heartbeat_data, $additional_data ) ); + } + + /** + * Get additional stat data to sync to WPCOM + */ + 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"] = count_users(); + $return["{$prefix}site-count"] = 0; + if ( function_exists( 'get_blog_count' ) ) { + $return["{$prefix}site-count"] = get_blog_count(); + } + return $return; + } + /* Admin Pages */ function admin_init() { @@ -2390,6 +3271,9 @@ p { // Show the notice on the Dashboard only for now add_action( 'load-index.php', array( $this, 'prepare_manage_jetpack_notice' ) ); + + // Identity crisis notices + add_action( 'jetpack_notices', array( $this, 'alert_identity_crisis' ) ); } // If the plugin has just been disconnected from WP.com, show the survey notice @@ -2397,8 +3281,6 @@ p { add_action( 'jetpack_notices', array( $this, 'disconnect_survey_notice' ) ); } - // add_action( 'admin_notices', array( $this, 'alert_identity_crisis' ) ); - if ( current_user_can( 'manage_options' ) && 'ALWAYS' == JETPACK_CLIENT__HTTPS && ! self::permit_ssl() ) { add_action( 'admin_notices', array( $this, 'alert_required_ssl_fail' ) ); } @@ -2414,6 +3296,9 @@ p { // Kick off synchronization of user role when it changes add_action( 'set_user_role', array( $this, 'user_role_change' ) ); } + + // Jetpack Manage Activation Screen from .com + Jetpack::module_configuration_activation_screen( 'manage', array( $this, 'manage_activate_screen' ) ); } function admin_body_class( $admin_body_class = '' ) { @@ -2448,6 +3333,9 @@ p { add_action( 'admin_notices', array( $this, 'admin_jetpack_manage_notice' ) ); } + function manage_activate_screen() { + include ( JETPACK__PLUGIN_DIR . 'modules/manage/activate-admin.php' ); + } /** * Sometimes a plugin can activate without causing errors, but it will cause errors on the next page load. * This function artificially throws errors for such cases (whitelisted). @@ -2694,16 +3582,16 @@ p { function admin_head() { if ( isset( $_GET['configure'] ) && Jetpack::is_module( $_GET['configure'] ) && current_user_can( 'manage_options' ) ) + /** This action is documented in class.jetpack-admin-page.php */ do_action( 'jetpack_module_configuration_head_' . $_GET['configure'] ); } function admin_banner_styles() { - global $wp_styles; - $min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min'; wp_enqueue_style( 'jetpack', plugins_url( "css/jetpack-banners{$min}.css", JETPACK__PLUGIN_FILE ), false, JETPACK__VERSION . '-20121016' ); - $wp_styles->add_data( 'jetpack', 'rtl', true ); + wp_style_add_data( 'jetpack', 'rtl', 'replace' ); + wp_style_add_data( 'jetpack', 'suffix', $min ); } function admin_scripts() { @@ -2728,6 +3616,7 @@ p { return array_merge( $jetpack_home, array( 'settings' => sprintf( '<a href="%s">%s</a>', Jetpack::admin_url( 'page=jetpack_modules' ), __( 'Settings', 'jetpack' ) ) ), + array( 'support' => sprintf( '<a href="%s">%s</a>', Jetpack::admin_url( 'page=jetpack-debugger '), __( 'Support', 'jetpack' ) ) ), $actions ); } @@ -2750,7 +3639,7 @@ p { <a class="jp-banner__dismiss" href="<?php echo esc_url( $dismiss_and_deactivate_url ); ?>" title="<?php esc_attr_e( 'Dismiss this notice and deactivate Jetpack.', 'jetpack' ); ?>"></a> <?php if ( in_array( Jetpack_Options::get_option( 'activated' ) , array( 1, 2, 3 ) ) ) : ?> <div class="jp-banner__content is-connection"> - <h4><?php _e( 'Your Jetpack is almost ready!', 'jetpack' ); ?></h4> + <h2><?php _e( 'Your Jetpack is almost ready!', 'jetpack' ); ?></h2> <p><?php _e( 'Connect now to enable features like Stats, Likes, and Social Sharing.', 'jetpack' ); ?></p> </div> <div class="jp-banner__action-container is-connection"> @@ -2758,7 +3647,7 @@ p { </div> <?php else : ?> <div class="jp-banner__content"> - <h4><?php _e( 'Jetpack is installed!', 'jetpack' ) ?></h4> + <h2><?php _e( 'Jetpack is installed!', 'jetpack' ) ?></h2> <p><?php _e( 'It\'s ready to bring awesome, WordPress.com cloud-powered features to your site.', 'jetpack' ) ?></p> </div> <div class="jp-banner__action-container"> @@ -2802,7 +3691,7 @@ p { <div id="message" class="updated jetpack-message jp-banner is-opt-in" style="display:block !important;"> <a class="jp-banner__dismiss" href="<?php echo esc_url( $opt_out_url ); ?>" title="<?php esc_attr_e( 'Dismiss this notice for now.', 'jetpack' ); ?>"></a> <div class="jp-banner__content"> - <h4><?php esc_html_e( 'New in Jetpack: Centralized Site Management', 'jetpack' ); ?></h4> + <h2><?php esc_html_e( 'New in Jetpack: Centralized Site Management', 'jetpack' ); ?></h2> <p><?php printf( __( 'Manage multiple sites from one dashboard at wordpress.com/sites. Enabling allows all existing, connected Administrators to modify your site from WordPress.com. <a href="%s" target="_blank">Learn More</a>.', 'jetpack' ), 'http://jetpack.me/support/site-management' ); ?></p> </div> <div class="jp-banner__action-container is-opt-in"> @@ -2855,6 +3744,13 @@ p { if( ! Jetpack_Options::get_option( 'public' ) ) return false; + /** + * Should the Jetpack Remote Site Management notice be displayed. + * + * @since 3.3.0 + * + * @param bool ! self::is_module_active( 'manage' ) Is the Manage module inactive. + */ return apply_filters( 'can_display_jetpack_manage_notice', ! self::is_module_active( 'manage' ) ); } @@ -2862,7 +3758,7 @@ p { ?> <div id="message" class="updated jetpack-message"> <div class="squeezer"> - <h4><?php _e( '<strong>Jetpack is activated!</strong> Each site on your network must be connected individually by an admin on that site.', 'jetpack' ) ?></h4> + <h2><?php _e( '<strong>Jetpack is activated!</strong> Each site on your network must be connected individually by an admin on that site.', 'jetpack' ) ?></h2> </div> </div> <?php @@ -2889,7 +3785,7 @@ p { } return '<br /><br />' . sprintf( - __( 'Jetpack now includes Jetpack Comments, which enables your visitors to use their WordPress.com, Twitter, or Facebook accounts when commenting on your site. To activate Jetpack Comments, <a href="%s">%s</a>.', 'jetpack' ), + __( 'Jetpack now includes Comments, which enables your visitors to use their WordPress.com, Twitter, or Facebook accounts when commenting on your site. To activate Comments, <a href="%s">%s</a>.', 'jetpack' ), wp_nonce_url( Jetpack::admin_url( array( @@ -2912,14 +3808,15 @@ p { <div class="wrap"> <div id="message" class="jetpack-message stay-visible"> <div class="squeezer"> - <h4> + <h2> <?php _e( 'You have successfully disconnected Jetpack.', 'jetpack' ); ?> <br /> <?php echo sprintf( - __( 'Would you tell us why? Just <a href="%s">answering two simple questions</a> would help us improve Jetpack.', 'jetpack' ), - 'https://jetpack.me/survey-disconnected/" target="_blank' + __( 'Would you tell us why? Just <a href="%1$s" target="%2$s">answering two simple questions</a> would help us improve Jetpack.', 'jetpack' ), + 'https://jetpack.me/survey-disconnected/', + '_blank' ); ?> - </h4> + </h2> </div> </div> </div> @@ -3003,6 +3900,10 @@ p { $client_server->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(); @@ -3077,13 +3978,25 @@ p { 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' ); - wp_safe_redirect( Jetpack::admin_url() ); + if ( 'sub-unlink' == $redirect ) { + wp_safe_redirect( admin_url() ); + } else { + wp_safe_redirect( Jetpack::admin_url( array( 'page' => $redirect ) ) ); + } 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'] ) ); } } @@ -3200,7 +4113,7 @@ p { case 'verify_secrets_missing' : case 'verify_secrets_mismatch' : $error = esc_html( $error ); - $this->error = sprintf( __( '<strong>Your Jetpack has a glitch.</strong> Something went wrong that’s never supposed to happen. Guess you’re just lucky: %s', 'jetpack' ), "<code>$error</code>" ); + $this->error = sprintf( __( '<strong>Your Jetpack has a glitch.</strong> We’re sorry for the inconvenience. Please try again later, if the issue continues please contact support with this message: %s', 'jetpack' ), "<code>$error</code>" ); if ( ! Jetpack::is_active() ) { $this->error .= '<br />'; $this->error .= sprintf( __( 'Try connecting again.', 'jetpack' ) ); @@ -3328,6 +4241,17 @@ p { $user = wp_get_current_user(); $this->message = sprintf( __( '<strong>You have unlinked your account (%s) from WordPress.com.</strong>', 'jetpack' ), $user->user_login ); break; + + case 'switch_master' : + global $current_user; + $is_master_user = $current_user->ID == Jetpack_Options::get_option( 'master_user' ); + $master_userdata = get_userdata( Jetpack_Options::get_option( 'master_user' ) ); + if ( $is_master_user ) { + $this->message = __( 'You have successfully set yourself as Jetpack’s primary user.', 'jetpack' ); + } else { + $this->message = sprintf( _x( 'You have successfully set %s as Jetpack’s primary user.', '%s is a username', 'jetpack' ), $master_userdata->user_login ); + } + break; } $deactivated_plugins = Jetpack::state( 'deactivated_plugins' ); @@ -3376,6 +4300,12 @@ p { } if ( isset( $_GET['configure'] ) && Jetpack::is_module( $_GET['configure'] ) && current_user_can( 'manage_options' ) ) { + /** + * Fires when a module configuration page is loaded. + * The dynamic part of the hook is the configure parameter from the URL. + * + * @since 1.1.0 + */ do_action( 'jetpack_module_configuration_load_' . $_GET['configure'] ); } @@ -3388,7 +4318,7 @@ p { ?> <div id="message" class="jetpack-message jetpack-err"> <div class="squeezer"> - <h4><?php echo wp_kses( $this->error, array( 'code' => true, 'strong' => true, 'br' => true, 'b' => true ) ); ?></h4> + <h2><?php echo wp_kses( $this->error, array( 'code' => true, 'strong' => true, 'br' => true, 'b' => true ) ); ?></h2> <?php if ( $desc = Jetpack::state( 'error_description' ) ) : ?> <p><?php echo esc_html( stripslashes( $desc ) ); ?></p> <?php endif; ?> @@ -3401,7 +4331,7 @@ p { ?> <div id="message" class="jetpack-message"> <div class="squeezer"> - <h4><?php echo wp_kses( $this->message, array( 'strong' => array(), 'a' => array( 'href' => true ), 'br' => true ) ); ?></h4> + <h2><?php echo wp_kses( $this->message, array( 'strong' => array(), 'a' => array( 'href' => true ), 'br' => true ) ); ?></h2> </div> </div> <?php @@ -3426,7 +4356,7 @@ p { ?> <div id="message" class="jetpack-message jetpack-err"> <div class="squeezer"> - <h4><strong><?php esc_html_e( 'Is this site private?', 'jetpack' ); ?></strong></h4><br /> + <h2><strong><?php esc_html_e( 'Is this site private?', 'jetpack' ); ?></strong></h2><br /> <p><?php echo wp_kses( wptexturize( @@ -3516,7 +4446,7 @@ p { * @return bool If it worked. */ static function do_server_side_stat( $args ) { - $response = wp_remote_get( self::build_stats_url( $args ) ); + $response = wp_remote_get( esc_url_raw( self::build_stats_url( $args ) ) ); if ( is_wp_error( $response ) ) return false; @@ -3539,6 +4469,13 @@ p { 'rand' => md5( mt_rand( 0, 999 ) . time() ), ); $args = wp_parse_args( $args, $defaults ); + /** + * Filter the URL used as the Stats tracking pixel. + * + * @since 2.3.2 + * + * @param string $url Base URL used as the Stats tracking pixel. + */ $base_url = apply_filters( 'jetpack_stats_base_url', set_url_scheme( 'http://pixel.wp.com/g.gif' ) @@ -3579,7 +4516,7 @@ p { } function build_connect_url( $raw = false, $redirect = false ) { - if ( ! Jetpack_Options::get_option( 'blog_token' ) ) { + if ( ! Jetpack_Options::get_option( 'blog_token' ) || ! Jetpack_Options::get_option( 'id' ) ) { $url = Jetpack::nonce_url_no_esc( Jetpack::admin_url( 'action=register' ), 'jetpack-register' ); if( is_network_admin() ) { $url = add_query_arg( 'is_multisite', network_admin_url( @@ -3670,6 +4607,21 @@ p { } } 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; case 'jetpack-manage-opt-in': if ( check_admin_referer( 'jetpack_manage_banner_opt_in' ) ) { // This makes sure that we are redirect to jetpack home so that we can see the Success Message. @@ -3700,185 +4652,6 @@ p { } } - /** - * This is the old pre-3.0 admin page. It is replaced by the Jetpack_Admin class. - * Tentatively left here for comparison purposes. - */ - function admin_page() { - global $current_user; - - $is_connected = Jetpack::is_active(); - $user_token = Jetpack_Data::get_access_token( $current_user->ID ); - $is_user_connected = $user_token && ! is_wp_error( $user_token ); - $is_master_user = $current_user->ID == Jetpack_Options::get_option( 'master_user' ); - - $can_reconnect_jpms = true; - if( is_plugin_active_for_network( 'jetpack/jetpack.php' ) ) { - $jpms = Jetpack_Network::init(); - $can_reconnect_jpms = ( $jpms->get_option( 'sub-site-connection-override' ) ) ? 1: 0; - } - - - - ?> - <div class="wrap" id="jetpack-settings"> - - <div id="jp-header"<?php if ( $is_connected ) : ?> class="small"<?php endif; ?>> - <div id="jp-clouds"> - <?php if ( $is_connected && $can_reconnect_jpms ) : ?> - <div id="jp-disconnectors"> - <?php if ( current_user_can( 'jetpack_disconnect' ) ) : ?> - <div id="jp-disconnect" class="jp-disconnect"> - <a href="<?php echo wp_nonce_url( Jetpack::admin_url( 'action=disconnect' ), 'jetpack-disconnect' ); ?>" onclick="return confirm('<?php echo htmlspecialchars( __('Are you sure you want to disconnect from WordPress.com?', 'jetpack'), ENT_QUOTES ); ?>');"><div class="deftext"><?php _e( 'Connected to WordPress.com', 'jetpack' ); ?></div><div class="hovertext"><?php _e( 'Disconnect from WordPress.com', 'jetpack' ) ?></div></a> - </div> - <?php endif; ?> - <?php if ( $is_user_connected && ! $is_master_user ) : ?> - <div id="jp-unlink" class="jp-disconnect"> - <a href="<?php echo wp_nonce_url( Jetpack::admin_url( 'action=unlink' ), 'jetpack-unlink' ); ?>"><div class="deftext"><?php _e( 'User linked to WordPress.com', 'jetpack' ); ?></div><div class="hovertext"><?php _e( 'Unlink user from WordPress.com', 'jetpack' ) ?></div></a> - </div> - <?php endif; ?> - </div> - <?php endif; ?> - <h3><?php _e( 'Jetpack by WordPress.com', 'jetpack' ) ?></h3> - <?php if ( ! $is_connected ) : ?> - <div id="jp-notice"> - <p><?php _e( 'Jetpack supercharges your self-hosted WordPress site with the awesome cloud power of WordPress.com.', 'jetpack' ); ?></p> - </div> - <?php endif; ?> - </div> - </div> - - <h2 style="display: none"></h2> <!-- For WP JS message relocation --> - - <?php Jetpack::init()->load_view( 'admin/network-activated-notice.php' ); ?> - - <?php do_action( 'jetpack_notices' ) ?> - - <?php - // If the connection has not been made then show the marketing text. - if( !$can_reconnect_jpms && !$is_connected ) { - ?> - <div id="message" class="updated jetpack-message jp-banner jp-multisite" style="display:block !important"> - <div class="jp-banner__content"> - <h4><?php _e( 'To use Jetpack please contact your WordPress administrator to connect it for you.', 'jetpack' ) ?></h4> - </div> - </div> <?php - } - if ( ! Jetpack::is_development_mode() && $can_reconnect_jpms ) : - ?> - <?php if ( ! $is_connected ) : - $dismiss_and_deactivate_url = wp_nonce_url( Jetpack::admin_url( '?page=jetpack&jetpack-notice=dismiss' ), 'jetpack-deactivate' ); - ?> - <div id="message" class="updated jetpack-message jp-banner" style="display:block !important;"> - <a class="jp-banner__dismiss" href="<?php echo esc_url( $dismiss_and_deactivate_url ); ?>"></a> - <div class="jp-banner__content"> - <h4><?php _e( 'To enable all of the Jetpack features, you’ll need to connect your website to WordPress.com.', 'jetpack' ) ?></h4> - <p><?php _e( 'Once you’ve made the connection you’ll activate all the delightful features below.', 'jetpack' ) ?></p> - </div> - <div class="jp-banner__action-container"> - <a href="<?php echo $this->build_connect_url() ?>" class="jp-banner__button" id="wpcom-connect"><?php _e( 'Connect', 'jetpack' ); ?></a> - </div> - </div> - - <?php else /* blog and user are connected */ : ?> - <?php /* TODO: if not master user, show user disconnect button? */ ?> - <?php endif; ?> - <?php endif; // ! Jetpack::is_development_mode() ?> - - - - - - <?php if ( Jetpack::is_active() && !Jetpack::is_development_mode() && ! $is_user_connected ) : ?> - - <div id="message" class="updated jetpack-message jp-banner" style="display:block !important;"> - <div class="jp-banner__content"> - <h4><?php _e( 'To enable all of the Jetpack features you’ll need to link your account here to your WordPress.com account.', 'jetpack' ) ?></h4> - </div> - <div class="jp-banner__action-container is-full-width"> - <a href="<?php echo $this->build_connect_url() ?>" class="jp-banner__button" id="wpcom-connect"><?php _e( 'Link account with WordPress.com', 'jetpack' ); ?></a> - </div> - </div> - - <?php endif; ?> - - - - - <?php - if ( isset( $_GET['configure'] ) && Jetpack::is_module( $_GET['configure'] ) && current_user_can( 'manage_options' ) ) { - $this->admin_screen_configure_module( $_GET['configure'] ); - } else { - $this->admin_screen_list_modules(); - } - ?> - - <div id="survey" class="jp-survey"> - <div class="jp-survey-container"> - <div class="jp-survey-text"> - <h4><?php _e( 'Have feedback on Jetpack?', 'jetpack' ); ?></h4> - <br /> - <?php _e( 'Answer a short survey to let us know how we’re doing and what to add in the future.', 'jetpack' ); ?> - </div> - <div class="jp-survey-button-container"> - <p class="submit"><?php printf( '<a id="jp-survey-button" class="button-primary" target="_blank" href="%1$s">%2$s</a>', 'http://jetpack.me/survey/?rel=' . JETPACK__VERSION, __( 'Take Survey', 'jetpack' ) ); ?></p> - </div> - </div> - </div> - - <?php if ( $is_connected && $this->current_user_is_connection_owner() ) : ?> - <p id="news-sub"><?php _e( 'Checking email updates status…', 'jetpack' ); ?></p> - <script type="text/javascript"> - jQuery(document).ready(function($){ - $.get( ajaxurl, { action: 'jetpack-check-news-subscription', rand: jQuery.now().toString() + Math.random().toString() }, function( data ) { - if ( 'subscribed' == data ) { - $( '#news-sub' ).html( '<?php printf( - esc_js( _x( 'You are currently subscribed to email updates. %s', '%s = Unsubscribe link', 'jetpack' ) ), - '<a href="#" class="jp-news-link button">' . esc_js( __( 'Unsubscribe', 'jetpack' ) ) . '</a>' - ); ?>' ); - } else { - $( '#news-sub' ).html( '<?php printf( - esc_js( _x( 'Want to receive updates about Jetpack by email? %s', '%s = Subscribe link', 'jetpack' ) ), - '<a href="#" class="jp-news-link button-primary">' . esc_js( __( 'Subscribe', 'jetpack' ) ) . '</a>' - ); ?>' ); - } - $( '.jp-news-link' ).click( function() { - $( '#news-sub' ).append( ' <img src="<?php echo esc_js( esc_url( admin_url( 'images/loading.gif' ) ) ); ?>" align="absmiddle" id="jp-news-loading" />' ); - $.get( ajaxurl, { action: 'jetpack-subscribe-to-news', rand: jQuery.now().toString() + Math.random().toString() }, function( data ) { - if ( 'subscribed' == data ) { - $( '#news-sub' ).text( '<?php echo esc_js( __( 'You have been subscribed to receive email updates.', 'jetpack' ) ); ?>' ); - } else { - $( '#news-sub' ).text( '<?php echo esc_js( __( 'You will no longer receive email updates about Jetpack.', 'jetpack' ) ); ?>' ); - } - $( '#jp-news-loading' ).remove(); - } ); - return false; - } ); - } ); - } ); - </script> - <?php endif; ?> - - <div id="jp-footer"> - <p class="automattic"><?php _e( 'An <span>Automattic</span> Airline', 'jetpack' ) ?></p> - <p class="small"> - <a href="http://jetpack.me/" target="_blank">Jetpack <?php echo esc_html( JETPACK__VERSION ); ?></a> | - <a href="http://automattic.com/privacy/" target="_blank"><?php _e( 'Privacy Policy', 'jetpack' ); ?></a> | - <a href="http://wordpress.com/tos/" target="_blank"><?php _e( 'Terms of Service', 'jetpack' ); ?></a> | -<?php if ( current_user_can( 'manage_options' ) ) : ?> - <a href="<?php echo Jetpack::admin_url( array( 'page' => 'jetpack-debugger' ) ); ?>"><?php _e( 'Debug', 'jetpack' ); ?></a> | -<?php endif; ?> - <a href="http://jetpack.me/support/" target="_blank"><?php _e( 'Support', 'jetpack' ); ?></a> - </p> - </div> - - <div id="jetpack-configuration" style="display:none;"> - <p><img width="16" src="<?php echo esc_url( plugins_url( 'images/wpspin_light-2x.gif', JETPACK__PLUGIN_FILE) ); ?>" alt="Loading ..." /></p> - </div> - </div> - <?php - } - function debugger_page() { nocache_headers(); if ( ! current_user_can( 'manage_options' ) ) { @@ -3892,7 +4665,24 @@ p { // User that doesn't have 'jetpack_configure_modules' will never end up here since Jetpack Landing Page woun't let them. if ( ! in_array( $module_id, Jetpack::get_active_modules() ) && current_user_can( 'manage_options' ) ) { - self::display_activate_module_link( $module_id ); + if ( has_action( 'display_activate_module_setting_' . $module_id ) ) { + /** + * Fires to diplay a custom module activation screen. + * + * To add a module actionation screen use Jetpack::module_configuration_activation_screen method. + * Example: Jetpack::module_configuration_activation_screen( 'manage', array( $this, 'manage_activate_screen' ) ); + * + * @module manage + * + * @since 3.8.0 + * + * @param int $module_id Module ID. + */ + do_action( 'display_activate_module_setting_' . $module_id ); + } else { + self::display_activate_module_link( $module_id ); + } + return false; } ?> @@ -3904,8 +4694,23 @@ p { printf( __( 'Configure %s', 'jetpack' ), $module['name'] ); ?> </h3> - <?php do_action( 'jetpack_notices_update_settings', $module_id ); ?> - <?php do_action( 'jetpack_module_configuration_screen_' . $module_id ); ?> + <?php + /** + * Fires within the displayed message when a feature configuation is updated. + * + * @since 3.4.0 + * + * @param int $module_id Module ID. + */ + do_action( 'jetpack_notices_update_settings', $module_id ); + /** + * Fires when a feature configuation screen is loaded. + * The dynamic part of the hook, $module_id, is the module ID. + * + * @since 1.1.0 + */ + do_action( 'jetpack_module_configuration_screen_' . $module_id ); + ?> </div><?php } @@ -3974,208 +4779,6 @@ p { return ( $a['sort'] < $b['sort'] ) ? -1 : 1; } - function admin_screen_list_modules() { - require_once JETPACK__PLUGIN_DIR . 'modules/module-info.php'; - $jetpack_connected = true; - if ( ! Jetpack::is_active() ) - $jetpack_connected = false; - - ?> - <div class="module-container"> - <?php - - $avail_raw = Jetpack::get_available_modules(); - $available = array(); - $active = Jetpack::get_active_modules(); - $counter = 0; - - foreach ( (array) $avail_raw as $module ) { - if ( $plugin = Jetpack::get_module( $module ) ) { - $plugin['module'] = $module; - $available[] = $plugin; - } - } - unset( $avail_raw ); - usort( $available, array( 'Jetpack', 'sort_modules' ) ); - $jetpack_version = Jetpack_Options::get_option( 'version' ); - if ( $jetpack_version ) { - list( $jetpack_version, $jetpack_version_time ) = explode( ':', $jetpack_version ); - } else { - $jetpack_version = 0; - $jetpack_version_time = 0; - } - - $jetpack_old_version = Jetpack_Options::get_option( 'old_version' ); - if ( $jetpack_old_version ) { - list( $jetpack_old_version ) = explode( ':', $jetpack_old_version ); - } else { - $jetpack_old_version = 0; - } - $now = time(); - - foreach ( (array) $available as $module_data ) { - $module = $module_data['module']; - $activated = in_array( $module, $active ); - if ( $activated ) { - $css = 'active'; - $toggle = __( 'Deactivate', 'jetpack' ); - $toggle_url = wp_nonce_url( - Jetpack::admin_url( - array( - 'page' => 'jetpack', - 'action' => 'deactivate', - 'module' => $module, - ) - ), - "jetpack_deactivate-$module" - ); - } else { - $css = 'inactive'; - $toggle = __( 'Activate', 'jetpack' ); - $toggle_url = wp_nonce_url( - Jetpack::admin_url( - array( - 'page' => 'jetpack', - 'action' => 'activate', - 'module' => $module, - ) - ), - "jetpack_activate-$module" - ); - } - - if ( $counter % 4 == 0 ) { - $classes = $css . ' jetpack-newline'; - $counter = 0; - } else { - $classes = $css; - } - - $free_text = esc_html( $module_data['free'] ? __( 'Free', 'jetpack' ) : __( 'Purchase', 'jetpack' ) ); - $free_text = apply_filters( 'jetpack_module_free_text_' . $module, $free_text ); - $badge_text = $free_text; - - if ( ( ! $jetpack_connected && ! Jetpack::is_development_mode() ) ) { - $classes = 'x disabled'; - } elseif ( $jetpack_version_time + 604800 > $now ) { // 1 week - if ( version_compare( $module_data['introduced'], $jetpack_old_version, '>' ) ) { - $badge_text = esc_html__( 'New', 'jetpack' ); - $classes .= ' jetpack-new-module'; - } elseif ( isset( $module_data['changed'] ) && version_compare( $module_data['changed'], $jetpack_old_version, '>' ) ) { - $badge_text = esc_html__( 'Updated', 'jetpack' ); - $classes .= ' jetpack-updated-module'; - } else { - $badge_text = $free_text; - } - } - - ?> - <div class="jetpack-module jetpack-<?php echo $classes; ?>" id="<?php echo $module ?>"> - <h3><?php echo esc_html( $module_data['name'] ); ?></h3> - <div class="jetpack-module-description"> - <div class="module-image"> - <p><span class="module-image-badge"><?php echo $badge_text; ?></span><span class="module-image-free" style="display: none"><?php echo $free_text; ?></span></p> - </div> - - <p><?php echo apply_filters( 'jetpack_short_module_description', $module_data['description'], $module ); ?></p> - </div> - - <div class="jetpack-module-actions"> - <?php if ( $jetpack_connected || ( Jetpack::is_development_mode() && ! $module_data['requires_connection'] ) ) : ?> - <?php if ( ! $activated && current_user_can( 'manage_options' ) && apply_filters( 'jetpack_can_activate_' . $module, true ) ) : ?> - <a href="<?php echo esc_url( $toggle_url ); ?>" class="<?php echo ( 'inactive' == $css ? ' button-primary' : ' button-secondary' ); ?>"><?php echo $toggle; ?></a> - <?php endif; ?> - - <?php do_action( 'jetpack_learn_more_button_' . $module ) ?> - - <?php - if ( current_user_can( 'manage_options' ) && apply_filters( 'jetpack_module_configurable_' . $module, false ) ) { - echo '<a href="' . esc_url( Jetpack::module_configuration_url( $module ) ) . '" class="jetpack-configure-button button-secondary">' . __( 'Configure', 'jetpack' ) . '</a>'; - } - ?><?php if ( $activated && $module_data['deactivate'] && current_user_can( 'manage_options' ) ) : ?><a style="display: none;" href="<?php echo esc_url( $toggle_url ); ?>" class="jetpack-deactivate-button button-secondary"><?php echo $toggle; ?></a> <?php endif; ?> - - <?php else : ?> - <?php do_action( 'jetpack_learn_more_button_' . $module ) ?> - <?php endif; ?> - </div> - </div> - <?php if ( 'inactive' == $css && $jetpack_connected && current_user_can( 'manage_options' ) && apply_filters( 'jetpack_can_activate_' . $module, true ) ) : ?> - <script type="text/javascript"> - jQuery( '#<?php echo esc_js( $module ); ?>' ).bind( 'click', function(e){ - if ( ! jQuery(e.target).hasClass('more-info-link') ) - document.location.href = '<?php echo str_replace( '&', '&', esc_js( esc_url( $toggle_url ) ) ); ?>'; - } ); - </script> - <?php else : ?> - <style> - #<?php echo $module; ?> { cursor: default; } - </style> - <?php endif; ?> - - <div id="jp-more-info-<?php echo esc_attr( $module ); ?>" style="display:none;"> - <?php - if ( $jetpack_connected && has_action( 'jetpack_module_more_info_connected_' . $module ) ) - do_action( 'jetpack_module_more_info_connected_' . $module ); - else - do_action( 'jetpack_module_more_info_' . $module ); - ?> - </div> - - <?php - $counter++; - } - - // Add in some "Coming soon..." placeholders to fill up the current row and one more - for ( $i = 0; $i < 4; $i++ ) { ?> - <div class="jetpack-module placeholder"<?php if ( $i > 8 - $counter ) echo ' style="display: none;"'; ?>> - <h3><?php _e( 'Coming soon…', 'jetpack' ) ?></h3> - </div> - <?php - } - - echo '</div><!-- .module-container -->'; - } - - function check_news_subscription() { - if ( ! $this->current_user_is_connection_owner() ) { - exit; - } - - Jetpack::load_xml_rpc_client(); - $xml = new Jetpack_IXR_Client( - array( - 'user_id' => JETPACK_MASTER_USER, - ) - ); - $xml->query( 'jetpack.checkNewsSubscription' ); - if ( $xml->isError() ) { - printf( '%s: %s', $xml->getErrorCode(), $xml->getErrorMessage() ); - } else { - print_r( $xml->getResponse() ); - } - exit; - } - - function subscribe_to_news() { - if ( ! $this->current_user_is_connection_owner() ) { - exit; - } - - Jetpack::load_xml_rpc_client(); - $xml = new Jetpack_IXR_Client( - array( - 'user_id' => JETPACK_MASTER_USER, - ) - ); - $xml->query( 'jetpack.subscribeToNews' ); - if ( $xml->isError() ) { - printf( '%s: %s', $xml->getErrorCode(), $xml->getErrorMessage() ); - } else { - print_r( $xml->getResponse() ); - } - exit; - } - function sync_reindex_trigger() { if ( $this->current_user_is_connection_owner() && current_user_can( 'manage_options' ) ) { echo json_encode( $this->sync->reindex_trigger() ); @@ -4277,7 +4880,7 @@ p { <div id="message" class="error jetpack-message jp-identity-crisis"> <div class="jp-banner__content"> - <h4><?php _e( 'Something is being cranky!', 'jetpack' ); ?></h4> + <h2><?php _e( 'Something is being cranky!', 'jetpack' ); ?></h2> <p><?php _e( 'Your site is configured to only permit SSL connections to Jetpack, but SSL connections don\'t seem to be functional!', 'jetpack' ); ?></p> </div> </div> @@ -4423,7 +5026,6 @@ p { return $valid_response; } - // Grab the response values to work with $code = wp_remote_retrieve_response_code( $response ); $entity = wp_remote_retrieve_body( $response ); @@ -4450,9 +5052,25 @@ p { ) ); + /** + * 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', $json->jetpack_id, $json->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' ); }; return true; @@ -4705,6 +5323,10 @@ p { } 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, @@ -4714,7 +5336,7 @@ p { $options['jetpack_client_id'] = array( 'desc' => __( 'The Client ID/WP.com Blog ID of this site', 'jetpack' ), 'readonly' => true, - 'value' => Jetpack_Options::get_option( 'id' ), + 'value' => $jetpack_client_id, ); return $options; } @@ -4944,7 +5566,7 @@ p { // Make sure the login form is POSTed to the signed URL so we can reverify the request function post_login_form_to_signed_url( $url, $path, $scheme ) { - if ( 'wp-login.php' !== $path || 'login_post' !== $scheme ) { + if ( 'wp-login.php' !== $path || ( 'login_post' !== $scheme && 'login' !== $scheme ) ) { return $url; } @@ -5084,6 +5706,13 @@ p { */ public static function get_content_width() { $content_width = isset( $GLOBALS['content_width'] ) ? $GLOBALS['content_width'] : false; + /** + * Filter the Content Width value. + * + * @since 2.2.3 + * + * @param string $content_width Content Width value. + */ return apply_filters( 'jetpack_content_width', $content_width ); } @@ -5140,7 +5769,10 @@ p { $xml = new Jetpack_IXR_Client( array( 'user_id' => JETPACK_MASTER_USER, ) ); $xml->query( 'jetpack.fetchSiteOptions', $option_names ); if ( $xml->isError() ) { - return array_flip( $option_names ); + return array( + 'error_code' => $xml->getErrorCode(), + 'error_msg' => $xml->getErrorMessage(), + ); } $cloud_site_options = $xml->getResponse(); @@ -5157,6 +5789,13 @@ p { 'siteurl', 'home', ); + /** + * Filter the options that we should compare to determine an identity crisis. + * + * @since 2.5.0 + * + * @param array $options Array of options to compare to determine an identity crisis. + */ return apply_filters( 'jetpack_identity_crisis_options_to_check', $options ); } @@ -5168,16 +5807,33 @@ p { * @return array An array of options that do not match. If everything is good, it will evaluate to false. */ public static function check_identity_crisis( $force_recheck = false ) { - if ( ! Jetpack::is_active() || Jetpack::is_development_mode() ) + if ( ! Jetpack::is_active() || Jetpack::is_development_mode() || Jetpack::is_staging_site() ) return false; if ( $force_recheck || false === ( $errors = get_transient( 'jetpack_has_identity_crisis' ) ) ) { $options_to_check = self::identity_crisis_options_to_check(); $cloud_options = Jetpack::init()->get_cloud_site_options( $options_to_check ); $errors = array(); + foreach ( $cloud_options as $cloud_key => $cloud_value ) { + // If it's not the same as the local value... if ( $cloud_value !== get_option( $cloud_key ) ) { + + // Break out if we're getting errors. We are going to check the error keys later when we alert. + if ( 'error_code' == $cloud_key ) { + $errors[ $cloud_key ] = $cloud_value; + break; + } + + $parsed_cloud_value = parse_url( $cloud_value ); + // If the current options is an IP address + if ( filter_var( $parsed_cloud_value['host'], FILTER_VALIDATE_IP ) ) { + // Give the new value a Jetpack to fly in to the clouds + Jetpack::resolve_identity_crisis( $cloud_key ); + continue; + } + // And it's not been added to the whitelist... if ( ! self::is_identity_crisis_value_whitelisted( $cloud_key, $cloud_value ) ) { /* @@ -5191,7 +5847,7 @@ p { * * @see https://github.com/Automattic/jetpack/issues/1006 */ - if( ( 'home' == $cloud_key || 'siteurl' == $cloud_key ) + if ( ( 'home' == $cloud_key || 'siteurl' == $cloud_key ) && ( substr( $cloud_value, 0, 8 ) == "https://" ) && Jetpack::init()->is_ssl_required_to_visit_site() ) { // Ok, we found a mismatch of http and https because of wp-config, not an invalid url @@ -5205,9 +5861,113 @@ p { } } } + + /** + * Filters the errors returned when checking for an Identity Crisis. + * + * @since 2.3.2 + * + * @param array $errors Array of Identity Crisis errors. + * @param bool $force_recheck Ignore any cached transient and manually re-check. Default to false. + */ return apply_filters( 'jetpack_has_identity_crisis', $errors, $force_recheck ); } + /* + * Resolve ID crisis + * + * If the URL has changed, but the rest of the options are the same (i.e. blog/user tokens) + * The user has the option to update the shadow site with the new URL before a new + * token is created. + * + * @param $key : Which option to sync. null defautlts to home and siteurl + */ + public static function resolve_identity_crisis( $key = null ) { + if ( $key ) { + $identity_options = array( $key ); + } else { + $identity_options = self::identity_crisis_options_to_check(); + } + + if ( is_array( $identity_options ) ) { + foreach( $identity_options as $identity_option ) { + Jetpack_Sync::sync_options( __FILE__, $identity_option ); + + /** + * Fires when a shadow site option is updated. + * These options are updated via the Identity Crisis UI. + * $identity_option is the option that gets updated. + * + * @since 3.7.0 + */ + do_action( "update_option_{$identity_option}" ); + } + } + } + + /* + * Whitelist URL + * + * Ignore the URL differences between the blog and the shadow site. + */ + public static function whitelist_current_url() { + $options_to_check = Jetpack::identity_crisis_options_to_check(); + $cloud_options = Jetpack::init()->get_cloud_site_options( $options_to_check ); + + foreach ( $cloud_options as $cloud_key => $cloud_value ) { + Jetpack::whitelist_identity_crisis_value( $cloud_key, $cloud_value ); + } + } + + /* + * Ajax callbacks for ID crisis resolutions + * + * Things that could happen here: + * - site_migrated : Update the URL on the shadow blog to match new domain + * - whitelist : Ignore the URL difference + * - default : Error message + */ + public static function resolve_identity_crisis_ajax_callback() { + check_ajax_referer( 'resolve-identity-crisis', 'ajax-nonce' ); + + switch ( $_POST[ 'crisis_resolution_action' ] ) { + case 'site_migrated': + Jetpack::resolve_identity_crisis(); + echo 'resolved'; + break; + + case 'whitelist': + Jetpack::whitelist_current_url(); + echo 'whitelisted'; + break; + + case 'reset_connection': + // Delete the options first so it doesn't get confused which site to disconnect dotcom-side + Jetpack_Options::delete_option( + array( + 'register', + 'blog_token', + 'user_token', + 'user_tokens', + 'master_user', + 'time_diff', + 'fallback_no_verify_ssl_certs', + 'id', + ) + ); + delete_transient( 'jetpack_has_identity_crisis' ); + + echo 'reset-connection-success'; + break; + + default: + echo 'missing action'; + break; + } + + wp_die(); + } + /** * Adds a value to the whitelist for the specified key. * @@ -5217,7 +5977,7 @@ p { * @return bool Whether the value was added to the whitelist, or false if it was already there. */ public static function whitelist_identity_crisis_value( $key, $value ) { - if ( self::is_identity_crisis_url_whitelisted( $key, $value ) ) { + if ( Jetpack::is_identity_crisis_value_whitelisted( $key, $value ) ) { return false; } @@ -5248,25 +6008,269 @@ p { } /** + * Checks whether the home and siteurl specifically are whitelisted + * Written so that we don't have re-check $key and $value params every time + * we want to check if this site is whitelisted, for example in footer.php + * + * @return bool True = already whitelsisted False = not whitelisted + */ + public static function is_staging_site() { + $is_staging = false; + + $current_whitelist = Jetpack_Options::get_option( 'identity_crisis_whitelist' ); + if ( $current_whitelist ) { + $options_to_check = Jetpack::identity_crisis_options_to_check(); + $cloud_options = Jetpack::init()->get_cloud_site_options( $options_to_check ); + + foreach ( $cloud_options as $cloud_key => $cloud_value ) { + if ( self::is_identity_crisis_value_whitelisted( $cloud_key, $cloud_value ) ) { + $is_staging = true; + break; + } + } + } + $known_staging = array( + 'urls' => array( + '#\.staging\.wpengine\.com$#i', + ), + 'constants' => array( + 'IS_WPE_SNAPSHOT', + ) + ); + /** + * Filters the flags of known staging sites. + * + * @since 3.9.0 + * + * @param array $known_staging { + * An array of arrays that each are used to check if the current site is staging. + * @type array $urls URLs of staging sites in regex to check against site_url. + * @type array $cosntants PHP constants of known staging/developement environments. + * } + */ + $known_staging = apply_filters( 'jetpack_known_staging', $known_staging ); + + if ( isset( $known_staging['urls'] ) ) { + foreach ( $known_staging['urls'] as $url ){ + if ( preg_match( $url, site_url() ) ) { + $is_staging = true; + break; + } + } + } + + if ( isset( $known_staging['constants'] ) ) { + foreach ( $known_staging['constants'] as $constant ) { + if ( defined( $constant ) && constant( $constant ) ) { + $is_staging = true; + } + } + } + + /** + * Filters is_staging_site check. + * + * @since 3.9.0 + * + * @param bool $is_staging If the current site is a staging site. + */ + return apply_filters( 'jetpack_is_staging_site', $is_staging ); + } + + public function identity_crisis_js( $nonce ) { +?> +<script> +(function( $ ) { + var SECOND_IN_MS = 1000; + + function contactSupport( e ) { + e.preventDefault(); + $( '.jp-id-crisis-question' ).hide(); + $( '#jp-id-crisis-contact-support' ).show(); + } + + function autodismissSuccessBanner() { + $( '.jp-identity-crisis' ).fadeOut(600); //.addClass( 'dismiss' ); + } + + var data = { action: 'jetpack_resolve_identity_crisis', 'ajax-nonce': '<?php echo $nonce; ?>' }; + + $( document ).ready(function() { + + // Site moved: Update the URL on the shadow blog + $( '.site-moved' ).click(function( e ) { + e.preventDefault(); + data.crisis_resolution_action = 'site_migrated'; + $( '#jp-id-crisis-question-1 .spinner' ).show(); + $.post( ajaxurl, data, function() { + $( '.jp-id-crisis-question' ).hide(); + $( '.banner-title' ).hide(); + $( '#jp-id-crisis-success' ).show(); + setTimeout( autodismissSuccessBanner, 6 * SECOND_IN_MS ); + }); + + }); + + // URL hasn't changed, next question please. + $( '.site-not-moved' ).click(function( e ) { + e.preventDefault(); + $( '.jp-id-crisis-question' ).hide(); + $( '#jp-id-crisis-question-2' ).show(); + }); + + // Reset connection: two separate sites. + $( '.reset-connection' ).click(function( e ) { + data.crisis_resolution_action = 'reset_connection'; + $.post( ajaxurl, data, function( response ) { + if ( 'reset-connection-success' === response ) { + window.location.replace( '<?php echo Jetpack::admin_url(); ?>' ); + } + }); + }); + + // It's a dev environment. Ignore. + $( '.is-dev-env' ).click(function( e ) { + data.crisis_resolution_action = 'whitelist'; + $( '#jp-id-crisis-question-2 .spinner' ).show(); + $.post( ajaxurl, data, function() { + $( '.jp-id-crisis-question' ).hide(); + $( '.banner-title' ).hide(); + $( '#jp-id-crisis-success' ).show(); + setTimeout( autodismissSuccessBanner, 4 * SECOND_IN_MS ); + }); + }); + + $( '.not-reconnecting' ).click(contactSupport); + $( '.not-staging-or-dev' ).click(contactSupport); + }); +})( jQuery ); +</script> +<?php + } + + /** * Displays an admin_notice, alerting the user to an identity crisis. */ public function alert_identity_crisis() { - if ( ! current_user_can( 'manage_options' ) ) + // @todo temporary killing of feature in 3.8.1 as it revealed a number of scenarios not foreseen. + if ( ! Jetpack::is_development_version() ) { return; + } - if ( ! $errors = self::check_identity_crisis() ) + // @todo temporary copout for dealing with domain mapping + // @see https://github.com/Automattic/jetpack/issues/2702 + if ( is_multisite() && defined( 'SUNRISE' ) && ! Jetpack::is_development_version() ) { return; + } + + if ( ! current_user_can( 'jetpack_disconnect' ) ) { + return; + } + + if ( ! $errors = self::check_identity_crisis() ) { + return; + } + + // Only show on dashboard and jetpack pages + $screen = get_current_screen(); + if ( 'dashboard' !== $screen->base && ! did_action( 'jetpack_notices' ) ) { + return; + } + + // Include the js! + $ajax_nonce = wp_create_nonce( 'resolve-identity-crisis' ); + $this->identity_crisis_js( $ajax_nonce ); + + // Include the CSS! + if ( ! wp_script_is( 'jetpack', 'done' ) ) { + $this->admin_banner_styles(); + } + + if ( ! array_key_exists( 'error_code', $errors ) ) { + $key = 'siteurl'; + if ( ! $errors[ $key ] ) { + $key = 'home'; + } + } else { + $key = 'error_code'; + // 401 is the only error we care about. Any other errors should not trigger the alert. + if ( 401 !== $errors[ $key ] ) { + return; + } + } + ?> - <div id="message" class="updated jetpack-message jp-identity-crisis"> - <div class="jp-banner__content"> - <h4><?php _e( 'Something has gotten mixed up!', 'jetpack' ); ?></h4> - <?php foreach ( $errors as $key => $value ) : ?> - <p><?php printf( __( 'Your <code>%1$s</code> option is set up as <strong>%2$s</strong>, but your WordPress.com connection lists it as <strong>%3$s</strong>!', 'jetpack' ), $key, (string) get_option( $key ), $value ); ?></p> - <?php endforeach; ?> - <p><a href="<?php echo $this->build_reconnect_url() ?>"><?php _e( 'The data listed above is not for my current site. Please disconnect, and then form a new connection to WordPress.com for this site using my current settings.', 'jetpack' ); ?></a></p> - <p><a href="#"><?php _e( 'Ignore the difference. This is just a staging site for the real site referenced above.', 'jetpack' ); ?></a></p> - <p><a href="#"><?php _e( 'That used to be my URL for this site before I changed it. Update the WordPress.com Cloud\'s data to match my current settings.', 'jetpack' ); ?></a></p> + <style> + .jp-identity-crisis .jp-btn-group { + margin: 15px 0; + } + .jp-identity-crisis strong { + color: #518d2a; + } + .jp-identity-crisis.dismiss { + display: none; + } + .jp-identity-crisis .button { + margin-right: 4px; + } + </style> + + <div id="message" class="error jetpack-message jp-identity-crisis stay-visible"> + <div class="service-mark"></div> + <div class="jp-id-banner__content"> + <!-- <h3 class="banner-title"><?php _e( 'Something\'s not quite right with your Jetpack connection! Let\'s fix that.', 'jetpack' ); ?></h3> --> + + <div class="jp-id-crisis-question" id="jp-id-crisis-question-1"> + <?php + // 401 means that this site has been disconnected from wpcom, but the remote site still thinks it's connected. + if ( 'error_code' == $key && '401' == $errors[ $key ] ) : ?> + <div class="banner-content"> + <p><?php + /* translators: %s is a URL */ + printf( __( 'Our records show that this site does not have a valid connection to WordPress.com. Please reset your connection to fix this. <a href="%s" target="_blank">What caused this?</a>', 'jetpack' ), 'https://jetpack.me/support/no-valid-wordpress-com-connection/' ); + ?></p> + </div> + <div class="jp-btn-group"> + <a href="#" class="reset-connection"><?php _e( 'Reset the connection', 'jetpack' ); ?></a> + <span class="idc-separator">|</span> + <a href="<?php echo esc_url( wp_nonce_url( Jetpack::admin_url( 'jetpack-notice=dismiss' ), 'jetpack-deactivate' ) ); ?>"><?php _e( 'Deactivate Jetpack', 'jetpack' ); ?></a> + </div> + <?php else : ?> + <div class="banner-content"> + <p><?php printf( __( 'It looks like you may have changed your domain. Is <strong>%1$s</strong> still your site\'s domain, or have you updated it to <strong> %2$s </strong>?', 'jetpack' ), $errors[ $key ], (string) get_option( $key ) ); ?></p> + </div> + <div class="jp-btn-group"> + <a href="#" class="regular site-moved"><?php printf( __( '%s is now my domain.', 'jetpack' ), $errors[ $key ] ); ?></a> <span class="idc-separator">|</span> <a href="#" class="site-not-moved" ><?php printf( __( '%s is still my domain.', 'jetpack' ), (string) get_option( $key ) ); ?></a> + <span class="spinner"></span> + </div> + <?php endif ; ?> + </div> + + <div class="jp-id-crisis-question" id="jp-id-crisis-question-2" style="display: none;"> + <div class="banner-content"> + <p><?php printf( + /* translators: %1$s, %2$s and %3$s are URLs */ + __( + 'Are <strong> %2$s </strong> and <strong> %1$s </strong> two completely separate websites? If so we should create a new connection, which will reset your followers and linked services. <a href="%3$s"><em>What does this mean?</em></a>', + 'jetpack' + ), + $errors[ $key ], + (string) get_option( $key ), + 'https://jetpack.me/support/what-does-resetting-the-connection-mean/' + ); ?></p> + </div> + <div class="jp-btn-group"> + <a href="#" class="reset-connection"><?php _e( 'Reset the connection', 'jetpack' ); ?></a> <span class="idc-separator">|</span> + <a href="#" class="is-dev-env"><?php _e( 'This is a development environment', 'jetpack' ); ?></a> <span class="idc-separator">|</span> + <a href="https://jetpack.me/contact-support/" class="contact-support"><?php _e( 'Submit a support ticket', 'jetpack' ); ?></a> + <span class="spinner"></span> + </div> + </div> + + <div class="jp-id-crisis-success" id="jp-id-crisis-success" style="display: none;"> + <h3 class="success-notice"><?php printf( __( 'Thanks for taking the time to sort things out. We've updated our records accordingly!', 'jetpack' ) ); ?></h3> + </div> </div> </div> @@ -5429,6 +6433,8 @@ p { */ $deprecated_list = array( 'jetpack_bail_on_shortcode' => 'jetpack_shortcodes_to_include', + 'wpl_sharing_2014_1' => null, + 'jetpack-tools-to-include' => 'jetpack_tools_to_include', ); // This is a silly loop depth. Better way? @@ -5512,11 +6518,10 @@ p { * @return boolean **/ private function is_ssl_required_to_visit_site() { + global $wp_version; $ssl = is_ssl(); - if ( force_ssl_login() ) { - $ssl = true; - } else if ( force_ssl_admin() ) { + if ( force_ssl_admin() ) { $ssl = true; } return $ssl; @@ -5554,6 +6559,13 @@ p { $do_implode = false; } + /** + * Allow CSS to be concatenated into a single jetpack.css file. + * + * @since 3.2.0 + * + * @param bool $do_implode Should CSS be concatenated? Default to true. + */ $do_implode = apply_filters( 'jetpack_implode_frontend_css', $do_implode ); // Do not use the imploded file when default behaviour was altered through the filter @@ -5606,22 +6618,90 @@ p { } /* - * Check if an option of a Jetpack module has been updated. + * Check the heartbeat data * - * If any module option has been updated before Jump Start has been dismissed, - * update the 'jumpstart' option so we can hide Jump Start. + * Organizes the heartbeat data by severity. For example, if the site + * is in an ID crisis, it will be in the $filtered_data['bad'] array. + * + * Data will be added to "caution" array, if it either: + * - Out of date Jetpack version + * - Out of date WP version + * - Out of date PHP version + * + * $return array $filtered_data */ - public static function jumpstart_has_updated_module_option( $option_name = '' ) { - // Bail if Jump Start has already been dismissed - if ( 'new_connection' !== Jetpack::get_option( 'jumpstart' ) ) { - return false; + public static function jetpack_check_heartbeat_data() { + $raw_data = Jetpack_Heartbeat::generate_stats_array(); + + $good = array(); + $caution = array(); + $bad = array(); + + foreach ( $raw_data as $stat => $value ) { + + // Check jetpack version + if ( 'version' == $stat ) { + if ( version_compare( $value, JETPACK__VERSION, '<' ) ) { + $caution[ $stat ] = $value . " - min supported is " . JETPACK__VERSION; + continue; + } + } + + // 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; + 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"; + continue; + } + } + + // Check ID crisis + if ( 'identitycrisis' == $stat ) { + if ( 'yes' == $value ) { + $bad[ $stat ] = $value; + continue; + } + } + + // The rest are good :) + $good[ $stat ] = $value; } - $jetpack = Jetpack::init(); + $filtered_data = array( + 'good' => $good, + 'caution' => $caution, + 'bad' => $bad + ); + return $filtered_data; + } - // Manual build of module options - $option_names = array( + + /* + * This method is used to organize all options that can be reset + * without disconnecting Jetpack. + * + * It is used in class.jetpack-cli.php to reset options + * + * @return array of options to delete. + */ + public static function get_jetpack_options_for_reset() { + $jetpack_options = Jetpack_Options::get_option_names(); + $jetpack_options_non_compat = Jetpack_Options::get_option_names( 'non_compact' ); + $jetpack_options_private = Jetpack_Options::get_option_names( 'private' ); + + $all_jp_options = array_merge( $jetpack_options, $jetpack_options_non_compat, $jetpack_options_private ); + + // A manual build of the wp options + $wp_options = array( 'sharing-options', 'disabled_likes', 'disabled_reblogs', @@ -5648,7 +6728,57 @@ p { 'site_logo', ); - if ( in_array( $option_name, $option_names ) ) { + // Flag some Jetpack options as unsafe + $unsafe_options = array( + 'id', // (int) The Client ID/WP.com Blog ID of this site. + 'master_user', // (int) The local User ID of the user who connected this site to jetpack.wordpress.com. + 'version', // (string) Used during upgrade procedure to auto-activate new modules. version:time + 'jumpstart', // (string) A flag for whether or not to show the Jump Start. Accepts: new_connection, jumpstart_activated, jetpack_action_taken, jumpstart_dismissed. + + // non_compact + 'activated', + + // private + 'register', + 'blog_token', // (string) The Client Secret/Blog Token of this site. + 'user_token', // (string) The User Token of this site. (deprecated) + 'user_tokens' + ); + + // Remove the unsafe Jetpack options + foreach ( $unsafe_options as $unsafe_option ) { + if ( false !== ( $key = array_search( $unsafe_option, $all_jp_options ) ) ) { + unset( $all_jp_options[ $key ] ); + } + } + + $options = array( + 'jp_options' => $all_jp_options, + 'wp_options' => $wp_options + ); + + return $options; + } + + /* + * Check if an option of a Jetpack module has been updated. + * + * If any module option has been updated before Jump Start has been dismissed, + * update the 'jumpstart' option so we can hide Jump Start. + */ + public static function jumpstart_has_updated_module_option( $option_name = '' ) { + // Bail if Jump Start has already been dismissed + if ( 'new_connection' !== Jetpack::get_option( 'jumpstart' ) ) { + return false; + } + + $jetpack = Jetpack::init(); + + + // Manual build of module options + $option_names = self::get_jetpack_options_for_reset(); + + if ( in_array( $option_name, $option_names['wp_options'] ) ) { Jetpack_Options::update_option( 'jumpstart', 'jetpack_action_taken' ); //Jump start is being dismissed send data to MC Stats @@ -5699,14 +6829,16 @@ p { public function wp_dashboard_setup() { if ( self::is_active() ) { add_action( 'jetpack_dashboard_widget', array( __CLASS__, 'dashboard_widget_footer' ), 999 ); - } elseif ( ! self::is_development_mode() ) { + $widget_title = __( 'Site Stats', 'jetpack' ); + } elseif ( ! self::is_development_mode() && current_user_can( 'jetpack_connect' ) ) { add_action( 'jetpack_dashboard_widget', array( $this, 'dashboard_widget_connect_to_wpcom' ) ); + $widget_title = __( 'Please Connect Jetpack', 'jetpack' ); } if ( has_action( 'jetpack_dashboard_widget' ) ) { wp_add_dashboard_widget( 'jetpack_summary_widget', - __( 'Jetpack', 'jetpack' ), + $widget_title, array( __CLASS__, 'dashboard_widget' ) ); wp_enqueue_style( 'jetpack-dashboard-widget', plugins_url( 'css/dashboard-widget.css', JETPACK__PLUGIN_FILE ), array(), JETPACK__VERSION ); @@ -5754,6 +6886,11 @@ p { } public static function dashboard_widget() { + /** + * Fires when the dashboard is loaded. + * + * @since 3.4.0 + */ do_action( 'jetpack_dashboard_widget' ); } @@ -5766,11 +6903,11 @@ p { <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( 'Jetpack Protect helps to keep you secure from brute-force login attacks.', 'jetpack' ); ?>"> - <?php esc_html_e( 'Activate Jetpack Protect', 'jetpack' ); ?> + <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 esc_html_e( 'Activate Protect', 'jetpack' ); ?> </a> <?php else : ?> - <?php esc_html_e( 'Jetpack Protect is inactive.', 'jetpack' ); ?> + <?php esc_html_e( 'Protect is inactive.', 'jetpack' ); ?> <?php endif; ?> </div> @@ -5787,33 +6924,85 @@ p { <?php endif; ?> </div> + + <?php if ( ! current_user_can( 'edit_posts' ) && self::is_user_connected() ) : ?> + <div style="width: 100%; text-align: center; padding-top: 20px; clear: both;"><a class="button" title="<?php esc_attr_e( 'Unlink your account from WordPress.com', 'jetpack' ); ?>" href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'unlink', 'redirect' => 'sub-unlink' ), admin_url( 'index.php' ) ), 'jetpack-unlink' ) ); ?>"><?php esc_html_e( 'Unlink your account from WordPress.com', 'jetpack' ); ?></a></div> + <?php endif; ?> + </footer> <?php } public function dashboard_widget_connect_to_wpcom() { + if ( Jetpack::is_active() || Jetpack::is_development_mode() || ! current_user_can( 'jetpack_connect' ) ) { + return; + } ?> <div class="wpcom-connect"> <div class="jp-emblem"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0" y="0" viewBox="0 0 172.9 172.9" enable-background="new 0 0 172.9 172.9" xml:space="preserve"> - <path d="M86.4 0C38.7 0 0 38.7 0 86.4c0 47.7 38.7 86.4 86.4 86.4s86.4-38.7 86.4-86.4C172.9 38.7 134.2 0 86.4 0zM83.1 106.6l-27.1-6.9C49 98 45.7 90.1 49.3 84l33.8-58.5V106.6zM124.9 88.9l-33.8 58.5V66.3l27.1 6.9C125.1 74.9 128.4 82.8 124.9 88.9z"/> + <path d="M86.4 0C38.7 0 0 38.7 0 86.4c0 47.7 38.7 86.4 86.4 86.4s86.4-38.7 86.4-86.4C172.9 38.7 134.2 0 86.4 0zM83.1 106.6l-27.1-6.9C49 98 45.7 90.1 49.3 84l33.8-58.5V106.6zM124.9 88.9l-33.8 58.5V66.3l27.1 6.9C125.1 74.9 128.4 82.8 124.9 88.9z"/> </svg> </div> - <h3><?php esc_html_e( 'Boost traffic, enhance security, and improve performance.', 'jetpack' ); ?></h3> - <p><?php esc_html_e( 'Jetpack connects your site to WordPress.com to give you traffic and customization tools, enhanced security, speed boosts, and more.', 'jetpack' ); ?></p> + <h3><?php esc_html_e( 'Please Connect Jetpack', 'jetpack' ); ?></h3> + <p><?php echo wp_kses( __( 'Connecting Jetpack will show you <strong>stats</strong> about your traffic, <strong>protect</strong> you from brute force attacks, <strong>speed up</strong> your images and photos, and enable other <strong>traffic and security</strong> features.', 'jetpack' ), 'jetpack' ) ?></p> <div class="actions"> <a href="<?php echo $this->build_connect_url() ?>" class="button button-primary"> - <?php esc_html_e( 'Connect to WordPress.com', 'jetpack' ); ?> + <?php esc_html_e( 'Connect Jetpack', 'jetpack' ); ?> </a> - <?php if ( current_user_can( 'activate_plugins' ) ) : ?> - <small><a href="<?php echo esc_url( wp_nonce_url( Jetpack::admin_url( 'jetpack-notice=dismiss' ), 'jetpack-deactivate' ) ); ?>" title="Deactivate Jetpack"> - <?php esc_html_e( 'or, deactivate Jetpack', 'jetpack' ); ?> - </a></small> - <?php endif; ?> </div> </div> <?php } + /* + * A graceful transition to using Core's site icon. + * + * All of the hard work has already been done with the image + * in all_done_page(). All that needs to be done now is update + * the option and display proper messaging. + * + * @todo remove when WP 4.3 is minimum + * + * @since 3.6.1 + * + * @return bool false = Core's icon not available || true = Core's icon is available + */ + public static function jetpack_site_icon_available_in_core() { + global $wp_version; + $core_icon_available = function_exists( 'has_site_icon' ) && version_compare( $wp_version, '4.3-beta' ) >= 0; + + if ( ! $core_icon_available ) { + return false; + } + + // No need for Jetpack's site icon anymore if core's is already set + if ( has_site_icon() ) { + if ( Jetpack::is_module_active( 'site-icon' ) ) { + Jetpack::log( 'deactivate', 'site-icon' ); + Jetpack::deactivate_module( 'site-icon' ); + } + return true; + } + + // Transfer Jetpack's site icon to use core. + $site_icon_id = Jetpack::get_option( 'site_icon_id' ); + if ( $site_icon_id ) { + // Update core's site icon + update_option( 'site_icon', $site_icon_id ); + + // Delete Jetpack's icon option. We still want the blavatar and attached data though. + delete_option( 'site_icon_id' ); + } + + // No need for Jetpack's site icon anymore + if ( Jetpack::is_module_active( 'site-icon' ) ) { + Jetpack::log( 'deactivate', 'site-icon' ); + Jetpack::deactivate_module( 'site-icon' ); + } + + return true; + } + } |