PageRenderTime 64ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 1ms

/class.jetpack.php

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

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