PageRenderTime 72ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 1ms

/blog/wp-content/plugins/jetpack/class.jetpack.php

https://github.com/BrianPrz/hifi-web
PHP | 4368 lines | 3020 code | 603 blank | 745 comment | 554 complexity | 3e6059359f23b417c863e77d827346d3 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /*
  3. Options:
  4. jetpack_options (array)
  5. An array of options.
  6. @see Jetpack_Options::get_option_names()
  7. jetpack_register (string)
  8. Temporary verification secrets.
  9. jetpack_activated (int)
  10. 1: the plugin was activated normally
  11. 2: the plugin was activated on this site because of a network-wide activation
  12. 3: the plugin was auto-installed
  13. 4: the plugin was manually disconnected (but is still installed)
  14. jetpack_active_modules (array)
  15. Array of active module slugs.
  16. jetpack_do_activate (bool)
  17. Flag for "activating" the plugin on sites where the activation hook never fired (auto-installs)
  18. */
  19. class Jetpack {
  20. var $xmlrpc_server = null;
  21. private $xmlrpc_verification = null;
  22. var $HTTP_RAW_POST_DATA = null; // copy of $GLOBALS['HTTP_RAW_POST_DATA']
  23. var $plugins_to_deactivate = array(
  24. 'stats' => array( 'stats/stats.php', 'WordPress.com Stats' ),
  25. 'shortlinks' => array( 'stats/stats.php', 'WordPress.com Stats' ),
  26. 'sharedaddy' => array( 'sharedaddy/sharedaddy.php', 'Sharedaddy' ),
  27. 'twitter-widget' => array( 'wickett-twitter-widget/wickett-twitter-widget.php', 'Wickett Twitter Widget' ),
  28. 'after-the-deadline' => array( 'after-the-deadline/after-the-deadline.php', 'After The Deadline' ),
  29. 'contact-form' => array( 'grunion-contact-form/grunion-contact-form.php', 'Grunion Contact Form' ),
  30. 'custom-css' => array( 'safecss/safecss.php', 'WordPress.com Custom CSS' ),
  31. 'random-redirect' => array( 'random-redirect/random-redirect.php', 'Random Redirect' ),
  32. 'videopress' => array( 'video/video.php', 'VideoPress' ),
  33. 'widget-visibility' => array( 'jetpack-widget-visibility/widget-visibility.php', 'Jetpack Widget Visibility' ),
  34. 'widget-visibility' => array( 'widget-visibility-without-jetpack/widget-visibility-without-jetpack.php', 'Widget Visibility Without Jetpack' ),
  35. 'sharedaddy' => array( 'jetpack-sharing/sharedaddy.php', 'Jetpack Sharing' ),
  36. 'omnisearch' => array( 'jetpack-omnisearch/omnisearch.php', 'Jetpack Omnisearch' ),
  37. 'gravatar-hovercards' => array( 'jetpack-gravatar-hovercards/gravatar-hovercards.php', 'Jetpack Gravatar Hovercards' ),
  38. 'latex' => array( 'wp-latex/wp-latex.php', 'WP LaTeX' ),
  39. );
  40. var $capability_translations = array(
  41. 'administrator' => 'manage_options',
  42. 'editor' => 'edit_others_posts',
  43. 'author' => 'publish_posts',
  44. 'contributor' => 'edit_posts',
  45. 'subscriber' => 'read',
  46. );
  47. /**
  48. * Map of modules that have conflicts with plugins and should not be auto-activated
  49. * if the plugins are active. Used by filter_default_modules
  50. *
  51. * Plugin Authors: If you'd like to prevent a single module from auto-activating,
  52. * change `module-slug` and add this to your plugin:
  53. *
  54. * add_filter( 'jetpack_get_default_modules', 'my_jetpack_get_default_modules' );
  55. * function my_jetpack_get_default_modules( $modules ) {
  56. * return array_diff( $modules, array( 'module-slug' ) );
  57. * }
  58. *
  59. * @var array
  60. */
  61. private $conflicting_plugins = array(
  62. 'comments' => array(
  63. 'Intense Debate' => 'intensedebate/intensedebate.php',
  64. 'Disqus' => 'disqus-comment-system/disqus.php',
  65. 'Livefyre' => 'livefyre-comments/livefyre.php',
  66. 'Comments Evolved for WordPress' => 'gplus-comments/comments-evolved.php',
  67. 'Google+ Comments' => 'google-plus-comments/google-plus-comments.php',
  68. ),
  69. 'contact-form' => array(
  70. 'Contact Form 7' => 'contact-form-7/wp-contact-form-7.php',
  71. 'Gravity Forms' => 'gravityforms/gravityforms.php',
  72. 'Contact Form Plugin' => 'contact-form-plugin/contact_form.php',
  73. 'Easy Contact Forms' => 'easy-contact-forms/easy-contact-forms.php',
  74. 'Fast Secure Contact Form' => 'si-contact-form/si-contact-form.php',
  75. ),
  76. 'gplus-authorship' => array(
  77. 'WP SEO by Yoast' => 'wordpress-seo/wp-seo.php',
  78. ),
  79. 'minileven' => array(
  80. 'WPtouch' => 'wptouch/wptouch.php',
  81. ),
  82. 'latex' => array(
  83. 'LaTeX for WordPress' => 'latex/latex.php',
  84. 'Youngwhans Simple Latex' => 'youngwhans-simple-latex/yw-latex.php',
  85. 'Easy WP LaTeX' => 'easy-wp-latex-lite/easy-wp-latex-lite.php',
  86. 'MathJax-LaTeX' => 'mathjax-latex/mathjax-latex.php',
  87. 'Enable Latex' => 'enable-latex/enable-latex.php',
  88. 'WP QuickLaTeX' => 'wp-quicklatex/wp-quicklatex.php',
  89. ),
  90. 'random-redirect' => array(
  91. 'Random Redirect 2' => 'random-redirect-2/random-redirect.php',
  92. ),
  93. 'related-posts' => array(
  94. 'YARPP' => 'yet-another-related-posts-plugin/yarpp.php',
  95. 'WordPress Related Posts' => 'wordpress-23-related-posts-plugin/wp_related_posts.php',
  96. 'nrelate Related Content' => 'nrelate-related-content/nrelate-related.php',
  97. 'Contextual Related Posts' => 'contextual-related-posts/contextual-related-posts.php',
  98. 'Related Posts for WordPress' => 'microkids-related-posts/microkids-related-posts.php',
  99. 'outbrain' => 'outbrain/outbrain.php',
  100. 'Shareaholic' => 'shareaholic/shareaholic.php',
  101. 'Sexybookmarks' => 'sexybookmarks/shareaholic.php',
  102. ),
  103. 'sharedaddy' => array(
  104. 'AddThis' => 'addthis/addthis_social_widget.php',
  105. 'Add To Any' => 'add-to-any/add-to-any.php',
  106. 'ShareThis' => 'share-this/sharethis.php',
  107. 'Shareaholic' => 'shareaholic/shareaholic.php',
  108. ),
  109. 'widget-visibility' => array(
  110. 'Widget Logic' => 'widget-logic/widget_logic.php',
  111. 'Dynamic Widgets' => 'dynamic-widgets/dynamic-widgets.php',
  112. ),
  113. );
  114. /**
  115. * Message to display in admin_notice
  116. * @var string
  117. */
  118. var $message = '';
  119. /**
  120. * Error to display in admin_notice
  121. * @var string
  122. */
  123. var $error = '';
  124. /**
  125. * Modules that need more privacy description.
  126. * @var string
  127. */
  128. var $privacy_checks = '';
  129. /**
  130. * Stats to record once the page loads
  131. *
  132. * @var array
  133. */
  134. var $stats = array();
  135. /**
  136. * Jetpack_Sync object
  137. */
  138. var $sync;
  139. /**
  140. * Verified data for JSON authorization request
  141. */
  142. var $json_api_authorization_request = array();
  143. /**
  144. * Holds the singleton instance of this class
  145. * @since 2.3.3
  146. * @var Jetpack
  147. */
  148. static $instance = false;
  149. /**
  150. * Singleton
  151. * @static
  152. */
  153. public static function init() {
  154. if ( ! self::$instance ) {
  155. if ( did_action( 'plugins_loaded' ) )
  156. self::plugin_textdomain();
  157. else
  158. add_action( 'plugins_loaded', array( __CLASS__, 'plugin_textdomain' ) );
  159. self::$instance = new Jetpack;
  160. self::$instance->plugin_upgrade();
  161. }
  162. return self::$instance;
  163. }
  164. /**
  165. * Must never be called statically
  166. */
  167. function plugin_upgrade() {
  168. // Upgrade: 1.1 -> 1.2
  169. if ( get_option( 'jetpack_id' ) ) {
  170. // Move individual jetpack options to single array of options
  171. $options = array();
  172. foreach ( Jetpack_Options::get_option_names() as $option ) {
  173. if ( false !== $value = get_option( "jetpack_$option" ) ) {
  174. $options[$option] = $value;
  175. }
  176. }
  177. if ( $options ) {
  178. Jetpack_Options::update_options( $options );
  179. foreach ( array_keys( $options ) as $option ) {
  180. delete_option( "jetpack_$option" );
  181. }
  182. }
  183. // Add missing version and old_version options
  184. if ( ! $version = Jetpack_Options::get_option( 'version' ) ) {
  185. $version = $old_version = '1.1:' . time();
  186. Jetpack_Options::update_options( compact( 'version', 'old_version' ) );
  187. }
  188. }
  189. // Upgrade from a single user token to a user_id-indexed array and a master_user ID
  190. if ( ! Jetpack_Options::get_option( 'user_tokens' ) ) {
  191. if ( $user_token = Jetpack_Options::get_option( 'user_token' ) ) {
  192. $token_parts = explode( '.', $user_token );
  193. if ( isset( $token_parts[2] ) ) {
  194. $master_user = $token_parts[2];
  195. $user_tokens = array( $master_user => $user_token );
  196. Jetpack_Options::update_options( compact( 'master_user', 'user_tokens' ) );
  197. Jetpack_Options::delete_option( 'user_token' );
  198. } else {
  199. // @todo: is this even possible?
  200. trigger_error( sprintf( 'Jetpack::plugin_upgrade found no user_id in user_token "%s"', $user_token ), E_USER_WARNING );
  201. }
  202. }
  203. }
  204. }
  205. /**
  206. * Constructor. Initializes WordPress hooks
  207. */
  208. private function Jetpack() {
  209. /*
  210. * Load things that should only be in Network Admin.
  211. *
  212. * For now blow away everything else until a more full
  213. * understanding of what is needed at the network level is
  214. * available
  215. */
  216. if( is_multisite() ) {
  217. $jpms = Jetpack_Network::init();
  218. if( is_network_admin() )
  219. return; // End here to prevent single site actions from firing
  220. }
  221. $this->sync = new Jetpack_Sync;
  222. // Modules should do Jetpack_Sync::sync_options( __FILE__, $option, ... ); instead
  223. // We access the "internal" method here only because the Jetpack object isn't instantiated yet
  224. $this->sync->options(
  225. JETPACK__PLUGIN_DIR . 'jetpack.php',
  226. 'home',
  227. 'siteurl',
  228. 'blogname',
  229. 'gmt_offset',
  230. 'timezone_string'
  231. );
  232. if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST && isset( $_GET['for'] ) && 'jetpack' == $_GET['for'] ) {
  233. @ini_set( 'display_errors', false ); // Display errors can cause the XML to be not well formed.
  234. require_once JETPACK__PLUGIN_DIR . 'class.jetpack-xmlrpc-server.php';
  235. $this->xmlrpc_server = new Jetpack_XMLRPC_Server();
  236. $this->require_jetpack_authentication();
  237. if ( Jetpack::is_active() ) {
  238. // Hack to preserve $HTTP_RAW_POST_DATA
  239. add_filter( 'xmlrpc_methods', array( $this, 'xmlrpc_methods' ) );
  240. $signed = $this->verify_xml_rpc_signature();
  241. if ( $signed && ! is_wp_error( $signed ) ) {
  242. // The actual API methods.
  243. add_filter( 'xmlrpc_methods', array( $this->xmlrpc_server, 'xmlrpc_methods' ) );
  244. } else {
  245. add_filter( 'xmlrpc_methods', '__return_empty_array' );
  246. }
  247. } else {
  248. // The bootstrap API methods.
  249. add_filter( 'xmlrpc_methods', array( $this->xmlrpc_server, 'bootstrap_xmlrpc_methods' ) );
  250. }
  251. // Now that no one can authenticate, and we're whitelisting all XML-RPC methods, force enable_xmlrpc on.
  252. add_filter( 'pre_option_enable_xmlrpc', '__return_true' );
  253. } elseif ( is_admin() && isset( $_POST['action'] ) && 'jetpack_upload_file' == $_POST['action'] ) {
  254. $this->require_jetpack_authentication();
  255. $this->add_remote_request_handlers();
  256. } else {
  257. if ( Jetpack::is_active() ) {
  258. add_action( 'login_form_jetpack_json_api_authorization', array( &$this, 'login_form_json_api_authorization' ) );
  259. }
  260. }
  261. if ( Jetpack::is_active() ) {
  262. Jetpack_Heartbeat::init();
  263. }
  264. add_action( 'jetpack_clean_nonces', array( 'Jetpack', 'clean_nonces' ) );
  265. if ( ! wp_next_scheduled( 'jetpack_clean_nonces' ) ) {
  266. wp_schedule_event( time(), 'hourly', 'jetpack_clean_nonces' );
  267. }
  268. add_filter( 'xmlrpc_blog_options', array( $this, 'xmlrpc_options' ) );
  269. add_action( 'admin_menu', array( $this, 'admin_menu' ), 999 ); // run late so that other plugins hooking into this menu don't get left out
  270. add_action( 'admin_init', array( $this, 'admin_init' ) );
  271. add_action( 'admin_init', array( $this, 'dismiss_jetpack_notice' ) );
  272. add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) );
  273. add_action( 'wp_ajax_jetpack-check-news-subscription', array( $this, 'check_news_subscription' ) );
  274. add_action( 'wp_ajax_jetpack-subscribe-to-news', array( $this, 'subscribe_to_news' ) );
  275. add_action( 'wp_ajax_jetpack-sync-reindex-trigger', array( $this, 'sync_reindex_trigger' ) );
  276. add_action( 'wp_ajax_jetpack-sync-reindex-status', array( $this, 'sync_reindex_status' ) );
  277. add_action( 'wp_loaded', array( $this, 'register_assets' ) );
  278. add_action( 'wp_enqueue_scripts', array( $this, 'devicepx' ) );
  279. add_action( 'customize_controls_enqueue_scripts', array( $this, 'devicepx' ) );
  280. add_action( 'admin_enqueue_scripts', array( $this, 'devicepx' ) );
  281. add_filter( 'jetpack_require_lib_dir', array( $this, 'require_lib_dir' ) );
  282. // add_action( 'jetpack_admin_menu', array( $this, 'admin_menu_modules' ) );
  283. add_action( 'jetpack_activate_module', array( $this, 'activate_module_actions' ) );
  284. add_action( 'plugins_loaded', array( $this, 'extra_oembed_providers' ) );
  285. /**
  286. * These actions run checks to load additional files.
  287. * They check for external files or plugins, so they need to run as late as possible.
  288. */
  289. add_action( 'wp_head', array( $this, 'check_open_graph' ), 1 );
  290. add_action( 'plugins_loaded', array( $this, 'check_twitter_tags' ), 999 );
  291. add_action( 'plugins_loaded', array( $this, 'check_rest_api_compat' ), 1000 );
  292. add_filter( 'map_meta_cap', array( $this, 'jetpack_custom_caps' ), 1, 4 );
  293. add_filter( 'jetpack_get_default_modules', array( $this, 'filter_default_modules' ) );
  294. add_filter( 'jetpack_get_default_modules', array( $this, 'handle_deprecated_modules' ), 99 );
  295. }
  296. /**
  297. * If there are any stats that need to be pushed, but haven't been, push them now.
  298. */
  299. function __destruct() {
  300. if ( ! empty( $this->stats ) ) {
  301. $this->do_stats( 'server_side' );
  302. }
  303. }
  304. function jetpack_custom_caps( $caps, $cap, $user_id, $args ) {
  305. switch( $cap ) {
  306. case 'jetpack_disconnect' :
  307. case 'jetpack_reconnect' :
  308. $caps = array( 'manage_options' );
  309. break;
  310. }
  311. return $caps;
  312. }
  313. function require_jetpack_authentication() {
  314. // Don't let anyone authenticate
  315. $_COOKIE = array();
  316. remove_all_filters( 'authenticate' );
  317. /**
  318. * For the moment, remove Limit Login Attempts if its xmlrpc for Jetpack.
  319. * If Limit Login Attempts is installed as a mu-plugin, it can occasionally
  320. * generate false-positives.
  321. */
  322. remove_filter( 'wp_login_failed', 'limit_login_failed' );
  323. if ( Jetpack::is_active() ) {
  324. // Allow Jetpack authentication
  325. add_filter( 'authenticate', array( $this, 'authenticate_jetpack' ), 10, 3 );
  326. }
  327. }
  328. /**
  329. * Load language files
  330. */
  331. public static function plugin_textdomain() {
  332. load_plugin_textdomain( 'jetpack', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
  333. }
  334. /**
  335. * Register assets for use in various modules and the Jetpack admin page.
  336. *
  337. * @uses wp_script_is, wp_register_script, plugins_url
  338. * @action wp_loaded
  339. * @return null
  340. */
  341. public function register_assets() {
  342. if ( ! wp_script_is( 'spin', 'registered' ) )
  343. wp_register_script( 'spin', plugins_url( '_inc/spin.js', __FILE__ ), false, '1.3' );
  344. if ( ! wp_script_is( 'jquery.spin', 'registered' ) )
  345. wp_register_script( 'jquery.spin', plugins_url( '_inc/jquery.spin.js', __FILE__ ) , array( 'jquery', 'spin' ), '1.3' );
  346. if ( ! wp_script_is( 'jetpack-gallery-settings', 'registered' ) )
  347. wp_register_script( 'jetpack-gallery-settings', plugins_url( '_inc/gallery-settings.js', __FILE__ ), array( 'media-views' ), '20121225' );
  348. /**
  349. * As jetpack_register_genericons is by default fired off a hook,
  350. * the hook may have already fired by this point.
  351. * So, let's just trigger it manually.
  352. */
  353. require_once( JETPACK__PLUGIN_DIR . '_inc/genericons.php' );
  354. jetpack_register_genericons();
  355. if ( ! wp_style_is( 'jetpack-icons', 'registered' ) )
  356. wp_register_style( 'jetpack-icons', plugins_url( '_inc/jetpack-icons/jetpack-icons.css', __FILE__ ), false, JETPACK__VERSION );
  357. }
  358. /**
  359. * Device Pixels support
  360. * This improves the resolution of gravatars and wordpress.com uploads on hi-res and zoomed browsers.
  361. */
  362. function devicepx() {
  363. if ( Jetpack::is_active() ) {
  364. wp_enqueue_script( 'devicepx', set_url_scheme( 'http://s0.wp.com/wp-content/js/devicepx-jetpack.js' ), array(), gmdate( 'oW' ), true );
  365. }
  366. }
  367. /*
  368. * Returns the location of Jetpack's lib directory. This filter is applied
  369. * in require_lib().
  370. *
  371. * @filter require_lib_dir
  372. */
  373. function require_lib_dir( $lib_dir ) {
  374. return JETPACK__PLUGIN_DIR . '_inc/lib';
  375. }
  376. /**
  377. * Is Jetpack active?
  378. */
  379. public static function is_active() {
  380. return (bool) Jetpack_Data::get_access_token( JETPACK_MASTER_USER );
  381. }
  382. /**
  383. * Is Jetpack in development (offline) mode?
  384. */
  385. public static function is_development_mode() {
  386. $development_mode = false;
  387. if ( defined( 'JETPACK_DEV_DEBUG' ) ) {
  388. $development_mode = JETPACK_DEV_DEBUG;
  389. }
  390. elseif ( site_url() && false === strpos( site_url(), '.' ) ) {
  391. $development_mode = true;
  392. }
  393. return apply_filters( 'jetpack_development_mode', $development_mode );
  394. }
  395. /**
  396. * Is a given user (or the current user if none is specified) linked to a WordPress.com user?
  397. */
  398. public static function is_user_connected( $user_id = false ) {
  399. $user_id = false === $user_id ? get_current_user_id() : absint( $user_id );
  400. if ( ! $user_id ) {
  401. return false;
  402. }
  403. return (bool) Jetpack_Data::get_access_token( $user_id );
  404. }
  405. /**
  406. * Get the wpcom email of the current connected user.
  407. */
  408. public static function get_connected_user_email() {
  409. Jetpack::load_xml_rpc_client();
  410. $xml = new Jetpack_IXR_Client( array(
  411. 'user_id' => get_current_user_id()
  412. ) );
  413. $xml->query( 'wpcom.getUserEmail' );
  414. if ( ! $xml->isError() ) {
  415. return $xml->getResponse();
  416. }
  417. return false;
  418. }
  419. function current_user_is_connection_owner() {
  420. $user_token = Jetpack_Data::get_access_token( JETPACK_MASTER_USER );
  421. return $user_token && is_object( $user_token ) && isset( $user_token->external_user_id ) && get_current_user_id() === $user_token->external_user_id;
  422. }
  423. /**
  424. * Add any extra oEmbed providers that we know about and use on wpcom for feature parity.
  425. */
  426. function extra_oembed_providers() {
  427. // Cloudup: https://dev.cloudup.com/#oembed
  428. wp_oembed_add_provider( 'https://cloudup.com/*' , 'https://cloudup.com/oembed' );
  429. }
  430. /**
  431. * Synchronize connected user role changes
  432. */
  433. function user_role_change( $user_id ) {
  434. if ( Jetpack::is_active() && Jetpack::is_user_connected( $user_id ) ) {
  435. $current_user_id = get_current_user_id();
  436. wp_set_current_user( $user_id );
  437. $role = $this->translate_current_user_to_role();
  438. $signed_role = $this->sign_role( $role );
  439. wp_set_current_user( $current_user_id );
  440. $master_token = Jetpack_Data::get_access_token( JETPACK_MASTER_USER );
  441. $master_user_id = absint( $master_token->external_user_id );
  442. if ( ! $master_user_id )
  443. return; // this shouldn't happen
  444. Jetpack::xmlrpc_async_call( 'jetpack.updateRole', $user_id, $signed_role );
  445. //@todo retry on failure
  446. //try to choose a new master if we're demoting the current one
  447. if ( $user_id == $master_user_id && 'administrator' != $role ) {
  448. $query = new WP_User_Query(
  449. array(
  450. 'fields' => array( 'id' ),
  451. 'role' => 'administrator',
  452. 'orderby' => 'id',
  453. 'exclude' => array( $master_user_id ),
  454. )
  455. );
  456. $new_master = false;
  457. foreach ( $query->results as $result ) {
  458. $uid = absint( $result->id );
  459. if ( $uid && Jetpack::is_user_connected( $uid ) ) {
  460. $new_master = $uid;
  461. break;
  462. }
  463. }
  464. if ( $new_master ) {
  465. Jetpack_Options::update_option( 'master_user', $new_master );
  466. }
  467. // else disconnect..?
  468. }
  469. }
  470. }
  471. /**
  472. * Loads the currently active modules.
  473. */
  474. public static function load_modules() {
  475. /*
  476. if ( ! Jetpack::is_active() && ! Jetpack::is_development_mode() ) {
  477. return;
  478. }
  479. */
  480. $version = Jetpack_Options::get_option( 'version' );
  481. if ( ! $version ) {
  482. $version = $old_version = JETPACK__VERSION . ':' . time();
  483. Jetpack_Options::update_options( compact( 'version', 'old_version' ) );
  484. }
  485. list( $version ) = explode( ':', $version );
  486. $modules = array_filter( Jetpack::get_active_modules(), array( 'Jetpack', 'is_module' ) );
  487. $modules_data = array();
  488. // Don't load modules that have had "Major" changes since the stored version until they have been deactivated/reactivated through the lint check.
  489. if ( version_compare( $version, JETPACK__VERSION, '<' ) ) {
  490. $updated_modules = array();
  491. foreach ( $modules as $module ) {
  492. $modules_data[ $module ] = Jetpack::get_module( $module );
  493. if ( ! isset( $modules_data[ $module ]['changed'] ) ) {
  494. continue;
  495. }
  496. if ( version_compare( $modules_data[ $module ]['changed'], $version, '<=' ) ) {
  497. continue;
  498. }
  499. $updated_modules[] = $module;
  500. }
  501. $modules = array_diff( $modules, $updated_modules );
  502. }
  503. foreach ( $modules as $module ) {
  504. // If not connected and we're in dev mode, disable modules requiring a connection
  505. if ( ! Jetpack::is_active() ) {
  506. if ( empty( $modules_data[ $module ] ) ) {
  507. $modules_data[ $module ] = Jetpack::get_module( $module );
  508. }
  509. if ( $modules_data[ $module ]['requires_connection'] || ! Jetpack::is_development_mode() ) {
  510. continue;
  511. }
  512. }
  513. if ( did_action( 'jetpack_module_loaded_' . $module ) ) {
  514. continue;
  515. }
  516. require Jetpack::get_module_path( $module );
  517. do_action( 'jetpack_module_loaded_' . $module );
  518. }
  519. do_action( 'jetpack_modules_loaded' );
  520. // 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.
  521. if ( Jetpack::is_active() || Jetpack::is_development_mode() )
  522. require_once( JETPACK__PLUGIN_DIR . 'modules/module-extras.php' );
  523. }
  524. /**
  525. * Check if Jetpack's REST API compat file should be included
  526. * @action plugins_loaded
  527. * @return null
  528. */
  529. public function check_rest_api_compat() {
  530. $_jetpack_rest_api_compat_includes = apply_filters( 'jetpack_rest_api_compat', array() );
  531. if ( function_exists( 'bbpress' ) )
  532. $_jetpack_rest_api_compat_includes[] = JETPACK__PLUGIN_DIR . 'class.jetpack-bbpress-json-api-compat.php';
  533. foreach ( $_jetpack_rest_api_compat_includes as $_jetpack_rest_api_compat_include )
  534. require_once $_jetpack_rest_api_compat_include;
  535. }
  536. /**
  537. * Check if Jetpack's Open Graph tags should be used.
  538. * If certain plugins are active, Jetpack's og tags are suppressed.
  539. *
  540. * @uses Jetpack::get_active_modules, add_filter, get_option, apply_filters
  541. * @action plugins_loaded
  542. * @return null
  543. */
  544. public function check_open_graph() {
  545. if ( in_array( 'publicize', Jetpack::get_active_modules() ) || in_array( 'sharedaddy', Jetpack::get_active_modules() ) )
  546. add_filter( 'jetpack_enable_open_graph', '__return_true', 0 );
  547. $active_plugins = get_option( 'active_plugins', array() );
  548. if ( is_multisite() ) {
  549. // Due to legacy code, active_sitewide_plugins stores them in the keys,
  550. // whereas active_plugins stores them in the values.
  551. $network_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) );
  552. if ( $network_plugins ) {
  553. $active_plugins = array_merge( $active_plugins, $network_plugins );
  554. }
  555. }
  556. $conflicting_plugins = array(
  557. 'facebook/facebook.php', // Official Facebook plugin
  558. 'wordpress-seo/wp-seo.php', // WordPress SEO by Yoast
  559. 'add-link-to-facebook/add-link-to-facebook.php', // Add Link to Facebook
  560. 'facebook-awd/AWD_facebook.php', // Facebook AWD All in one
  561. 'header-footer/plugin.php', // Header and Footer
  562. 'nextgen-facebook/nextgen-facebook.php', // NextGEN Facebook OG
  563. 'seo-facebook-comments/seofacebook.php', // SEO Facebook Comments
  564. 'seo-ultimate/seo-ultimate.php', // SEO Ultimate
  565. 'sexybookmarks/sexy-bookmarks.php', // Shareaholic
  566. 'shareaholic/sexy-bookmarks.php', // Shareaholic
  567. 'social-discussions/social-discussions.php', // Social Discussions
  568. 'social-networks-auto-poster-facebook-twitter-g/NextScripts_SNAP.php', // NextScripts SNAP
  569. 'wordbooker/wordbooker.php', // Wordbooker
  570. 'socialize/socialize.php', // Socialize
  571. 'simple-facebook-connect/sfc.php', // Simple Facebook Connect
  572. 'social-sharing-toolkit/social_sharing_toolkit.php', // Social Sharing Toolkit
  573. 'wp-facebook-open-graph-protocol/wp-facebook-ogp.php', // WP Facebook Open Graph protocol
  574. 'opengraph/opengraph.php', // Open Graph
  575. 'sharepress/sharepress.php', // SharePress
  576. 'wp-facebook-like-send-open-graph-meta/wp-facebook-like-send-open-graph-meta.php', // WP Facebook Like Send & Open Graph Meta
  577. 'network-publisher/networkpub.php', // Network Publisher
  578. 'wp-ogp/wp-ogp.php', // WP-OGP
  579. 'open-graph-protocol-framework/open-graph-protocol-framework.php', // Open Graph Protocol Framework
  580. 'all-in-one-seo-pack/all_in_one_seo_pack.php', // All in One SEO Pack
  581. 'facebook-featured-image-and-open-graph-meta-tags/fb-featured-image.php', // Facebook Featured Image & OG Meta Tags
  582. 'add-meta-tags/add-meta-tags.php', // Add Meta Tags
  583. 'only-tweet-like-share-and-google-1/tweet-like-plusone.php', // Tweet, Like, Google +1 and Share
  584. 'easy-facebook-share-thumbnails/esft.php', // Easy Facebook Share Thumbnail
  585. '2-click-socialmedia-buttons/2-click-socialmedia-buttons.php', // 2 Click Social Media Buttons
  586. 'facebook-thumb-fixer/_facebook-thumb-fixer.php', // Facebook Thumb Fixer
  587. 'zoltonorg-social-plugin/zosp.php', // Zolton.org Social Plugin
  588. 'wp-caregiver/wp-caregiver.php', // WP Caregiver
  589. 'facebook-revised-open-graph-meta-tag/index.php', // Facebook Revised Open Graph Meta Tag
  590. 'facebook-and-digg-thumbnail-generator/facebook-and-digg-thumbnail-generator.php', // Fedmich's Facebook Open Graph Meta
  591. 'facebook-meta-tags/facebook-metatags.php', // Facebook Meta Tags
  592. );
  593. foreach ( $conflicting_plugins as $plugin ) {
  594. if ( in_array( $plugin, $active_plugins ) ) {
  595. add_filter( 'jetpack_enable_open_graph', '__return_false', 99 );
  596. break;
  597. }
  598. }
  599. if ( apply_filters( 'jetpack_enable_open_graph', false ) )
  600. require_once JETPACK__PLUGIN_DIR . 'functions.opengraph.php';
  601. }
  602. /**
  603. * Check if Jetpack's Twitter tags should be used.
  604. * If certain plugins are active, Jetpack's twitter tags are suppressed.
  605. *
  606. * @uses Jetpack::get_active_modules, add_filter, get_option, apply_filters
  607. * @action plugins_loaded
  608. * @return null
  609. */
  610. public function check_twitter_tags() {
  611. $active_plugins = get_option( 'active_plugins', array() );
  612. if ( is_multisite() ) {
  613. // Due to legacy code, active_sitewide_plugins stores them in the keys,
  614. // whereas active_plugins stores them in the values.
  615. $network_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) );
  616. if ( $network_plugins ) {
  617. $active_plugins = array_merge( $active_plugins, $network_plugins );
  618. }
  619. }
  620. $conflicting_plugins = array(
  621. 'twitter-cards/twitter-cards.php', // Twitter Cards
  622. 'twitter-cards-meta/twitter-cards-meta.php', // Twitter Cards Meta
  623. 'ig-twitter-cards/ig-twitter-cards.php', // IG:Twitter Cards
  624. 'jm-twitter-cards/jm-twitter-cards.php', // JM Twitter Cards
  625. 'wp-twitter-cards/twitter_cards.php', // WP Twitter Cards
  626. 'eewee-twitter-card/index.php', // Eewee Twitter Card
  627. 'kevinjohn-gallagher-pure-web-brilliants-social-graph-twitter-cards-extention/kevinjohn_gallagher___social_graph_twitter_output.php', // Pure Web Brilliant's Social Graph Twitter Cards Extention
  628. );
  629. foreach ( $conflicting_plugins as $plugin ) {
  630. if ( in_array( $plugin, $active_plugins ) ) {
  631. add_filter( 'jetpack_disable_twitter_cards', '__return_true', 99 );
  632. break;
  633. }
  634. }
  635. if ( apply_filters( 'jetpack_disable_twitter_cards', true ) )
  636. require_once JETPACK__PLUGIN_DIR . 'functions.twitter-cards.php';
  637. }
  638. /* Jetpack Options API */
  639. public static function get_option_names( $type = 'compact' ) {
  640. return Jetpack_Options::get_option_names( $type );
  641. }
  642. /**
  643. * Returns the requested option. Looks in jetpack_options or jetpack_$name as appropriate.
  644. *
  645. * @param string $name Option name
  646. * @param mixed $default (optional)
  647. */
  648. public static function get_option( $name, $default = false ) {
  649. return Jetpack_Options::get_option( $name, $default );
  650. }
  651. /**
  652. * Stores two secrets and a timestamp so WordPress.com can make a request back and verify an action
  653. * Does some extra verification so urls (such as those to public-api, register, etc) cant just be crafted
  654. * $name must be a registered option name.
  655. */
  656. public static function create_nonce( $name ) {
  657. $secret = wp_generate_password( 32, false ) . ':' . wp_generate_password( 32, false ) . ':' . ( time() + 600 );
  658. Jetpack_Options::update_option( $name, $secret );
  659. @list( $secret_1, $secret_2, $eol ) = explode( ':', Jetpack_Options::get_option( $name ) );
  660. if ( empty( $secret_1 ) || empty( $secret_2 ) || $eol < time() )
  661. return new Jetpack_Error( 'missing_secrets' );
  662. return array(
  663. 'secret_1' => $secret_1,
  664. 'secret_2' => $secret_2,
  665. 'eol' => $eol,
  666. );
  667. }
  668. /**
  669. * Updates the single given option. Updates jetpack_options or jetpack_$name as appropriate.
  670. *
  671. * @param string $name Option name
  672. * @param mixed $value Option value
  673. */
  674. public static function update_option( $name, $value ) {
  675. return Jetpack_Options::update_option( $name, $value );
  676. }
  677. /**
  678. * Updates the multiple given options. Updates jetpack_options and/or jetpack_$name as appropriate.
  679. *
  680. * @param array $array array( option name => option value, ... )
  681. */
  682. public static function update_options( $array ) {
  683. return Jetpack_Options::update_options( $array );
  684. }
  685. /**
  686. * Deletes the given option. May be passed multiple option names as an array.
  687. * Updates jetpack_options and/or deletes jetpack_$name as appropriate.
  688. *
  689. * @param string|array $names
  690. */
  691. public static function delete_option( $names ) {
  692. return Jetpack_Options::delete_option( $names );
  693. }
  694. /**
  695. * Enters a user token into the user_tokens option
  696. *
  697. * @param int $user_id
  698. * @param string $token
  699. * return bool
  700. */
  701. public static function update_user_token( $user_id, $token, $is_master_user ) {
  702. // not designed for concurrent updates
  703. $user_tokens = Jetpack_Options::get_option( 'user_tokens' );
  704. if ( ! is_array( $user_tokens ) )
  705. $user_tokens = array();
  706. $user_tokens[$user_id] = $token;
  707. if ( $is_master_user ) {
  708. $master_user = $user_id;
  709. $options = compact( 'user_tokens', 'master_user' );
  710. } else {
  711. $options = compact( 'user_tokens' );
  712. }
  713. return Jetpack_Options::update_options( $options );
  714. }
  715. /**
  716. * Returns an array of all PHP files in the specified absolute path.
  717. * Equivalent to glob( "$absolute_path/*.php" ).
  718. *
  719. * @param string $absolute_path The absolute path of the directory to search.
  720. * @return array Array of absolute paths to the PHP files.
  721. */
  722. public static function glob_php( $absolute_path ) {
  723. $absolute_path = untrailingslashit( $absolute_path );
  724. $files = array();
  725. if ( ! $dir = @opendir( $absolute_path ) ) {
  726. return $files;
  727. }
  728. while ( false !== $file = readdir( $dir ) ) {
  729. if ( '.' == substr( $file, 0, 1 ) || '.php' != substr( $file, -4 ) ) {
  730. continue;
  731. }
  732. $file = "$absolute_path/$file";
  733. if ( ! is_file( $file ) ) {
  734. continue;
  735. }
  736. $files[] = $file;
  737. }
  738. closedir( $dir );
  739. return $files;
  740. }
  741. public function activate_new_modules() {
  742. if ( ! Jetpack::is_active() && ! Jetpack::is_development_mode() ) {
  743. return;
  744. }
  745. $jetpack_old_version = Jetpack_Options::get_option( 'version' ); // [sic]
  746. if ( ! $jetpack_old_version ) {
  747. $jetpack_old_version = $version = $old_version = '1.1:' . time();
  748. Jetpack_Options::update_options( compact( 'version', 'old_version' ) );
  749. }
  750. list( $jetpack_version ) = explode( ':', $jetpack_old_version ); // [sic]
  751. if ( version_compare( JETPACK__VERSION, $jetpack_version, '<=' ) ) {
  752. return;
  753. }
  754. $active_modules = Jetpack::get_active_modules();
  755. $reactivate_modules = array();
  756. foreach ( $active_modules as $active_module ) {
  757. $module = Jetpack::get_module( $active_module );
  758. if ( ! isset( $module['changed'] ) ) {
  759. continue;
  760. }
  761. if ( version_compare( $module['changed'], $jetpack_version, '<=' ) ) {
  762. continue;
  763. }
  764. $reactivate_modules[] = $active_module;
  765. Jetpack::deactivate_module( $active_module );
  766. }
  767. if ( version_compare( $jetpack_version, '1.9.2', '<' ) && version_compare( '1.9-something', JETPACK__VERSION, '<' ) ) {
  768. add_action( 'jetpack_activate_default_modules', array( $this->sync, 'sync_all_registered_options' ), 1000 );
  769. }
  770. Jetpack_Options::update_options(
  771. array(
  772. 'version' => JETPACK__VERSION . ':' . time(),
  773. 'old_version' => $jetpack_old_version,
  774. )
  775. );
  776. Jetpack::state( 'message', 'modules_activated' );
  777. Jetpack::activate_default_modules( $jetpack_version, JETPACK__VERSION, $reactivate_modules );
  778. wp_safe_redirect( Jetpack::admin_url( 'page=jetpack' ) );
  779. exit;
  780. }
  781. /**
  782. * List available Jetpack modules. Simply lists .php files in /modules/.
  783. * Make sure to tuck away module "library" files in a sub-directory.
  784. */
  785. public static function get_available_modules( $min_version = false, $max_version = false ) {
  786. static $modules = null;
  787. if ( ! isset( $modules ) ) {
  788. $files = Jetpack::glob_php( JETPACK__PLUGIN_DIR . 'modules' );
  789. $modules = array();
  790. foreach ( $files as $file ) {
  791. if ( ! $headers = Jetpack::get_module( $file ) ) {
  792. continue;
  793. }
  794. $modules[ Jetpack::get_module_slug( $file ) ] = $headers['introduced'];
  795. }
  796. }
  797. $modules = apply_filters( 'jetpack_get_available_modules', $modules, $min_version, $max_version );
  798. if ( ! $min_version && ! $max_version ) {
  799. return array_keys( $modules );
  800. }
  801. $r = array();
  802. foreach ( $modules as $slug => $introduced ) {
  803. if ( $min_version && version_compare( $min_version, $introduced, '>=' ) ) {
  804. continue;
  805. }
  806. if ( $max_version && version_compare( $max_version, $introduced, '<' ) ) {
  807. continue;
  808. }
  809. $r[] = $slug;
  810. }
  811. return $r;
  812. }
  813. /**
  814. * Default modules loaded on activation.
  815. */
  816. public static function get_default_modules( $min_version = false, $max_version = false ) {
  817. $return = array();
  818. foreach ( Jetpack::get_available_modules( $min_version, $max_version ) as $module ) {
  819. $module_data = Jetpack::get_module( $module );
  820. switch ( strtolower( $module_data['auto_activate'] ) ) {
  821. case 'yes' :
  822. $return[] = $module;
  823. break;
  824. case 'public' :
  825. if ( Jetpack_Options::get_option( 'public' ) ) {
  826. $return[] = $module;
  827. }
  828. break;
  829. case 'no' :
  830. default :
  831. break;
  832. }
  833. }
  834. return apply_filters( 'jetpack_get_default_modules', $return, $min_version, $max_version );
  835. }
  836. /**
  837. * Checks activated modules during auto-activation to determine
  838. * if any of those modules are being deprecated. If so, close
  839. * them out, and add any replacement modules.
  840. *
  841. * Runs at priority 99 by default.
  842. *
  843. * This is run late, so that it can still activate a module if
  844. * the new module is a replacement for another that the user
  845. * currently has active, even if something at the normal priority
  846. * would kibosh everything.
  847. *
  848. * @since 2.6
  849. * @uses jetpack_get_default_modules filter
  850. * @param array $modules
  851. * @return array
  852. */
  853. function handle_deprecated_modules( $modules ) {
  854. $deprecated_modules = array(
  855. 'debug' => null, // Closed out and moved to ./class.jetpack-debugger.php
  856. 'wpcc' => 'sso', // Closed out in 2.6 -- SSO provides the same functionality.
  857. );
  858. // Don't activate SSO if they never completed activating WPCC.
  859. if ( Jetpack::is_module_active( 'wpcc' ) ) {
  860. $wpcc_options = Jetpack_Options::get_option( 'wpcc_options' );
  861. if ( empty( $wpcc_options ) || empty( $wpcc_options['client_id'] ) || empty( $wpcc_options['client_id'] ) ) {
  862. $deprecated_modules['wpcc'] = null;
  863. }
  864. }
  865. foreach ( $deprecated_modules as $module => $replacement ) {
  866. if ( Jetpack::is_module_active( $module ) ) {
  867. self::deactivate_module( $module );
  868. if ( $replacement ) {
  869. $modules[] = $replacement;
  870. }
  871. }
  872. }
  873. return array_unique( $modules );
  874. }
  875. /**
  876. * Checks activated plugins during auto-activation to determine
  877. * if any of those plugins are in the list with a corresponding module
  878. * that is not compatible with the plugin. The module will not be allowed
  879. * to auto-activate.
  880. *
  881. * @since 2.6
  882. * @uses jetpack_get_default_modules filter
  883. * @param array $modules
  884. * @return array
  885. */
  886. function filter_default_modules( $modules ) {
  887. $active_plugins = get_option( 'active_plugins', array() );
  888. if ( is_multisite() ) {
  889. // Due to legacy code, active_sitewide_plugins stores them in the keys,
  890. // whereas active_plugins stores them in the values.
  891. $network_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) );
  892. if ( $network_plugins ) {
  893. $active_plugins = array_merge( $active_plugins, $network_plugins );
  894. }
  895. }
  896. sort( $active_plugins );
  897. // For each module we'd like to auto-activate...
  898. foreach ( $modules as $key => $module ) {
  899. // If there are potential conflicts for it...
  900. if ( ! empty( $this->conflicting_plugins[ $module ] ) ) {
  901. // For each potential conflict...
  902. foreach ( $this->conflicting_plugins[ $module ] as $title => $plugin ) {
  903. // If that conflicting plugin is active...
  904. if ( in_array( $plugin, $active_plugins ) ) {
  905. // Remove that item from being auto-activated.
  906. unset( $modules[ $key ] );
  907. }
  908. }
  909. }
  910. }
  911. return $modules;
  912. }
  913. /**
  914. * Extract a module's slug from its full path.
  915. */
  916. public static function get_module_slug( $file ) {
  917. return str_replace( '.php', '', basename( $file ) );
  918. }
  919. /**
  920. * Generate a module's path from its slug.
  921. */
  922. public static function get_module_path( $slug ) {
  923. return JETPACK__PLUGIN_DIR . "modules/$slug.php";
  924. }
  925. /**
  926. * Load module data from module file. Headers differ from WordPress
  927. * plugin headers to avoid them being identified as standalone
  928. * plugins on the WordPress plugins page.
  929. */
  930. public static function get_module( $module ) {
  931. $headers = array(
  932. 'name' => 'Module Name',
  933. 'description' => 'Module Description',
  934. 'sort' => 'Sort Order',
  935. 'introduced' => 'First Introduced',
  936. 'changed' => 'Major Changes In',
  937. 'deactivate' => 'Deactivate',
  938. 'free' => 'Free',
  939. 'requires_connection' => 'Requires Connection',
  940. 'auto_activate' => 'Auto Activate',
  941. 'module_tags' => 'Module Tags',
  942. );
  943. $file = Jetpack::get_module_path( Jetpack::get_module_slug( $module ) );
  944. if ( ! file_exists( $file ) )
  945. return false;
  946. $mod = get_file_data( $file, $headers );
  947. if ( empty( $mod['name'] ) )
  948. return false;
  949. $mod['name'] = translate( $mod['name'], 'jetpack' );
  950. $mod['description'] = translate( $mod['description'], 'jetpack' );
  951. $mod['sort'] = empty( $mod['sort'] ) ? 10 : (int) $mod['sort'];
  952. $mod['deactivate'] = empty( $mod['deactivate'] );
  953. $mod['free'] = empty( $mod['free'] );
  954. $mod['requires_connection'] = ( ! empty( $mod['requires_connection'] ) && 'No' == $mod['requires_connection'] ) ? false : true;
  955. if ( empty( $mod['auto_activate'] ) || ! in_array( strtolower( $mod['auto_activate'] ), array( 'yes', 'no', 'public' ) ) ) {
  956. $mod['auto_activate'] = 'No';
  957. } else {
  958. $mod['auto_activate'] = (string) $mod['auto_activate'];
  959. }
  960. if ( $mod['module_tags'] ) {
  961. $mod['module_tags'] = explode( ',', $mod['module_tags'] );
  962. $mod['module_tags'] = array_map( 'trim', $mod['module_tags'] );
  963. $mod['module_tags'] = array_map( array( __CLASS__, 'translate_module_tag' ), $mod['module_tags'] );
  964. } else {
  965. $mod['module_tags'] = array( self::translate_module_tag( 'Other' ) );
  966. }
  967. return $mod;
  968. }
  969. public static function translate_module_tag( $untranslated_tag ) {
  970. return _x( $untranslated_tag, 'Module Tag', 'jetpack' );
  971. // Calls here are to populate translation files.
  972. _x( 'Photos and Videos', 'Module Tag', 'jetpack' );
  973. _x( 'Social', 'Module Tag', 'jetpack' );
  974. _x( 'WordPress.com Stats', 'Module Tag', 'jetpack' );
  975. _x( 'Writing', 'Module Tag', 'jetpack' );
  976. _x( 'Appearance', 'Module Tag', 'jetpack' );
  977. _x( 'Developers', 'Module Tag', 'jetpack' );
  978. _x( 'Mobile', 'Module Tag', 'jetpack' );
  979. _x( 'Other', 'Module Tag', 'jetpack' );
  980. }
  981. /**
  982. * Get a list of activated modules as an array of module slugs.
  983. */
  984. public static function get_active_modules() {
  985. $active = Jetpack_Options::get_option( 'active_modules' );
  986. if ( ! is_array( $active ) )
  987. $active = array();
  988. if ( is_admin() ) {
  989. $active[] = 'vaultpress';
  990. } else {
  991. $active = array_diff( $active, array( 'vaultpress' ) );
  992. }
  993. return array_unique( $active );
  994. }
  995. /**
  996. * Check whether or not a Jetpack module is active.
  997. *
  998. * @param string $module The slug of a Jetpack module.
  999. * @return bool
  1000. *
  1001. * @static
  1002. */
  1003. public static function is_module_active( $module ) {
  1004. return in_array( $module, self::get_active_modules() );
  1005. }
  1006. public static function is_module( $module ) {
  1007. return ! empty( $module ) && ! validate_file( $module, Jetpack::get_available_modules() );
  1008. }
  1009. /**
  1010. * Catches PHP errors. Must be used in conjunction with output buffering.
  1011. *
  1012. * @param bool $catch True to start catching, False to stop.
  1013. *
  1014. * @static
  1015. */
  1016. public static function catch_errors( $catch ) {
  1017. static $display_errors, $error_reporting;
  1018. if ( $catch ) {
  1019. $display_errors = @ini_set( 'display_errors', 1 );
  1020. $error_reporting = @error_reporting( E_ALL );
  1021. add_action( 'shutdown', array( 'Jetpack', 'catch_errors_on_shutdown' ), 0 );
  1022. } else {
  1023. @ini_set( 'display_errors', $display_errors );
  1024. @error_reporting( $error_reporting );
  1025. remove_action( 'shutdown', array( 'Jetpack', 'catch_errors_on_shutdown' ), 1 );
  1026. }
  1027. }
  1028. /**
  1029. * Saves any generated PHP errors in ::state( 'php_errors', {errors} )
  1030. */
  1031. public static function catch_errors_on_shutdown() {
  1032. Jetpack::state( 'php_errors', ob_get_clean() );
  1033. }
  1034. public static function activate_default_modules( $min_version = false, $max_version = false, $other_modules = array() ) {
  1035. $jetpack = Jetpack::init();
  1036. $modules = Jetpack::get_default_modules( $min_version, $max_version );
  1037. $modules = array_merge( $other_modules, $modules );
  1038. // Look for standalone plugins and disable if active.
  1039. $to_deactivate = array();
  1040. foreach ( $modules as $module ) {
  1041. if ( isset( $jetpack->plugins_to_deactivate[$module] ) ) {
  1042. $to_deactivate[$module] = $jetpack->plugins_to_deactivate[$module];
  1043. }
  1044. }
  1045. $deactivated = array();
  1046. foreach ( $to_deactivate as $module => $deactivate_me ) {
  1047. list( $probable_file, $probable_title ) = $deactivate_me;
  1048. if ( Jetpack_Client_Server::deactivate_plugin( $probable_file, $probable_title ) ) {
  1049. $deactivated[] = $module;
  1050. }
  1051. }
  1052. if ( $deactivated ) {
  1053. Jetpack::state( 'deactivated_plugins', join( ',', $deactivated ) );
  1054. $url = add_query_arg(
  1055. array(
  1056. 'action' => 'activate_default_modules',
  1057. '_wpnonce' => wp_create_nonce( 'activate_default_modules' ),
  1058. ),
  1059. add_query_arg( compact( 'min_version', 'max_version', 'other_modules' ), Jetpack::admin_url( 'page=jetpack' ) )
  1060. );
  1061. wp_safe_redirect( $url );
  1062. exit;
  1063. }
  1064. do_action( 'jetpack_before_activate_default_modules', $min_version, $max_version, $other_modules );
  1065. // Check each module for fatal errors, a la wp-admin/plugins.php::activate before activating
  1066. Jetpack::restate();
  1067. Jetpack::catch_errors( true );
  1068. foreach ( $modules as $module ) {
  1069. if ( did_action( "jetpack_module_loaded_$module" ) ) {
  1070. $active[] = $module;
  1071. Jetpack_Options::update_option( 'active_modules', array_unique( $active ) );
  1072. continue;
  1073. }
  1074. $active = Jetpack::get_active_modules();
  1075. if ( in_array( $module, $active ) ) {
  1076. $module_info = Jetpack::get_module( $module );
  1077. if ( ! $module_info['deactivate'] ) {
  1078. $state = in_array( $module, $other_modules ) ? 'reactivated_modules' : 'activated_modules';
  1079. if ( $active_state = Jetpack::state( $state ) ) {
  1080. $active_state = explode( ',', $active_state );
  1081. } else {
  1082. $active_state = array();
  1083. }
  1084. $active_state[] = $module;
  1085. Jetpack::state( $state, implode( ',', $active_state ) );
  1086. }
  1087. continue;
  1088. }
  1089. $file = Jetpack::get_module_path( $module );
  1090. if ( ! file_exists( $file ) ) {
  1091. continue;
  1092. }
  1093. // we'll override this later if the plugin can be included without fatal error
  1094. wp_safe_redirect( Jetpack::admin_url( 'page=jetpack' ) );
  1095. Jetpack::state( 'error', 'module_activation_failed' );
  1096. Jetpack::state( 'module', $module );
  1097. ob_start();
  1098. require $file;
  1099. do_action( 'jetpack_activate_module', $module );
  1100. $active[] = $module;
  1101. $state = in_array( $module, $other_modules ) ? 'reactivated_modules' : 'activated_modules';
  1102. if ( $active_state = Jetpack::state( $state ) ) {
  1103. $active_state = explode( ',', $active_state );
  1104. } else {
  1105. $active_state = array();
  1106. }
  1107. $active_state[] = $module;
  1108. Jetpack::state( $state, implode( ',', $active_state ) );
  1109. Jetpack_Options::update_option( 'active_modules', array_unique( $active ) );
  1110. ob_end_clean();
  1111. }
  1112. Jetpack::state( 'error', false );
  1113. Jetpack::state( 'module', false );
  1114. Jetpack::catch_errors( false );
  1115. do_action( 'jetpack_activate_default_modules', $min_version, $max_version, $other_modules );
  1116. }
  1117. public static function activate_module( $module, $exit = true ) {
  1118. do_action( 'jetpack_pre_activate_module', $module, $exit );
  1119. $jetpack = Jetpack::init();
  1120. if ( ! strlen( $module ) )
  1121. return false;
  1122. if ( ! Jetpack::is_module( $module ) )
  1123. return false;
  1124. // If it's already active, then don't do it again
  1125. $active = Jetpack::get_active_modules();
  1126. foreach ( $active as $act ) {
  1127. if ( $act == $module )
  1128. return true;
  1129. }
  1130. $module_data = Jetpack::get_module( $module );
  1131. if ( ! Jetpack::is_active() ) {
  1132. if ( ! Jetpack::is_development_mode() )
  1133. return false;
  1134. // If we're not connected but in development mode, make sure the module doesn't require a connection
  1135. if ( Jetpack::is_development_mode() && $module_data['requires_connection'] )
  1136. return false;
  1137. }
  1138. // Check and see if the old plugin is active
  1139. if ( isset( $jetpack->plugins_to_deactivate[$module] ) ) {
  1140. // Deactivate the old plugin
  1141. if ( Jetpack_Client_Server::deactivate_plugin( $jetpack->plugins_to_deactivate[$module][0], $jetpack->plugins_to_deactivate[$module][1] ) ) {
  1142. // If we deactivated the old plugin, remembere that with ::state() and redirect back to this page to activate the module
  1143. // We can't activate the module on this page load since the newly deactivated old plugin is still loaded on this page load.
  1144. Jetpack::state( 'deactivated_plugins', $module );
  1145. wp_safe_redirect( add_query_arg( 'jetpack_restate', 1 ) );
  1146. exit;
  1147. }
  1148. }
  1149. // Check the file for fatal errors, a la wp-admin/plugins.php::activate
  1150. Jetpack::state( 'module', $module );
  1151. Jetpack::state( 'error', 'module_activation_failed' ); // we'll override this later if the plugin can be included without fatal error
  1152. wp_safe_redirect( Jetpack::admin_url( 'page=jetpack' ) );
  1153. Jetpack::catch_errors( true );
  1154. ob_start();
  1155. require Jetpack::get_module_path( $module );
  1156. do_action( 'jetpack_activate_module', $module );
  1157. $active[] = $module;
  1158. Jetpack_Options::update_option( 'active_modules', array_unique( $active ) );
  1159. Jetpack::state( 'error', false ); // the override
  1160. Jetpack::state( 'message', 'module_activated' );
  1161. Jetpack::state( 'module', $module );
  1162. ob_end_clean();
  1163. Jetpack::catch_errors( false );
  1164. if ( $exit ) {
  1165. exit;
  1166. }
  1167. }
  1168. function activate_module_actions( $module ) {
  1169. do_action( "jetpack_activate_module_$module" );
  1170. $this->sync->sync_all_module_options( $module );
  1171. }
  1172. public static function deactivate_module( $module ) {
  1173. do_action( 'jetpack_pre_deactivate_module', $module );
  1174. $active = Jetpack::get_active_modules();
  1175. $new = array_filter( array_diff( $active, (array) $module ) );
  1176. do_action( "jetpack_deactivate_module_$module" );
  1177. return Jetpack_Options::update_option( 'active_modules', array_unique( $new ) );
  1178. }
  1179. public static function enable_module_configurable( $module ) {
  1180. $module = Jetpack::get_module_slug( $module );
  1181. add_filter( 'jetpack_module_configurable_' . $module, '__return_true' );
  1182. }
  1183. public static function module_configuration_url( $module ) {
  1184. $module = Jetpack::get_module_slug( $module );
  1185. return Jetpack::admin_url( array( 'page' => 'jetpack', 'configure' => $module ) );
  1186. }
  1187. public static function module_configuration_load( $module, $method ) {
  1188. $module = Jetpack::get_module_slug( $module );
  1189. add_action( 'jetpack_module_configuration_load_' . $module, $method );
  1190. }
  1191. public static function module_configuration_head( $module, $method ) {
  1192. $module = Jetpack::get_module_slug( $module );
  1193. add_action( 'jetpack_module_configuration_head_' . $module, $method );
  1194. }
  1195. public static function module_configuration_screen( $module, $method ) {
  1196. $module = Jetpack::get_module_slug( $module );
  1197. add_action( 'jetpack_module_configuration_screen_' . $module, $method );
  1198. }
  1199. /* Installation */
  1200. public static function bail_on_activation( $message, $deactivate = true ) {
  1201. ?>
  1202. <!doctype html>
  1203. <html>
  1204. <head>
  1205. <meta charset="<?php bloginfo( 'charset' ); ?>">
  1206. <style>
  1207. * {
  1208. text-align: center;
  1209. margin: 0;
  1210. padding: 0;
  1211. font-family: "Lucida Grande",Verdana,Arial,"Bitstream Vera Sans",sans-serif;
  1212. }
  1213. p {
  1214. margin-top: 1em;
  1215. font-size: 18px;
  1216. }
  1217. </style>
  1218. <body>
  1219. <p><?php echo esc_html( $message ); ?></p>
  1220. </body

Large files files are truncated, but you can click here to view the full file