class.jetpack-network.php 21 KB

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