Jetpack_Network

Used to manage Jetpack installation on Multisite Network installs.

Defined (1)

The class is defined in the following location(s).

/class.jetpack-network.php  
  1. class Jetpack_Network { 
  2.  
  3. /** 
  4. * Holds a static copy of Jetpack_Network for the singleton 
  5. * @since 2.9 
  6. * @var Jetpack_Network 
  7. */ 
  8. private static $instance = null; 
  9.  
  10. /** 
  11. * Name of the network wide settings 
  12. * @since 2.9 
  13. * @var string 
  14. */ 
  15. private $settings_name = 'jetpack-network-settings'; 
  16.  
  17. /** 
  18. * Defaults for settings found on the Jetpack > Settings page 
  19. * @since 2.9 
  20. * @var array 
  21. */ 
  22. private $setting_defaults = array( 
  23. 'auto-connect' => 0,  
  24. 'sub-site-connection-override' => 1,  
  25. //'manage_auto_activated_modules' => 0,  
  26. ); 
  27.  
  28. /** 
  29. * Constructor 
  30. * @since 2.9 
  31. */ 
  32. private function __construct() { 
  33. require_once( ABSPATH . '/wp-admin/includes/plugin.php' ); // For the is_plugin... check 
  34. require_once( JETPACK__PLUGIN_DIR . 'modules/protect/shared-functions.php' ); // For managing the global whitelist 
  35. /** 
  36. * Sanity check to ensure the install is Multisite and we 
  37. * are in Network Admin 
  38. */ 
  39. if ( is_multisite() && is_network_admin() ) { 
  40. add_action( 'network_admin_menu', array( $this, 'add_network_admin_menu' ) ); 
  41. add_action( 'network_admin_edit_jetpack-network-settings', array( $this, 'save_network_settings_page' ), 10, 0 ); 
  42. add_filter( 'admin_body_class', array( $this, 'body_class' ) ); 
  43.  
  44. if ( isset( $_GET['page'] ) && 'jetpack' == $_GET['page'] ) { 
  45. add_action( 'admin_init', array( $this, 'jetpack_sites_list' ) ); 
  46.  
  47. /** 
  48. * Things that should only run on multisite 
  49. */ 
  50. if ( is_multisite() && is_plugin_active_for_network( 'jetpack/jetpack.php' ) ) { 
  51. add_action( 'wp_before_admin_bar_render', array( $this, 'add_to_menubar' ) ); 
  52.  
  53. /** 
  54. * If admin wants to automagically register new sites set the hook here 
  55. * This is a hacky way because xmlrpc is not available on wpmu_new_blog 
  56. */ 
  57. if ( $this->get_option( 'auto-connect' ) == 1 ) { 
  58. add_action( 'wpmu_new_blog', array( $this, 'do_automatically_add_new_site' ) ); 
  59.  
  60. // Remove the toggles for 2.9, re-evaluate how they're done and added for a 3.0 release. They don't feel quite right yet. 
  61. // add_filter( 'jetpack_get_default_modules', array( $this, 'set_auto_activated_modules' ) ); 
  62.  
  63. /** 
  64. * Sets which modules get activated by default on subsite connection. 
  65. * Modules can be set in Network Admin > Jetpack > Settings 
  66. * @since 2.9 
  67. * @param array $modules 
  68. * @return array 
  69. **/ 
  70. public function set_auto_activated_modules( $modules ) { 
  71. return $modules; 
  72.  
  73. /** Remove the toggles for 2.9, re-evaluate how they're done and added for a 3.0 release. They don't feel quite right yet. 
  74. if( 1 == $this->get_option( 'manage_auto_activated_modules' ) ) { 
  75. return (array) $this->get_option( 'modules' ); 
  76. } else { 
  77. return $modules; 
  78. */ 
  79.  
  80. /** 
  81. * Registers new sites upon creation 
  82. * @since 2.9 
  83. * @uses wpmu_new_blog 
  84. * @param int $blog_id 
  85. **/ 
  86. public function do_automatically_add_new_site( $blog_id ) { 
  87. $this->do_subsiteregister( $blog_id ); 
  88.  
  89. /** 
  90. * Adds .network-admin class to the body tag 
  91. * Helps distinguish network admin JP styles from regular site JP styles 
  92. * @since 2.9 
  93. */ 
  94. public function body_class( $classes ) { 
  95. return trim( $classes ) . ' network-admin '; 
  96.  
  97. /** 
  98. * Provides access to an instance of Jetpack_Network 
  99. * This is how the Jetpack_Network object should *always* be accessed 
  100. * @since 2.9 
  101. * @return Jetpack_Network 
  102. */ 
  103. public static function init() { 
  104. if ( ! self::$instance || ! is_a( self::$instance, 'Jetpack_Network' ) ) { 
  105. self::$instance = new Jetpack_Network; 
  106.  
  107. return self::$instance; 
  108.  
  109. /** 
  110. * Registers the Multisite admin bar menu item shortcut. 
  111. * This shortcut helps users quickly and easily navigate to the Jetpack Network Admin 
  112. * menu from anywhere in their network. 
  113. * @since 2.9 
  114. */ 
  115. public function register_menubar() { 
  116. add_action( 'wp_before_admin_bar_render', array( $this, 'add_to_menubar' ) ); 
  117.  
  118. /** 
  119. * Runs when Jetpack is deactivated from the network admin plugins menu. 
  120. * Each individual site will need to have Jetpack::disconnect called on it. 
  121. * Site that had Jetpack individually enabled will not be disconnected as 
  122. * on Multisite individually activated plugins are still activated when 
  123. * a plugin is deactivated network wide. 
  124. * @since 2.9 
  125. **/ 
  126. public function deactivate() { 
  127. // Only fire if in network admin 
  128. if ( ! is_network_admin() ) { 
  129. return; 
  130.  
  131. $sites = $this->wp_get_sites(); 
  132.  
  133. foreach ( $sites as $s ) { 
  134. switch_to_blog( $s->blog_id ); 
  135. $active_plugins = get_option( 'active_plugins' ); 
  136.  
  137. /** 
  138. * If this plugin was activated in the subsite individually 
  139. * we do not want to call disconnect. Plugins activated 
  140. * individually (before network activation) stay activated 
  141. * when the network deactivation occurs 
  142. */ 
  143. if ( ! in_array( 'jetpack/jetpack.php', $active_plugins ) ) { 
  144. Jetpack::disconnect(); 
  145. restore_current_blog(); 
  146.  
  147. /** 
  148. * Adds a link to the Jetpack Network Admin page in the network admin menu bar. 
  149. * @since 2.9 
  150. **/ 
  151. public function add_to_menubar() { 
  152. global $wp_admin_bar; 
  153. // Don't show for logged out users or single site mode. 
  154. if ( ! is_user_logged_in() || ! is_multisite() ) { 
  155. return; 
  156.  
  157. $wp_admin_bar->add_node( array( 
  158. 'parent' => 'network-admin',  
  159. 'id' => 'network-admin-jetpack',  
  160. 'title' => __( 'Jetpack', 'jetpack' ),  
  161. 'href' => $this->get_url( 'network_admin_page' ),  
  162. ) ); 
  163.  
  164. /** 
  165. * Returns various URL strings. Factory like 
  166. * $args can be a string or an array. 
  167. * If $args is an array there must be an element called name for the switch statement 
  168. * Currently supports: 
  169. * - subsiteregister: Pass array( 'name' => 'subsiteregister', 'site_id' => SITE_ID ) 
  170. * - network_admin_page: Provides link to /wp-admin/network/JETPACK 
  171. * - subsitedisconnect: Pass array( 'name' => 'subsitedisconnect', 'site_id' => SITE_ID ) 
  172. * @since 2.9 
  173. * @param Mixed $args 
  174. * @return String 
  175. **/ 
  176. public function get_url( $args ) { 
  177. $url = null; // Default url value 
  178.  
  179. if ( is_string( $args ) ) { 
  180. $name = $args; 
  181. } else { 
  182. $name = $args['name']; 
  183.  
  184. switch ( $name ) { 
  185. case 'subsiteregister': 
  186. if ( ! isset( $args['site_id'] ) ) { 
  187. break; // If there is not a site id present we cannot go further 
  188. $url = network_admin_url( 
  189. 'admin.php?page=jetpack&action=subsiteregister&site_id=' 
  190. . $args['site_id'] 
  191. ); 
  192. break; 
  193.  
  194. case 'network_admin_page': 
  195. $url = network_admin_url( 'admin.php?page=jetpack' ); 
  196. break; 
  197.  
  198. case 'subsitedisconnect': 
  199. if ( ! isset( $args['site_id'] ) ) { 
  200. break; // If there is not a site id present we cannot go further 
  201. $url = network_admin_url( 
  202. 'admin.php?page=jetpack&action=subsitedisconnect&site_id=' 
  203. . $args['site_id'] 
  204. ); 
  205. break; 
  206.  
  207. return $url; 
  208.  
  209. /** 
  210. * Adds the Jetpack menu item to the Network Admin area 
  211. * @since 2.9 
  212. */ 
  213. public function add_network_admin_menu() { 
  214. add_menu_page( __( 'Jetpack', 'jetpack' ), __( 'Jetpack', 'jetpack' ), 'jetpack_network_admin_page', 'jetpack', array( $this, 'network_admin_page' ), 'div', 3 ); 
  215. add_submenu_page( 'jetpack', __( 'Jetpack Sites', 'jetpack' ), __( 'Sites', 'jetpack' ), 'jetpack_network_sites_page', 'jetpack', array( $this, 'network_admin_page' ) ); 
  216. add_submenu_page( 'jetpack', __( 'Settings', 'jetpack' ), __( 'Settings', 'jetpack' ), 'jetpack_network_settings_page', 'jetpack-settings', array( $this, 'render_network_admin_settings_page' ) ); 
  217.  
  218. /** 
  219. * As jetpack_register_genericons is by default fired off a hook,  
  220. * the hook may have already fired by this point. 
  221. * So, let's just trigger it manually. 
  222. */ 
  223. require_once( JETPACK__PLUGIN_DIR . '_inc/genericons.php' ); 
  224. jetpack_register_genericons(); 
  225.  
  226. if ( ! wp_style_is( 'jetpack-icons', 'registered' ) ) { 
  227. wp_register_style( 'jetpack-icons', plugins_url( 'css/jetpack-icons.min.css', JETPACK__PLUGIN_FILE ), false, JETPACK__VERSION ); 
  228.  
  229. add_action( 'admin_enqueue_scripts', array( $this, 'admin_menu_css' ) ); 
  230.  
  231. /** 
  232. * Adds JP menu icon 
  233. * @since 2.9 
  234. **/ 
  235. function admin_menu_css() { 
  236. wp_enqueue_style( 'jetpack-icons' ); 
  237.  
  238. /** 
  239. * Provides functionality for the Jetpack > Sites page. 
  240. * Does not do the display! 
  241. * @since 2.9 
  242. */ 
  243. public function jetpack_sites_list() { 
  244. Jetpack::init(); 
  245.  
  246. if ( isset( $_GET['action'] ) ) { 
  247. switch ( $_GET['action'] ) { 
  248. case 'subsiteregister': 
  249. /** 
  250. * @todo check_admin_referer( 'jetpack-subsite-register' ); 
  251. */ 
  252. Jetpack::log( 'subsiteregister' ); 
  253.  
  254. // If !$_GET['site_id'] stop registration and error 
  255. if ( ! isset( $_GET['site_id'] ) || empty( $_GET['site_id'] ) ) { 
  256. // Log error to state cookie for display later 
  257. /** 
  258. * @todo Make state messages show on Jetpack NA pages 
  259. **/ 
  260. Jetpack::state( 'missing_site_id', 'Site ID must be provided to register a sub-site' ); 
  261. break; 
  262.  
  263. // Send data to register endpoint and retrieve shadow blog details 
  264. $result = $this->do_subsiteregister(); 
  265. $url = $this->get_url( 'network_admin_page' ); 
  266.  
  267. if ( is_wp_error( $result ) ) { 
  268. $url = add_query_arg( 'action', 'connection_failed', $url ); 
  269. } else { 
  270. $url = add_query_arg( 'action', 'connected', $url ); 
  271.  
  272. wp_safe_redirect( $url ); 
  273. break; 
  274.  
  275. case 'subsitedisconnect': 
  276. Jetpack::log( 'subsitedisconnect' ); 
  277.  
  278. if ( ! isset( $_GET['site_id'] ) || empty( $_GET['site_id'] ) ) { 
  279. Jetpack::state( 'missing_site_id', 'Site ID must be provided to disconnect a sub-site' ); 
  280. break; 
  281.  
  282. $this->do_subsitedisconnect(); 
  283. break; 
  284.  
  285. case 'connected': 
  286. case 'connection_failed': 
  287. add_action( 'jetpack_notices', array( $this, 'show_jetpack_notice' ) ); 
  288. break; 
  289.  
  290. public function show_jetpack_notice() { 
  291. if ( isset( $_GET['action'] ) && 'connected' == $_GET['action'] ) { 
  292. $notice = __( 'Site successfully connected.', 'jetpack' ); 
  293. } else if ( isset( $_GET['action'] ) && 'connection_failed' == $_GET['action'] ) { 
  294. $notice = __( 'Site connection <strong>failed</strong>', 'jetpack' ); 
  295.  
  296. Jetpack::init()->load_view( 'admin/network-admin-alert.php', array( 'notice' => $notice ) ); 
  297.  
  298. /** 
  299. * Disconnect functionality for an individual site 
  300. * @since 2.9 
  301. * @see Jetpack_Network::jetpack_sites_list() 
  302. */ 
  303. public function do_subsitedisconnect( $site_id = null ) { 
  304. if ( ! current_user_can( 'jetpack_disconnect' ) ) { 
  305. return; 
  306. $site_id = ( is_null( $site_id ) ) ? $_GET['site_id'] : $site_id; 
  307. switch_to_blog( $site_id ); 
  308. Jetpack::disconnect(); 
  309. restore_current_blog(); 
  310.  
  311. /** 
  312. * Registers a subsite with the Jetpack servers 
  313. * @since 2.9 
  314. * @todo Break apart into easier to manage chunks that can be unit tested 
  315. * @see Jetpack_Network::jetpack_sites_list(); 
  316. */ 
  317. public function do_subsiteregister( $site_id = null ) { 
  318. if ( ! current_user_can( 'jetpack_disconnect' ) ) { 
  319. return; 
  320.  
  321. if ( Jetpack::is_development_mode() ) { 
  322. return; 
  323.  
  324. $jp = Jetpack::init(); 
  325.  
  326. // Figure out what site we are working on 
  327. $site_id = ( is_null( $site_id ) ) ? $_GET['site_id'] : $site_id; 
  328.  
  329. // Build secrets to sent to wpcom for verification 
  330. $secrets = $jp->generate_secrets(); 
  331.  
  332. // Remote query timeout limit 
  333. $timeout = $jp->get_remote_query_timeout_limit(); 
  334.  
  335. // The blog id on WordPress.com of the primary network site 
  336. $network_wpcom_blog_id = Jetpack_Options::get_option( 'id' ); 
  337.  
  338. /** 
  339. * Here we need to switch to the subsite 
  340. * For the registration process we really only hijack how it 
  341. * works for an individual site and pass in some extra data here 
  342. */ 
  343. switch_to_blog( $site_id ); 
  344.  
  345. // Save the secrets in the subsite so when the wpcom server does a pingback it 
  346. // will be able to validate the connection 
  347. Jetpack_Options::update_option( 'register',  
  348. $secrets[0] . ':' . $secrets[1] . ':' . $secrets[2] 
  349. ); 
  350.  
  351. // Gra info for gmt offset 
  352. $gmt_offset = get_option( 'gmt_offset' ); 
  353. if ( ! $gmt_offset ) { 
  354. $gmt_offset = 0; 
  355.  
  356. /** 
  357. * Get the stats_option option from the db. 
  358. * It looks like the server strips this out so maybe it is not necessary? 
  359. * Does it match the Jetpack site with the old stats plugin id? 
  360. * @todo Find out if sending the stats_id is necessary 
  361. */ 
  362. $stat_options = get_option( 'stats_options' ); 
  363. $stat_id = $stat_options = isset( $stats_options['blog_id'] ) ? $stats_options['blog_id'] : null; 
  364.  
  365. $args = array( 
  366. 'method' => 'POST',  
  367. 'body' => array( 
  368. 'network_url' => $this->get_url( 'network_admin_page' ),  
  369. 'network_wpcom_blog_id' => $network_wpcom_blog_id,  
  370. 'siteurl' => site_url(),  
  371. 'home' => home_url(),  
  372. 'gmt_offset' => $gmt_offset,  
  373. 'timezone_string' => (string) get_option( 'timezone_string' ),  
  374. 'site_name' => (string) get_option( 'blogname' ),  
  375. 'secret_1' => $secrets[0],  
  376. 'secret_2' => $secrets[1],  
  377. 'site_lang' => get_locale(),  
  378. 'timeout' => $timeout,  
  379. 'stats_id' => $stat_id, // Is this still required? 
  380. 'user_id' => get_current_user_id(),  
  381. ),  
  382. 'headers' => array( 
  383. 'Accept' => 'application/json',  
  384. ),  
  385. 'timeout' => $timeout,  
  386. ); 
  387.  
  388. // Attempt to retrieve shadow blog details 
  389. $response = Jetpack_Client::_wp_remote_request( 
  390. Jetpack::fix_url_for_bad_hosts( Jetpack::api_url( 'subsiteregister' ) ), $args, true 
  391. ); 
  392.  
  393. /** 
  394. * $response should either be invalid or contain: 
  395. * - jetpack_id => id 
  396. * - jetpack_secret => blog_token 
  397. * - jetpack_public 
  398. * Store the wpcom site details 
  399. */ 
  400. $valid_response = $jp->validate_remote_register_response( $response ); 
  401.  
  402. if ( is_wp_error( $valid_response ) || ! $valid_response ) { 
  403. restore_current_blog(); 
  404. return $valid_response; 
  405.  
  406. // Grab the response values to work with 
  407. $code = wp_remote_retrieve_response_code( $response ); 
  408. $entity = wp_remote_retrieve_body( $response ); 
  409. if ( $entity ) { 
  410. $json = json_decode( $entity ); 
  411. } else { 
  412. $json = false; 
  413.  
  414. if ( empty( $json->jetpack_secret ) || ! is_string( $json->jetpack_secret ) ) { 
  415. restore_current_blog(); 
  416. return new Jetpack_Error( 'jetpack_secret', '', $code ); 
  417.  
  418. if ( isset( $json->jetpack_public ) ) { 
  419. $jetpack_public = (int) $json->jetpack_public; 
  420. } else { 
  421. $jetpack_public = false; 
  422.  
  423. Jetpack_Options::update_options( array( 
  424. 'id' => (int) $json->jetpack_id,  
  425. 'blog_token' => (string) $json->jetpack_secret,  
  426. 'public' => $jetpack_public,  
  427. ) ); 
  428.  
  429. /** 
  430. * Update the subsiteregister method on wpcom so that it also sends back the 
  431. * token in this same request 
  432. */ 
  433. $is_master_user = ! Jetpack::is_active(); 
  434. Jetpack::update_user_token( 
  435. get_current_user_id(),  
  436. sprintf( '%s.%d', $json->token->secret, get_current_user_id() ),  
  437. $is_master_user 
  438. ); 
  439.  
  440. Jetpack::activate_default_modules(); 
  441.  
  442. restore_current_blog(); 
  443.  
  444. /** 
  445. * Handles the displaying of all sites on the network that are 
  446. * dis/connected to Jetpack 
  447. * @since 2.9 
  448. * @see Jetpack_Network::jetpack_sites_list() 
  449. */ 
  450. function network_admin_page() { 
  451. global $current_site; 
  452. $this->network_admin_page_header(); 
  453.  
  454. $jp = Jetpack::init(); 
  455.  
  456. // We should be, but ensure we are on the main blog 
  457. switch_to_blog( $current_site->blog_id ); 
  458. $main_active = $jp->is_active(); 
  459. restore_current_blog(); 
  460.  
  461. // If we are in dev mode, just show the notice and bail 
  462. if ( Jetpack::is_development_mode() ) { 
  463. Jetpack::show_development_mode_notice(); 
  464. return; 
  465.  
  466. /** 
  467. * Ensure the main blog is connected as all other subsite blog 
  468. * connections will feed off this one 
  469. */ 
  470. if ( ! $main_active ) { 
  471. $url = $this->get_url( array( 
  472. 'name' => 'subsiteregister',  
  473. 'site_id' => 1,  
  474. ) ); 
  475. $data = array( 'url' => $jp->build_connect_url() ); 
  476. Jetpack::init()->load_view( 'admin/must-connect-main-blog.php', $data ); 
  477.  
  478. return; 
  479.  
  480. require_once( 'class.jetpack-network-sites-list-table.php' ); 
  481. $myListTable = new Jetpack_Network_Sites_List_Table(); 
  482. echo '<div class="wrap"><h2>' . __( 'Sites', 'jetpack' ) . '</h2>'; 
  483. echo '<form method="post">'; 
  484. $myListTable->prepare_items(); 
  485. $myListTable->display(); 
  486. echo '</form></div>'; 
  487.  
  488. $this->network_admin_page_footer(); 
  489.  
  490. /** 
  491. * Stylized JP header formatting 
  492. * @since 2.9 
  493. */ 
  494. function network_admin_page_header() { 
  495. global $current_user; 
  496.  
  497. $is_connected = Jetpack::is_active(); 
  498.  
  499. $data = array( 
  500. 'is_connected' => $is_connected 
  501. ); 
  502. Jetpack::init()->load_view( 'admin/network-admin-header.php', $data ); 
  503.  
  504. /** 
  505. * Stylized JP footer formatting 
  506. * @since 2.9 
  507. */ 
  508. function network_admin_page_footer() { 
  509. Jetpack::init()->load_view( 'admin/network-admin-footer.php' ); 
  510.  
  511. /** 
  512. * Fires when the Jetpack > Settings page is saved. 
  513. * @since 2.9 
  514. */ 
  515. public function save_network_settings_page() { 
  516.  
  517. if ( ! wp_verify_nonce( $_POST['_wpnonce'], 'jetpack-network-settings' ) ) { 
  518. // no nonce, push back to settings page 
  519. wp_safe_redirect( 
  520. add_query_arg( 
  521. array( 'page' => 'jetpack-settings' ),  
  522. network_admin_url( 'admin.php' ) 
  523. ); 
  524. exit(); 
  525.  
  526. // try to save the Protect whitelist before anything else, since that action can result in errors 
  527. $whitelist = str_replace( ' ', '', $_POST['global-whitelist'] ); 
  528. $whitelist = explode( PHP_EOL, $whitelist ); 
  529. $result = jetpack_protect_save_whitelist( $whitelist, $global = true ); 
  530. if ( is_wp_error( $result ) ) { 
  531. wp_safe_redirect( 
  532. add_query_arg( 
  533. array( 'page' => 'jetpack-settings', 'error' => 'jetpack_protect_whitelist' ),  
  534. network_admin_url( 'admin.php' ) 
  535. ); 
  536. exit(); 
  537.  
  538. /** 
  539. * Fields 
  540. * auto-connect - Checkbox for global Jetpack connection 
  541. * sub-site-connection-override - Allow sub-site admins to (dis)reconnect with their own Jetpack account 
  542. */ 
  543. $auto_connect = 0; 
  544. if ( isset( $_POST['auto-connect'] ) ) { 
  545. $auto_connect = 1; 
  546.  
  547. $sub_site_connection_override = 0; 
  548. if ( isset( $_POST['sub-site-connection-override'] ) ) { 
  549. $sub_site_connection_override = 1; 
  550.  
  551. /** Remove the toggles for 2.9, re-evaluate how they're done and added for a 3.0 release. They don't feel quite right yet. 
  552. $manage_auto_activated_modules = 0; 
  553. if ( isset( $_POST['manage_auto_activated_modules'] ) ) { 
  554. $manage_auto_activated_modules = 1; 
  555.   
  556. $modules = array(); 
  557. if ( isset( $_POST['modules'] ) ) { 
  558. $modules = $_POST['modules']; 
  559. */ 
  560.  
  561. $data = array( 
  562. 'auto-connect' => $auto_connect,  
  563. 'sub-site-connection-override' => $sub_site_connection_override,  
  564. //'manage_auto_activated_modules' => $manage_auto_activated_modules,  
  565. //'modules' => $modules,  
  566. ); 
  567.  
  568. update_site_option( $this->settings_name, $data ); 
  569. wp_safe_redirect( 
  570. add_query_arg( 
  571. array( 'page' => 'jetpack-settings', 'updated' => 'true' ),  
  572. network_admin_url( 'admin.php' ) 
  573. ); 
  574. exit(); 
  575.  
  576. public function render_network_admin_settings_page() { 
  577. $this->network_admin_page_header(); 
  578. $options = wp_parse_args( get_site_option( $this->settings_name ), $this->setting_defaults ); 
  579.  
  580. $modules = array(); 
  581. $module_slugs = Jetpack::get_available_modules(); 
  582. foreach ( $module_slugs as $slug ) { 
  583. $module = Jetpack::get_module( $slug ); 
  584. $module['module'] = $slug; 
  585. $modules[] = $module; 
  586.  
  587. usort( $modules, array( 'Jetpack', 'sort_modules' ) ); 
  588.  
  589. if ( ! isset( $options['modules'] ) ) { 
  590. $options['modules'] = $modules; 
  591.  
  592. $data = array( 
  593. 'modules' => $modules,  
  594. 'options' => $options,  
  595. 'jetpack_protect_whitelist' => jetpack_protect_format_whitelist(),  
  596. ); 
  597.  
  598. Jetpack::init()->load_view( 'admin/network-settings.php', $data ); 
  599. $this->network_admin_page_footer(); 
  600.  
  601. /** 
  602. * Updates a site wide option 
  603. * @since 2.9 
  604. * @param string $key 
  605. * @param mixed $value 
  606. * @return boolean 
  607. **/ 
  608. public function update_option( $key, $value ) { 
  609. $options = get_site_option( $this->settings_name, $this->setting_defaults ); 
  610. $options[ $key ] = $value; 
  611.  
  612. return update_site_option( $this->settings_name, $options ); 
  613.  
  614. /** 
  615. * Retrieves a site wide option 
  616. * @since 2.9 
  617. * @param string $name - Name of the option in the database 
  618. **/ 
  619. public function get_option( $name ) { 
  620. $options = get_site_option( $this->settings_name, $this->setting_defaults ); 
  621. $options = wp_parse_args( $options, $this->setting_defaults ); 
  622.  
  623. if ( ! isset( $options[ $name ] ) ) { 
  624. $options[ $name ] = null; 
  625.  
  626. return $options[ $name ]; 
  627.  
  628. /** 
  629. * Return an array of sites on the specified network. If no network is specified,  
  630. * return all sites, regardless of network. 
  631. * @todo REMOVE THIS FUNCTION! This function is moving to core. Use that one in favor of this. WordPress::wp_get_sites(). http://codex.wordpress.org/Function_Reference/wp_get_sites NOTE, This returns an array instead of stdClass. Be sure to update class.network-sites-list-table.php 
  632. * @since 2.9 
  633. * @deprecated 2.4.5 
  634. * @param array|string $args Optional. Specify the status of the sites to return. 
  635. * @return array An array of site data 
  636. */ 
  637. public function wp_get_sites( $args = array() ) { 
  638. global $wpdb; 
  639.  
  640. if ( wp_is_large_network() ) { 
  641. return; 
  642.  
  643. $defaults = array( 'network_id' => $wpdb->siteid ); 
  644. $args = wp_parse_args( $args, $defaults ); 
  645. $query = "SELECT * FROM $wpdb->blogs WHERE 1=1 "; 
  646.  
  647. if ( isset( $args['network_id'] ) && ( is_array( $args['network_id'] ) || is_numeric( $args['network_id'] ) ) ) { 
  648. $network_ids = array_map( 'intval', (array) $args['network_id'] ); 
  649. $network_ids = implode( ', ', $network_ids ); 
  650. $query .= "AND site_id IN ($network_ids) "; 
  651.  
  652. if ( isset( $args['public'] ) ) { 
  653. $query .= $wpdb->prepare( "AND public = %s ", $args['public'] ); 
  654.  
  655. if ( isset( $args['archived'] ) ) { 
  656. $query .= $wpdb->prepare( "AND archived = %s ", $args['archived'] ); 
  657.  
  658. if ( isset( $args['mature'] ) ) { 
  659. $query .= $wpdb->prepare( "AND mature = %s ", $args['mature'] ); 
  660.  
  661. if ( isset( $args['spam'] ) ) { 
  662. $query .= $wpdb->prepare( "AND spam = %s ", $args['spam'] ); 
  663.  
  664. if ( isset( $args['deleted'] ) ) { 
  665. $query .= $wpdb->prepare( "AND deleted = %s ", $args['deleted'] ); 
  666.  
  667. if ( isset( $args['exclude_blogs'] ) ) { 
  668. $query .= "AND blog_id NOT IN (" . implode( ', ', $args['exclude_blogs'] ) . ")"; 
  669.  
  670. $key = 'wp_get_sites:' . md5( $query ); 
  671.  
  672. if ( ! $site_results = wp_cache_get( $key, 'site-id-cache' ) ) { 
  673. $site_results = (array) $wpdb->get_results( $query ); 
  674. wp_cache_set( $key, $site_results, 'site-id-cache' ); 
  675.  
  676. return $site_results;