PageRenderTime 63ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/plugins/jetpack/class.jetpack.php

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

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