if ( Jetpack_Options::get_option( 'ab_connect_banner_green_bar' ) ) {
Jetpack_Options::delete_option( 'ab_connect_banner_green_bar' );
// Update to 8.8.x (WordPress 5.5 Compatibility).
if ( Jetpack_Options::get_option( 'autoupdate_plugins' ) ) {
$updated = update_site_option(
(array) Jetpack_Options::get_option( 'autoupdate_plugins', array() ),
(array) get_site_option( 'auto_update_plugins', array() )
Jetpack_Options::delete_option( 'autoupdate_plugins' );
} // Should we have some type of fallback if something fails here?
if ( did_action( 'wp_loaded' ) ) {
array( __CLASS__, 'upgrade_on_load' )
* Runs upgrade routines that need to have modules loaded.
public static function upgrade_on_load() {
// Not attempting any upgrades if jetpack_modules_loaded did not fire.
// This can happen in case Jetpack has been just upgraded and is
// being initialized late during the page load. In this case we wait
// until the next proper admin page load with Jetpack active.
if ( ! did_action( 'jetpack_modules_loaded' ) ) {
delete_transient( self::$plugin_upgrade_lock_key );
self::maybe_set_version_option();
if ( method_exists( 'Jetpack_Widget_Conditions', 'migrate_post_type_rules' ) ) {
Jetpack_Widget_Conditions::migrate_post_type_rules();
class_exists( 'Jetpack_Sitemap_Manager' )
do_action( 'jetpack_sitemaps_purge_data' );
// Delete old stats cache.
delete_option( 'jetpack_restapi_stats_cache' );
delete_transient( self::$plugin_upgrade_lock_key );
* Saves all the currently active modules to options.
* Also fires Action hooks for each newly activated and deactivated module.
* @param array $modules Array of active modules to be saved in options.
* @return bool $success true for success, false for failure.
public static function update_active_modules( $modules ) {
return ( new Modules() )->update_active( $modules );
* Remove all active modules.
public static function delete_active_modules() {
self::update_active_modules( array() );
* Adds a hook to plugins_loaded at a priority that's currently the earliest
public function add_configure_hook() {
$current_priority = has_filter( 'plugins_loaded', array( $this, 'configure' ) );
if ( false !== $current_priority ) {
remove_action( 'plugins_loaded', array( $this, 'configure' ), $current_priority );
$taken_priorities = array_map( 'intval', array_keys( $wp_filter['plugins_loaded']->callbacks ) );
sort( $taken_priorities );
$first_priority = array_shift( $taken_priorities );
if ( $first_priority <= PHP_INT_MIN ) {
$new_priority = PHP_INT_MIN;
$new_priority = $first_priority - 1;
add_action( 'plugins_loaded', array( $this, 'configure' ), $new_priority );
* Constructor. Initializes WordPress hooks
private function __construct() {
* Check for and alert any deprecated hooks
add_action( 'init', array( $this, 'deprecated_hooks' ) );
// Note how this runs at an earlier plugin_loaded hook intentionally to accomodate for other plugins.
add_action( 'plugin_loaded', array( $this, 'add_configure_hook' ), 90 );
add_action( 'network_plugin_loaded', array( $this, 'add_configure_hook' ), 90 );
add_action( 'mu_plugin_loaded', array( $this, 'add_configure_hook' ), 90 );
add_action( 'plugins_loaded', array( $this, 'late_initialization' ), 90 );
add_action( 'jetpack_verify_signature_error', array( $this, 'track_xmlrpc_error' ) );
* Prepare Gutenberg Editor functionality
* The hooks previously here have been moved to modules/blocks.php but leaving this here pending
* a longer investigation to see if code is expecting the Gutenberg class to always be available.
require_once JETPACK__PLUGIN_DIR . 'class.jetpack-gutenberg.php';
add_action( 'set_user_role', array( $this, 'maybe_clear_other_linked_admins_transient' ), 10, 3 );
add_action( 'jetpack_event_log', array( 'Jetpack', 'log' ), 10, 2 );
add_filter( 'login_url', array( $this, 'login_url' ), 10, 2 );
add_action( 'login_init', array( $this, 'login_init' ) );
// Set up the REST authentication hooks.
Connection_Rest_Authentication::init();
add_action( 'admin_init', array( $this, 'admin_init' ) );
add_action( 'admin_init', array( $this, 'dismiss_jetpack_notice' ) );
add_filter( 'admin_body_class', array( $this, 'admin_body_class' ), 20 );
// 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' ) );
// WordPress dashboard widget.
require_once JETPACK__PLUGIN_DIR . 'class-jetpack-stats-dashboard-widget.php';
add_action( 'wp_dashboard_setup', array( new Jetpack_Stats_Dashboard_Widget(), 'init' ) );
// Returns HTTPS support status.
add_action( 'wp_ajax_jetpack-recheck-ssl', array( $this, 'ajax_recheck_ssl' ) );
add_action( 'wp_loaded', array( $this, 'register_assets' ) );
* These actions run checks to load additional files.
* They check for external files or plugins, so they need to run as late as possible.
add_action( 'wp_head', array( $this, 'check_open_graph' ), 1 );
add_action( 'web_stories_story_head', array( $this, 'check_open_graph' ), 1 );
add_action( 'plugins_loaded', array( $this, 'check_twitter_tags' ), 999 );
add_action( 'plugins_loaded', array( $this, 'check_rest_api_compat' ), 1000 );
add_filter( 'plugins_url', array( 'Jetpack', 'maybe_min_asset' ), 1, 3 );
add_action( 'style_loader_src', array( 'Jetpack', 'set_suffix_on_min' ), 10, 2 );
add_filter( 'profile_update', array( 'Jetpack', 'user_meta_cleanup' ) );
add_filter( 'jetpack_get_default_modules', array( $this, 'filter_default_modules' ) );
add_filter( 'jetpack_get_default_modules', array( $this, 'handle_deprecated_modules' ), 99 );
if ( User_Agent_Info::is_mobile_app() ) {
add_filter( 'get_edit_post_link', '__return_empty_string' );
// Update the site's Jetpack plan and products from API on heartbeats.
add_action( 'jetpack_heartbeat', array( Jetpack_Plan::class, 'refresh_from_wpcom' ) );
// Actually push the stats on shutdown.
if ( ! has_action( 'shutdown', array( $this, 'push_stats' ) ) ) {
add_action( 'shutdown', array( $this, 'push_stats' ) );
// After a successful connection.
add_action( 'jetpack_site_registered', array( $this, 'activate_default_modules_on_site_register' ) );
add_action( 'jetpack_site_registered', array( $this, 'handle_unique_registrations_stats' ) );
add_action( 'jetpack_site_registered', array( Reader_Link::class, 'activate_on_connection' ), 9 );
// Actions for Manager::authorize().
add_action( 'jetpack_authorize_starting', array( $this, 'authorize_starting' ) );
add_action( 'jetpack_authorize_ending_linked', array( $this, 'authorize_ending_linked' ) );
add_action( 'jetpack_authorize_ending_authorized', array( $this, 'authorize_ending_authorized' ) );
Jetpack_Client_Server::init();
add_action( 'jetpack_client_authorize_error', array( Jetpack_Client_Server::class, 'client_authorize_error' ) );
add_filter( 'jetpack_client_authorize_already_authorized_url', array( Jetpack_Client_Server::class, 'client_authorize_already_authorized_url' ) );
add_action( 'jetpack_client_authorize_processing', array( Jetpack_Client_Server::class, 'client_authorize_processing' ) );
add_filter( 'jetpack_client_authorize_fallback_url', array( Jetpack_Client_Server::class, 'client_authorize_fallback_url' ) );
// Filters for the Manager::get_token() urls and request body.
add_filter( 'jetpack_token_redirect_url', array( Authorize_Redirect::class, 'filter_connect_redirect_url' ) );
add_filter( 'jetpack_token_request_body', array( __CLASS__, 'filter_token_request_body' ) );
// Filter for the `jetpack/v4/connection/data` API response.
add_filter( 'jetpack_current_user_connection_data', array( __CLASS__, 'filter_jetpack_current_user_connection_data' ) );
// Actions for successful reconnect.
add_action( 'jetpack_reconnection_completed', array( $this, 'reconnection_completed' ) );
// Actions for successful disconnect.
add_action( 'jetpack_site_disconnected', array( $this, 'jetpack_site_disconnected' ) );
// Actions for licensing.
Licensing::instance()->initialize();
// Filters for Sync Callables.
add_filter( 'jetpack_sync_callable_whitelist', array( $this, 'filter_sync_callable_whitelist' ), 10, 1 );
add_filter( 'jetpack_sync_multisite_callable_whitelist', array( $this, 'filter_sync_multisite_callable_whitelist' ), 10, 1 );
// Make resources use static domain when possible.
add_filter( 'jetpack_static_url', array( 'Automattic\\Jetpack\\Assets', 'staticize_subdomain' ) );
// Validate the domain names in Jetpack development versions.
add_action( 'jetpack_pre_register', array( static::class, 'registration_check_domains' ) );
// Register product descriptions for partner coupon usage.
add_filter( 'jetpack_partner_coupon_products', array( $this, 'get_partner_coupon_product_descriptions' ) );
// Actions for conditional recommendations.
add_action( 'plugins_loaded', array( 'Jetpack_Recommendations', 'init_conditional_recommendation_actions' ) );
add_filter( 'plugin_row_meta', array( $this, 'add_5_star_review_link' ), 10, 2 );
add_action( 'init', array( Deprecate::class, 'instance' ) );
* Before everything else starts getting initalized, we need to initialize Jetpack using the
public function configure() {
$config->ensure( $feature );
// Identity crisis package.
'admin_page' => '/wp-admin/admin.php?page=jetpack',
$config->ensure( 'search' );
if ( ! $this->connection_manager ) {
$this->connection_manager = new Connection_Manager( 'jetpack' );
$modules = new Automattic\Jetpack\Modules();
if ( $modules->is_active( 'publicize' ) && $this->connection_manager->has_connected_user() ) {
$config->ensure( 'publicize' );
add_action( 'jetpack_initialize_tracking', array( $this, 'initialize_tracking' ) );
* Load things that should only be in Network Admin.
* For now blow away everything else until a more full
* understanding of what is needed at the network level is
$network = Jetpack_Network::init();
$network->set_connection( $this->connection_manager );
$is_connection_ready = self::is_connection_ready();
if ( $is_connection_ready ) {
add_action( 'login_form_jetpack_json_api_authorization', array( $this, 'login_form_json_api_authorization' ) );
$this->run_initialize_tracking_action();
Jetpack_Heartbeat::init();
if ( self::is_module_active( 'stats' ) && self::is_module_active( 'search' ) ) {
require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.jetpack-search-performance-logger.php';
Jetpack_Search_Performance_Logger::init();
add_action( 'jetpack_agreed_to_terms_of_service', array( $this, 'run_initialize_tracking_action' ) );
add_action( 'rest_api_init', array( $this, 'run_initialize_tracking_action' ) );
$this->run_initialize_tracking_action();
// Initialize remote file upload request handlers.
$this->add_remote_request_handlers();
* Enable enhanced handling of previewing sites in Calypso
if ( $is_connection_ready ) {
require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.jetpack-iframe-embed.php';
add_action( 'init', array( 'Jetpack_Iframe_Embed', 'init' ), 9, 0 );
add_action( 'rest_api_init', array( $this, 'maybe_initialize_rest_jsonapi' ) );
* Runs on plugins_loaded. Use this to add code that needs to be executed later than other
public function late_initialization() {
add_action( 'after_setup_theme', array( 'Jetpack', 'load_modules' ), -2 );
My_Jetpack_Initializer::init();
// Initialize Boost Speed Score
new Speed_Score( array(), 'jetpack-dashboard' );
* Fires when Jetpack is fully loaded and ready. This is the point where it's safe
* to instantiate classes from packages and namespaces that are managed by the Jetpack Autoloader.
* @param Jetpack $jetpack the main plugin class object.
do_action( 'jetpack_loaded', $this );
add_filter( 'map_meta_cap', array( $this, 'jetpack_custom_caps' ), 1, 2 );
* This is ported over from the manage module, which has been deprecated and baked in here.
public function add_wpcom_to_allowed_redirect_hosts() {
add_filter( 'allowed_redirect_hosts', array( $this, 'allow_wpcom_domain' ) );
* Return $domains, with 'wordpress.com' appended.
* This is ported over from the manage module, which has been deprecated and baked in here.
* @param array $domains Array of domains allowed for redirect.
public function allow_wpcom_domain( $domains ) {
if ( empty( $domains ) ) {
$domains[] = 'wordpress.com';
return array_unique( $domains );
* Redirect edit post links to Calypso.
* @param string $default_url Post edit URL.
* @param int $post_id Post ID.
public function point_edit_post_links_to_calypso( $default_url, $post_id ) {
_deprecated_function( __METHOD__, '13.9' );
$post = get_post( $post_id );
$post_type = $post->post_type;
// Mapping the allowed CPTs on WordPress.com to corresponding paths in Calypso.
// https://en.support.wordpress.com/custom-post-types/.
$allowed_post_types = array(
if ( ! in_array( $post_type, $allowed_post_types, true ) ) {
return Redirect::get_url(
'calypso-edit-' . $post_type,
* Redirect edit comment links to Calypso.
* @param string $url Comment edit URL.
public function point_edit_comment_links_to_calypso( $url ) {
_deprecated_function( __METHOD__, '13.9' );
// Take the `query` key value from the URL, and parse its parts to the $query_args. `amp;c` matches the comment ID.
wp_parse_str( wp_parse_url( $url, PHP_URL_QUERY ), $query_args );
return Redirect::get_url(
'path' => $query_args['amp;c'],
* Extend Sync callables with Jetpack Plugin functions.
* @param array $callables list of callables.
* @return array list of callables.
public function filter_sync_callable_whitelist( $callables ) {
$jetpack_callables = array(
'single_user_site' => array( 'Jetpack', 'is_single_user_site' ),
'updates' => array( 'Jetpack', 'get_updates' ),
'available_jetpack_blocks' => array( 'Jetpack_Gutenberg', 'get_availability' ), // Includes both Gutenberg blocks *and* plugins.
return array_merge( $callables, $jetpack_callables );
* Extend Sync multisite callables with Jetpack Plugin functions.
* @param array $callables list of callables.
* @return array list of callables.
public function filter_sync_multisite_callable_whitelist( $callables ) {
$jetpack_multisite_callables = array(
'network_name' => array( 'Jetpack', 'network_name' ),
'network_allow_new_registrations' => array( 'Jetpack', 'network_allow_new_registrations' ),
'network_add_new_users' => array( 'Jetpack', 'network_add_new_users' ),