PageRenderTime 97ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

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

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