PageRenderTime 80ms CodeModel.GetById 48ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://gitlab.com/hunt9310/ras
PHP | 813 lines | 409 code | 112 blank | 292 comment | 71 complexity | 3969b9d4f5a313897f218499faab8838 MD5 | raw file
  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 = $this->wp_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', 'Site ID must be provided to register a sub-site' );
  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. break;
  298. case 'subsitedisconnect':
  299. Jetpack::log( 'subsitedisconnect' );
  300. if ( ! isset( $_GET['site_id'] ) || empty( $_GET['site_id'] ) ) {
  301. Jetpack::state( 'missing_site_id', 'Site ID must be provided to disconnect a sub-site' );
  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. // Remote query timeout limit
  354. $timeout = $jp->get_remote_query_timeout_limit();
  355. // The blog id on WordPress.com of the primary network site
  356. $network_wpcom_blog_id = Jetpack_Options::get_option( 'id' );
  357. /*
  358. * Here we need to switch to the subsite
  359. * For the registration process we really only hijack how it
  360. * works for an individual site and pass in some extra data here
  361. */
  362. switch_to_blog( $site_id );
  363. // Save the secrets in the subsite so when the wpcom server does a pingback it
  364. // will be able to validate the connection
  365. $secrets = $jp->generate_secrets( 'register' );
  366. @list( $secret_1, $secret_2, $secret_eol ) = explode( ':', $secrets );
  367. if ( empty( $secret_1 ) || empty( $secret_2 ) || empty( $secret_eol ) || $secret_eol < time() ) {
  368. return new Jetpack_Error( 'missing_secrets' );
  369. }
  370. // Gra info for gmt offset
  371. $gmt_offset = get_option( 'gmt_offset' );
  372. if ( ! $gmt_offset ) {
  373. $gmt_offset = 0;
  374. }
  375. /*
  376. * Get the stats_option option from the db.
  377. * It looks like the server strips this out so maybe it is not necessary?
  378. * Does it match the Jetpack site with the old stats plugin id?
  379. *
  380. * @todo Find out if sending the stats_id is necessary
  381. */
  382. $stat_options = get_option( 'stats_options' );
  383. $stat_id = $stat_options = isset( $stats_options['blog_id'] ) ? $stats_options['blog_id'] : null;
  384. $user_id = get_current_user_id();
  385. /**
  386. * Both `state` and `user_id` need to be sent in the request, even though they are the same value.
  387. * Connecting via the network admin combines `register()` and `authorize()` methods into one step,
  388. * because we assume the main site is already authorized. `state` is used to verify the `register()`
  389. * request, while `user_id()` is used to create the token in the `authorize()` request.
  390. */
  391. $args = array(
  392. 'method' => 'POST',
  393. 'body' => array(
  394. 'network_url' => $this->get_url( 'network_admin_page' ),
  395. 'network_wpcom_blog_id' => $network_wpcom_blog_id,
  396. 'siteurl' => site_url(),
  397. 'home' => home_url(),
  398. 'gmt_offset' => $gmt_offset,
  399. 'timezone_string' => (string) get_option( 'timezone_string' ),
  400. 'site_name' => (string) get_option( 'blogname' ),
  401. 'secret_1' => $secret_1,
  402. 'secret_2' => $secret_2,
  403. 'site_lang' => get_locale(),
  404. 'timeout' => $timeout,
  405. 'stats_id' => $stat_id, // Is this still required?
  406. 'user_id' => $user_id,
  407. 'state' => $user_id
  408. ),
  409. 'headers' => array(
  410. 'Accept' => 'application/json',
  411. ),
  412. 'timeout' => $timeout,
  413. );
  414. // Attempt to retrieve shadow blog details
  415. $response = Jetpack_Client::_wp_remote_request(
  416. Jetpack::fix_url_for_bad_hosts( Jetpack::api_url( 'subsiteregister' ) ), $args, true
  417. );
  418. /*
  419. * $response should either be invalid or contain:
  420. * - jetpack_id => id
  421. * - jetpack_secret => blog_token
  422. * - jetpack_public
  423. *
  424. * Store the wpcom site details
  425. */
  426. $valid_response = $jp->validate_remote_register_response( $response );
  427. if ( is_wp_error( $valid_response ) || ! $valid_response ) {
  428. restore_current_blog();
  429. return $valid_response;
  430. }
  431. // Grab the response values to work with
  432. $code = wp_remote_retrieve_response_code( $response );
  433. $entity = wp_remote_retrieve_body( $response );
  434. if ( $entity ) {
  435. $json = json_decode( $entity );
  436. } else {
  437. $json = false;
  438. }
  439. if ( empty( $json->jetpack_secret ) || ! is_string( $json->jetpack_secret ) ) {
  440. restore_current_blog();
  441. return new Jetpack_Error( 'jetpack_secret', '', $code );
  442. }
  443. if ( isset( $json->jetpack_public ) ) {
  444. $jetpack_public = (int) $json->jetpack_public;
  445. } else {
  446. $jetpack_public = false;
  447. }
  448. Jetpack_Options::update_options( array(
  449. 'id' => (int) $json->jetpack_id,
  450. 'blog_token' => (string) $json->jetpack_secret,
  451. 'public' => $jetpack_public,
  452. ) );
  453. /*
  454. * Update the subsiteregister method on wpcom so that it also sends back the
  455. * token in this same request
  456. */
  457. $is_master_user = ! Jetpack::is_active();
  458. Jetpack::update_user_token(
  459. get_current_user_id(),
  460. sprintf( '%s.%d', $json->token->secret, get_current_user_id() ),
  461. $is_master_user
  462. );
  463. Jetpack::activate_default_modules();
  464. restore_current_blog();
  465. }
  466. /**
  467. * Handles the displaying of all sites on the network that are
  468. * dis/connected to Jetpack
  469. *
  470. * @since 2.9
  471. * @see Jetpack_Network::jetpack_sites_list()
  472. */
  473. function network_admin_page() {
  474. global $current_site;
  475. $this->network_admin_page_header();
  476. $jp = Jetpack::init();
  477. // We should be, but ensure we are on the main blog
  478. switch_to_blog( $current_site->blog_id );
  479. $main_active = $jp->is_active();
  480. restore_current_blog();
  481. // If we are in dev mode, just show the notice and bail
  482. if ( Jetpack::is_development_mode() ) {
  483. Jetpack::show_development_mode_notice();
  484. return;
  485. }
  486. /*
  487. * Ensure the main blog is connected as all other subsite blog
  488. * connections will feed off this one
  489. */
  490. if ( ! $main_active ) {
  491. $url = $this->get_url( array(
  492. 'name' => 'subsiteregister',
  493. 'site_id' => 1,
  494. ) );
  495. $data = array( 'url' => $jp->build_connect_url() );
  496. Jetpack::init()->load_view( 'admin/must-connect-main-blog.php', $data );
  497. return;
  498. }
  499. require_once( 'class.jetpack-network-sites-list-table.php' );
  500. $myListTable = new Jetpack_Network_Sites_List_Table();
  501. echo '<div class="wrap"><h2>' . __( 'Sites', 'jetpack' ) . '</h2>';
  502. echo '<form method="post">';
  503. $myListTable->prepare_items();
  504. $myListTable->display();
  505. echo '</form></div>';
  506. $this->network_admin_page_footer();
  507. }
  508. /**
  509. * Stylized JP header formatting
  510. *
  511. * @since 2.9
  512. */
  513. function network_admin_page_header() {
  514. global $current_user;
  515. $is_connected = Jetpack::is_active();
  516. $data = array(
  517. 'is_connected' => $is_connected
  518. );
  519. Jetpack::init()->load_view( 'admin/network-admin-header.php', $data );
  520. }
  521. /**
  522. * Stylized JP footer formatting
  523. *
  524. * @since 2.9
  525. */
  526. function network_admin_page_footer() {
  527. Jetpack::init()->load_view( 'admin/network-admin-footer.php' );
  528. }
  529. /**
  530. * Fires when the Jetpack > Settings page is saved.
  531. *
  532. * @since 2.9
  533. */
  534. public function save_network_settings_page() {
  535. if ( ! wp_verify_nonce( $_POST['_wpnonce'], 'jetpack-network-settings' ) ) {
  536. // no nonce, push back to settings page
  537. wp_safe_redirect(
  538. add_query_arg(
  539. array( 'page' => 'jetpack-settings' ),
  540. network_admin_url( 'admin.php' )
  541. )
  542. );
  543. exit();
  544. }
  545. // try to save the Protect whitelist before anything else, since that action can result in errors
  546. $whitelist = str_replace( ' ', '', $_POST['global-whitelist'] );
  547. $whitelist = explode( PHP_EOL, $whitelist );
  548. $result = jetpack_protect_save_whitelist( $whitelist, $global = true );
  549. if ( is_wp_error( $result ) ) {
  550. wp_safe_redirect(
  551. add_query_arg(
  552. array( 'page' => 'jetpack-settings', 'error' => 'jetpack_protect_whitelist' ),
  553. network_admin_url( 'admin.php' )
  554. )
  555. );
  556. exit();
  557. }
  558. /*
  559. * Fields
  560. *
  561. * auto-connect - Checkbox for global Jetpack connection
  562. * sub-site-connection-override - Allow sub-site admins to (dis)reconnect with their own Jetpack account
  563. */
  564. $auto_connect = 0;
  565. if ( isset( $_POST['auto-connect'] ) ) {
  566. $auto_connect = 1;
  567. }
  568. $sub_site_connection_override = 0;
  569. if ( isset( $_POST['sub-site-connection-override'] ) ) {
  570. $sub_site_connection_override = 1;
  571. }
  572. /* 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.
  573. $manage_auto_activated_modules = 0;
  574. if ( isset( $_POST['manage_auto_activated_modules'] ) ) {
  575. $manage_auto_activated_modules = 1;
  576. }
  577. $modules = array();
  578. if ( isset( $_POST['modules'] ) ) {
  579. $modules = $_POST['modules'];
  580. }
  581. */
  582. $data = array(
  583. 'auto-connect' => $auto_connect,
  584. 'sub-site-connection-override' => $sub_site_connection_override,
  585. //'manage_auto_activated_modules' => $manage_auto_activated_modules,
  586. //'modules' => $modules,
  587. );
  588. update_site_option( $this->settings_name, $data );
  589. wp_safe_redirect(
  590. add_query_arg(
  591. array( 'page' => 'jetpack-settings', 'updated' => 'true' ),
  592. network_admin_url( 'admin.php' )
  593. )
  594. );
  595. exit();
  596. }
  597. public function render_network_admin_settings_page() {
  598. $this->network_admin_page_header();
  599. $options = wp_parse_args( get_site_option( $this->settings_name ), $this->setting_defaults );
  600. $modules = array();
  601. $module_slugs = Jetpack::get_available_modules();
  602. foreach ( $module_slugs as $slug ) {
  603. $module = Jetpack::get_module( $slug );
  604. $module['module'] = $slug;
  605. $modules[] = $module;
  606. }
  607. usort( $modules, array( 'Jetpack', 'sort_modules' ) );
  608. if ( ! isset( $options['modules'] ) ) {
  609. $options['modules'] = $modules;
  610. }
  611. $data = array(
  612. 'modules' => $modules,
  613. 'options' => $options,
  614. 'jetpack_protect_whitelist' => jetpack_protect_format_whitelist(),
  615. );
  616. Jetpack::init()->load_view( 'admin/network-settings.php', $data );
  617. $this->network_admin_page_footer();
  618. }
  619. /**
  620. * Updates a site wide option
  621. *
  622. * @since 2.9
  623. *
  624. * @param string $key
  625. * @param mixed $value
  626. *
  627. * @return boolean
  628. **/
  629. public function update_option( $key, $value ) {
  630. $options = get_site_option( $this->settings_name, $this->setting_defaults );
  631. $options[ $key ] = $value;
  632. return update_site_option( $this->settings_name, $options );
  633. }
  634. /**
  635. * Retrieves a site wide option
  636. *
  637. * @since 2.9
  638. *
  639. * @param string $name - Name of the option in the database
  640. **/
  641. public function get_option( $name ) {
  642. $options = get_site_option( $this->settings_name, $this->setting_defaults );
  643. $options = wp_parse_args( $options, $this->setting_defaults );
  644. if ( ! isset( $options[ $name ] ) ) {
  645. $options[ $name ] = null;
  646. }
  647. return $options[ $name ];
  648. }
  649. /**
  650. * Return an array of sites on the specified network. If no network is specified,
  651. * return all sites, regardless of network.
  652. *
  653. * @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
  654. * @since 2.9
  655. * @deprecated 2.4.5
  656. *
  657. * @param array|string $args Optional. Specify the status of the sites to return.
  658. *
  659. * @return array An array of site data
  660. */
  661. public function wp_get_sites( $args = array() ) {
  662. global $wpdb;
  663. if ( wp_is_large_network() ) {
  664. return;
  665. }
  666. $defaults = array( 'network_id' => $wpdb->siteid );
  667. $args = wp_parse_args( $args, $defaults );
  668. $query = "SELECT * FROM $wpdb->blogs WHERE 1=1 ";
  669. if ( isset( $args['network_id'] ) && ( is_array( $args['network_id'] ) || is_numeric( $args['network_id'] ) ) ) {
  670. $network_ids = array_map( 'intval', (array) $args['network_id'] );
  671. $network_ids = implode( ',', $network_ids );
  672. $query .= "AND site_id IN ($network_ids) ";
  673. }
  674. if ( isset( $args['public'] ) ) {
  675. $query .= $wpdb->prepare( "AND public = %d ", $args['public'] );
  676. }
  677. if ( isset( $args['archived'] ) ) {
  678. $query .= $wpdb->prepare( "AND archived = %d ", $args['archived'] );
  679. }
  680. if ( isset( $args['mature'] ) ) {
  681. $query .= $wpdb->prepare( "AND mature = %d ", $args['mature'] );
  682. }
  683. if ( isset( $args['spam'] ) ) {
  684. $query .= $wpdb->prepare( "AND spam = %d ", $args['spam'] );
  685. }
  686. if ( isset( $args['deleted'] ) ) {
  687. $query .= $wpdb->prepare( "AND deleted = %d ", $args['deleted'] );
  688. }
  689. if ( isset( $args['exclude_blogs'] ) ) {
  690. $query .= "AND blog_id NOT IN (" . implode( ',', $args['exclude_blogs'] ) . ")";
  691. }
  692. $key = 'wp_get_sites:' . md5( $query );
  693. if ( ! $site_results = wp_cache_get( $key, 'site-id-cache' ) ) {
  694. $site_results = (array) $wpdb->get_results( $query );
  695. wp_cache_set( $key, $site_results, 'site-id-cache' );
  696. }
  697. return $site_results;
  698. }
  699. }
  700. // end class