/wp-includes/ms-blogs.php

  1. <?php 
  2.  
  3. /** 
  4. * Site/blog functions that work with the blogs table and related data. 
  5. * 
  6. * @package WordPress 
  7. * @subpackage Multisite 
  8. * @since MU 
  9. */ 
  10.  
  11. /** 
  12. * Update the last_updated field for the current site. 
  13. * 
  14. * @since MU 
  15. * 
  16. * @global wpdb $wpdb WordPress database abstraction object. 
  17. */ 
  18. function wpmu_update_blogs_date() { 
  19. global $wpdb; 
  20.  
  21. update_blog_details( $wpdb->blogid, array('last_updated' => current_time('mysql', true)) ); 
  22. /** 
  23. * Fires after the blog details are updated. 
  24. * 
  25. * @since MU 
  26. * 
  27. * @param int $blog_id Site ID. 
  28. */ 
  29. do_action( 'wpmu_blog_updated', $wpdb->blogid ); 
  30.  
  31. /** 
  32. * Get a full blog URL, given a blog id. 
  33. * 
  34. * @since MU 
  35. * 
  36. * @param int $blog_id Blog ID 
  37. * @return string Full URL of the blog if found. Empty string if not. 
  38. */ 
  39. function get_blogaddress_by_id( $blog_id ) { 
  40. $bloginfo = get_site( (int) $blog_id ); 
  41.  
  42. if ( empty( $bloginfo ) ) { 
  43. return ''; 
  44.  
  45. $scheme = parse_url( $bloginfo->home, PHP_URL_SCHEME ); 
  46. $scheme = empty( $scheme ) ? 'http' : $scheme; 
  47.  
  48. return esc_url( $scheme . '://' . $bloginfo->domain . $bloginfo->path ); 
  49.  
  50. /** 
  51. * Get a full blog URL, given a blog name. 
  52. * 
  53. * @since MU 
  54. * 
  55. * @param string $blogname The (subdomain or directory) name 
  56. * @return string 
  57. */ 
  58. function get_blogaddress_by_name( $blogname ) { 
  59. if ( is_subdomain_install() ) { 
  60. if ( $blogname == 'main' ) 
  61. $blogname = 'www'; 
  62. $url = rtrim( network_home_url(), '/' ); 
  63. if ( !empty( $blogname ) ) 
  64. $url = preg_replace( '|^([^\.]+://)|', "\${1}" . $blogname . '.', $url ); 
  65. } else { 
  66. $url = network_home_url( $blogname ); 
  67. return esc_url( $url . '/' ); 
  68.  
  69. /** 
  70. * Retrieves a sites ID given its (subdomain or directory) slug. 
  71. * 
  72. * @since MU 
  73. * @since 4.7.0 Converted to use get_sites(). 
  74. * 
  75. * @param string $slug A site's slug. 
  76. * @return int|null The site ID, or null if no site is found for the given slug. 
  77. */ 
  78. function get_id_from_blogname( $slug ) { 
  79. $current_network = get_network(); 
  80. $slug = trim( $slug, '/' ); 
  81.  
  82. if ( is_subdomain_install() ) { 
  83. $domain = $slug . '.' . preg_replace( '|^www\.|', '', $current_network->domain ); 
  84. $path = $current_network->path; 
  85. } else { 
  86. $domain = $current_network->domain; 
  87. $path = $current_network->path . $slug . '/'; 
  88.  
  89. $site_ids = get_sites( array( 
  90. 'number' => 1,  
  91. 'fields' => 'ids',  
  92. 'domain' => $domain,  
  93. 'path' => $path,  
  94. ) ); 
  95.  
  96. if ( empty( $site_ids ) ) { 
  97. return null; 
  98.  
  99. return array_shift( $site_ids ); 
  100.  
  101. /** 
  102. * Retrieve the details for a blog from the blogs table and blog options. 
  103. * 
  104. * @since MU 
  105. * 
  106. * @global wpdb $wpdb WordPress database abstraction object. 
  107. * 
  108. * @param int|string|array $fields Optional. A blog ID, a blog slug, or an array of fields to query against. 
  109. * If not specified the current blog ID is used. 
  110. * @param bool $get_all Whether to retrieve all details or only the details in the blogs table. 
  111. * Default is true. 
  112. * @return WP_Site|false Blog details on success. False on failure. 
  113. */ 
  114. function get_blog_details( $fields = null, $get_all = true ) { 
  115. global $wpdb; 
  116.  
  117. if ( is_array($fields ) ) { 
  118. if ( isset($fields['blog_id']) ) { 
  119. $blog_id = $fields['blog_id']; 
  120. } elseif ( isset($fields['domain']) && isset($fields['path']) ) { 
  121. $key = md5( $fields['domain'] . $fields['path'] ); 
  122. $blog = wp_cache_get($key, 'blog-lookup'); 
  123. if ( false !== $blog ) 
  124. return $blog; 
  125. if ( substr( $fields['domain'], 0, 4 ) == 'www.' ) { 
  126. $nowww = substr( $fields['domain'], 4 ); 
  127. $blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain IN (%s, %s) AND path = %s ORDER BY CHAR_LENGTH(domain) DESC", $nowww, $fields['domain'], $fields['path'] ) ); 
  128. } else { 
  129. $blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain = %s AND path = %s", $fields['domain'], $fields['path'] ) ); 
  130. if ( $blog ) { 
  131. wp_cache_set($blog->blog_id . 'short', $blog, 'blog-details'); 
  132. $blog_id = $blog->blog_id; 
  133. } else { 
  134. return false; 
  135. } elseif ( isset($fields['domain']) && is_subdomain_install() ) { 
  136. $key = md5( $fields['domain'] ); 
  137. $blog = wp_cache_get($key, 'blog-lookup'); 
  138. if ( false !== $blog ) 
  139. return $blog; 
  140. if ( substr( $fields['domain'], 0, 4 ) == 'www.' ) { 
  141. $nowww = substr( $fields['domain'], 4 ); 
  142. $blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain IN (%s, %s) ORDER BY CHAR_LENGTH(domain) DESC", $nowww, $fields['domain'] ) ); 
  143. } else { 
  144. $blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain = %s", $fields['domain'] ) ); 
  145. if ( $blog ) { 
  146. wp_cache_set($blog->blog_id . 'short', $blog, 'blog-details'); 
  147. $blog_id = $blog->blog_id; 
  148. } else { 
  149. return false; 
  150. } else { 
  151. return false; 
  152. } else { 
  153. if ( ! $fields ) 
  154. $blog_id = get_current_blog_id(); 
  155. elseif ( ! is_numeric( $fields ) ) 
  156. $blog_id = get_id_from_blogname( $fields ); 
  157. else 
  158. $blog_id = $fields; 
  159.  
  160. $blog_id = (int) $blog_id; 
  161.  
  162. $all = $get_all == true ? '' : 'short'; 
  163. $details = wp_cache_get( $blog_id . $all, 'blog-details' ); 
  164.  
  165. if ( $details ) { 
  166. if ( ! is_object( $details ) ) { 
  167. if ( $details == -1 ) { 
  168. return false; 
  169. } else { 
  170. // Clear old pre-serialized objects. Cache clients do better with that. 
  171. wp_cache_delete( $blog_id . $all, 'blog-details' ); 
  172. unset($details); 
  173. } else { 
  174. return $details; 
  175.  
  176. // Try the other cache. 
  177. if ( $get_all ) { 
  178. $details = wp_cache_get( $blog_id . 'short', 'blog-details' ); 
  179. } else { 
  180. $details = wp_cache_get( $blog_id, 'blog-details' ); 
  181. // If short was requested and full cache is set, we can return. 
  182. if ( $details ) { 
  183. if ( ! is_object( $details ) ) { 
  184. if ( $details == -1 ) { 
  185. return false; 
  186. } else { 
  187. // Clear old pre-serialized objects. Cache clients do better with that. 
  188. wp_cache_delete( $blog_id, 'blog-details' ); 
  189. unset($details); 
  190. } else { 
  191. return $details; 
  192.  
  193. if ( empty($details) ) { 
  194. $details = WP_Site::get_instance( $blog_id ); 
  195. if ( ! $details ) { 
  196. // Set the full cache. 
  197. wp_cache_set( $blog_id, -1, 'blog-details' ); 
  198. return false; 
  199.  
  200. if ( ! $details instanceof WP_Site ) { 
  201. $details = new WP_Site( $details ); 
  202.  
  203. if ( ! $get_all ) { 
  204. wp_cache_set( $blog_id . $all, $details, 'blog-details' ); 
  205. return $details; 
  206.  
  207. switch_to_blog( $blog_id ); 
  208. $details->blogname = get_option( 'blogname' ); 
  209. $details->siteurl = get_option( 'siteurl' ); 
  210. $details->post_count = get_option( 'post_count' ); 
  211. $details->home = get_option( 'home' ); 
  212. restore_current_blog(); 
  213.  
  214. /** 
  215. * Filters a blog's details. 
  216. * 
  217. * @since MU 
  218. * @deprecated 4.7.0 Use site_details 
  219. * 
  220. * @param object $details The blog details. 
  221. */ 
  222. $details = apply_filters_deprecated( 'blog_details', array( $details ), '4.7.0', 'site_details' ); 
  223.  
  224. wp_cache_set( $blog_id . $all, $details, 'blog-details' ); 
  225.  
  226. $key = md5( $details->domain . $details->path ); 
  227. wp_cache_set( $key, $details, 'blog-lookup' ); 
  228.  
  229. return $details; 
  230.  
  231. /** 
  232. * Clear the blog details cache. 
  233. * 
  234. * @since MU 
  235. * 
  236. * @param int $blog_id Optional. Blog ID. Defaults to current blog. 
  237. */ 
  238. function refresh_blog_details( $blog_id = 0 ) { 
  239. $blog_id = (int) $blog_id; 
  240. if ( ! $blog_id ) { 
  241. $blog_id = get_current_blog_id(); 
  242.  
  243. $details = get_site( $blog_id ); 
  244. if ( ! $details ) { 
  245. // Make sure clean_blog_cache() gets the blog ID 
  246. // when the blog has been previously cached as 
  247. // non-existent. 
  248. $details = (object) array( 
  249. 'blog_id' => $blog_id,  
  250. 'domain' => null,  
  251. 'path' => null 
  252. ); 
  253.  
  254. clean_blog_cache( $details ); 
  255.  
  256. /** 
  257. * Fires after the blog details cache is cleared. 
  258. * 
  259. * @since 3.4.0 
  260. * 
  261. * @param int $blog_id Blog ID. 
  262. */ 
  263. do_action( 'refresh_blog_details', $blog_id ); 
  264.  
  265. /** 
  266. * Update the details for a blog. Updates the blogs table for a given blog id. 
  267. * 
  268. * @since MU 
  269. * 
  270. * @global wpdb $wpdb WordPress database abstraction object. 
  271. * 
  272. * @param int $blog_id Blog ID 
  273. * @param array $details Array of details keyed by blogs table field names. 
  274. * @return bool True if update succeeds, false otherwise. 
  275. */ 
  276. function update_blog_details( $blog_id, $details = array() ) { 
  277. global $wpdb; 
  278.  
  279. if ( empty($details) ) 
  280. return false; 
  281.  
  282. if ( is_object($details) ) 
  283. $details = get_object_vars($details); 
  284.  
  285. $current_details = get_site( $blog_id ); 
  286. if ( empty($current_details) ) 
  287. return false; 
  288.  
  289. $current_details = get_object_vars($current_details); 
  290.  
  291. $details = array_merge($current_details, $details); 
  292. $details['last_updated'] = current_time('mysql', true); 
  293.  
  294. $update_details = array(); 
  295. $fields = array( 'site_id', 'domain', 'path', 'registered', 'last_updated', 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id'); 
  296. foreach ( array_intersect( array_keys( $details ), $fields ) as $field ) { 
  297. if ( 'path' === $field ) { 
  298. $details[ $field ] = trailingslashit( '/' . trim( $details[ $field ], '/' ) ); 
  299.  
  300. $update_details[ $field ] = $details[ $field ]; 
  301.  
  302. $result = $wpdb->update( $wpdb->blogs, $update_details, array('blog_id' => $blog_id) ); 
  303.  
  304. if ( false === $result ) 
  305. return false; 
  306.  
  307. // If spam status changed, issue actions. 
  308. if ( $details['spam'] != $current_details['spam'] ) { 
  309. if ( $details['spam'] == 1 ) { 
  310. /** 
  311. * Fires when the blog status is changed to 'spam'. 
  312. * 
  313. * @since MU 
  314. * 
  315. * @param int $blog_id Blog ID. 
  316. */ 
  317. do_action( 'make_spam_blog', $blog_id ); 
  318. } else { 
  319. /** 
  320. * Fires when the blog status is changed to 'ham'. 
  321. * 
  322. * @since MU 
  323. * 
  324. * @param int $blog_id Blog ID. 
  325. */ 
  326. do_action( 'make_ham_blog', $blog_id ); 
  327.  
  328. // If mature status changed, issue actions. 
  329. if ( $details['mature'] != $current_details['mature'] ) { 
  330. if ( $details['mature'] == 1 ) { 
  331. /** 
  332. * Fires when the blog status is changed to 'mature'. 
  333. * 
  334. * @since 3.1.0 
  335. * 
  336. * @param int $blog_id Blog ID. 
  337. */ 
  338. do_action( 'mature_blog', $blog_id ); 
  339. } else { 
  340. /** 
  341. * Fires when the blog status is changed to 'unmature'. 
  342. * 
  343. * @since 3.1.0 
  344. * 
  345. * @param int $blog_id Blog ID. 
  346. */ 
  347. do_action( 'unmature_blog', $blog_id ); 
  348.  
  349. // If archived status changed, issue actions. 
  350. if ( $details['archived'] != $current_details['archived'] ) { 
  351. if ( $details['archived'] == 1 ) { 
  352. /** 
  353. * Fires when the blog status is changed to 'archived'. 
  354. * 
  355. * @since MU 
  356. * 
  357. * @param int $blog_id Blog ID. 
  358. */ 
  359. do_action( 'archive_blog', $blog_id ); 
  360. } else { 
  361. /** 
  362. * Fires when the blog status is changed to 'unarchived'. 
  363. * 
  364. * @since MU 
  365. * 
  366. * @param int $blog_id Blog ID. 
  367. */ 
  368. do_action( 'unarchive_blog', $blog_id ); 
  369.  
  370. // If deleted status changed, issue actions. 
  371. if ( $details['deleted'] != $current_details['deleted'] ) { 
  372. if ( $details['deleted'] == 1 ) { 
  373. /** 
  374. * Fires when the blog status is changed to 'deleted'. 
  375. * 
  376. * @since 3.5.0 
  377. * 
  378. * @param int $blog_id Blog ID. 
  379. */ 
  380. do_action( 'make_delete_blog', $blog_id ); 
  381. } else { 
  382. /** 
  383. * Fires when the blog status is changed to 'undeleted'. 
  384. * 
  385. * @since 3.5.0 
  386. * 
  387. * @param int $blog_id Blog ID. 
  388. */ 
  389. do_action( 'make_undelete_blog', $blog_id ); 
  390.  
  391. if ( isset( $details['public'] ) ) { 
  392. switch_to_blog( $blog_id ); 
  393. update_option( 'blog_public', $details['public'] ); 
  394. restore_current_blog(); 
  395.  
  396. refresh_blog_details($blog_id); 
  397.  
  398. return true; 
  399.  
  400. /** 
  401. * Clean the blog cache 
  402. * 
  403. * @since 3.5.0 
  404. * 
  405. * @param WP_Site $blog The site object to be cleared from cache. 
  406. */ 
  407. function clean_blog_cache( $blog ) { 
  408. $blog_id = $blog->blog_id; 
  409. $domain_path_key = md5( $blog->domain . $blog->path ); 
  410.  
  411. wp_cache_delete( $blog_id, 'sites' ); 
  412. wp_cache_delete( $blog_id, 'site-details' ); 
  413. wp_cache_delete( $blog_id , 'blog-details' ); 
  414. wp_cache_delete( $blog_id . 'short' , 'blog-details' ); 
  415. wp_cache_delete( $domain_path_key, 'blog-lookup' ); 
  416. wp_cache_delete( 'current_blog_' . $blog->domain, 'site-options' ); 
  417. wp_cache_delete( 'current_blog_' . $blog->domain . $blog->path, 'site-options' ); 
  418. wp_cache_delete( $domain_path_key, 'blog-id-cache' ); 
  419.  
  420. /** 
  421. * Fires immediately after a site has been removed from the object cache. 
  422. * 
  423. * @since 4.6.0 
  424. * 
  425. * @param int $id Blog ID. 
  426. * @param WP_Site $blog Site object. 
  427. * @param string $domain_path_key md5 hash of domain and path. 
  428. */ 
  429. do_action( 'clean_site_cache', $blog_id, $blog, $domain_path_key ); 
  430.  
  431. wp_cache_set( 'last_changed', microtime(), 'sites' ); 
  432.  
  433. /** 
  434. * Retrieves site data given a site ID or site object. 
  435. * 
  436. * Site data will be cached and returned after being passed through a filter. 
  437. * If the provided site is empty, the current site global will be used. 
  438. * 
  439. * @since 4.6.0 
  440. * 
  441. * @param WP_Site|int|null $site Optional. Site to retrieve. Default is the current site. 
  442. * @return WP_Site|null The site object or null if not found. 
  443. */ 
  444. function get_site( $site = null ) { 
  445. if ( empty( $site ) ) { 
  446. $site = get_current_blog_id(); 
  447.  
  448. if ( $site instanceof WP_Site ) { 
  449. $_site = $site; 
  450. } elseif ( is_object( $site ) ) { 
  451. $_site = new WP_Site( $site ); 
  452. } else { 
  453. $_site = WP_Site::get_instance( $site ); 
  454.  
  455. if ( ! $_site ) { 
  456. return null; 
  457.  
  458. /** 
  459. * Fires after a site is retrieved. 
  460. * 
  461. * @since 4.6.0 
  462. * 
  463. * @param WP_Site $_site Site data. 
  464. */ 
  465. $_site = apply_filters( 'get_site', $_site ); 
  466.  
  467. return $_site; 
  468.  
  469. /** 
  470. * Adds any sites from the given ids to the cache that do not already exist in cache. 
  471. * 
  472. * @since 4.6.0 
  473. * @access private 
  474. * 
  475. * @see update_site_cache() 
  476. * @global wpdb $wpdb WordPress database abstraction object. 
  477. * 
  478. * @param array $ids ID list. 
  479. */ 
  480. function _prime_site_caches( $ids ) { 
  481. global $wpdb; 
  482.  
  483. $non_cached_ids = _get_non_cached_ids( $ids, 'sites' ); 
  484. if ( ! empty( $non_cached_ids ) ) { 
  485. $fresh_sites = $wpdb->get_results( sprintf( "SELECT * FROM $wpdb->blogs WHERE blog_id IN (%s)", join( ", ", array_map( 'intval', $non_cached_ids ) ) ) ); 
  486.  
  487. update_site_cache( $fresh_sites ); 
  488.  
  489. /** 
  490. * Updates sites in cache. 
  491. * 
  492. * @since 4.6.0 
  493. * 
  494. * @param array $sites Array of site objects. 
  495. */ 
  496. function update_site_cache( $sites ) { 
  497. if ( ! $sites ) { 
  498. return; 
  499.  
  500. foreach ( $sites as $site ) { 
  501. wp_cache_add( $site->blog_id, $site, 'sites' ); 
  502. wp_cache_add( $site->blog_id . 'short', $site, 'blog-details' ); 
  503.  
  504. /** 
  505. * Retrieves a list of sites matching requested arguments. 
  506. * 
  507. * @since 4.6.0 
  508. * 
  509. * @see WP_Site_Query::parse_query() 
  510. * 
  511. * @param string|array $args { 
  512. * Optional. Array or query string of site query parameters. Default empty. 
  513. * 
  514. * @type array $site__in Array of site IDs to include. Default empty. 
  515. * @type array $site__not_in Array of site IDs to exclude. Default empty. 
  516. * @type bool $count Whether to return a site count (true) or array of site objects. 
  517. * Default false. 
  518. * @type array $date_query Date query clauses to limit sites by. See WP_Date_Query. 
  519. * Default null. 
  520. * @type string $fields Site fields to return. Accepts 'ids' (returns an array of site IDs) 
  521. * or empty (returns an array of complete site objects). Default empty. 
  522. * @type int $ID A site ID to only return that site. Default empty. 
  523. * @type int $number Maximum number of sites to retrieve. Default 100. 
  524. * @type int $offset Number of sites to offset the query. Used to build LIMIT clause. 
  525. * Default 0. 
  526. * @type bool $no_found_rows Whether to disable the `SQL_CALC_FOUND_ROWS` query. Default true. 
  527. * @type string|array $orderby Site status or array of statuses. Accepts 'id', 'domain', 'path',  
  528. * 'network_id', 'last_updated', 'registered', 'domain_length',  
  529. * 'path_length', 'site__in' and 'network__in'. Also accepts false,  
  530. * an empty array, or 'none' to disable `ORDER BY` clause. 
  531. * Default 'id'. 
  532. * @type string $order How to order retrieved sites. Accepts 'ASC', 'DESC'. Default 'ASC'. 
  533. * @type int $network_id Limit results to those affiliated with a given network ID. If 0,  
  534. * include all networks. Default 0. 
  535. * @type array $network__in Array of network IDs to include affiliated sites for. Default empty. 
  536. * @type array $network__not_in Array of network IDs to exclude affiliated sites for. Default empty. 
  537. * @type string $domain Limit results to those affiliated with a given domain. Default empty. 
  538. * @type array $domain__in Array of domains to include affiliated sites for. Default empty. 
  539. * @type array $domain__not_in Array of domains to exclude affiliated sites for. Default empty. 
  540. * @type string $path Limit results to those affiliated with a given path. Default empty. 
  541. * @type array $path__in Array of paths to include affiliated sites for. Default empty. 
  542. * @type array $path__not_in Array of paths to exclude affiliated sites for. Default empty. 
  543. * @type int $public Limit results to public sites. Accepts '1' or '0'. Default empty. 
  544. * @type int $archived Limit results to archived sites. Accepts '1' or '0'. Default empty. 
  545. * @type int $mature Limit results to mature sites. Accepts '1' or '0'. Default empty. 
  546. * @type int $spam Limit results to spam sites. Accepts '1' or '0'. Default empty. 
  547. * @type int $deleted Limit results to deleted sites. Accepts '1' or '0'. Default empty. 
  548. * @type string $search Search term(s) to retrieve matching sites for. Default empty. 
  549. * @type array $search_columns Array of column names to be searched. Accepts 'domain' and 'path'. 
  550. * Default empty array. 
  551. * @type bool $update_site_cache Whether to prime the cache for found sites. Default false. 
  552. * } 
  553. * @return array List of sites. 
  554. */ 
  555. function get_sites( $args = array() ) { 
  556. $query = new WP_Site_Query(); 
  557.  
  558. return $query->query( $args ); 
  559.  
  560. /** 
  561. * Retrieve option value for a given blog id based on name of option. 
  562. * 
  563. * If the option does not exist or does not have a value, then the return value 
  564. * will be false. This is useful to check whether you need to install an option 
  565. * and is commonly used during installation of plugin options and to test 
  566. * whether upgrading is required. 
  567. * 
  568. * If the option was serialized then it will be unserialized when it is returned. 
  569. * 
  570. * @since MU 
  571. * 
  572. * @param int $id A blog ID. Can be null to refer to the current blog. 
  573. * @param string $option Name of option to retrieve. Expected to not be SQL-escaped. 
  574. * @param mixed $default Optional. Default value to return if the option does not exist. 
  575. * @return mixed Value set for the option. 
  576. */ 
  577. function get_blog_option( $id, $option, $default = false ) { 
  578. $id = (int) $id; 
  579.  
  580. if ( empty( $id ) ) 
  581. $id = get_current_blog_id(); 
  582.  
  583. if ( get_current_blog_id() == $id ) 
  584. return get_option( $option, $default ); 
  585.  
  586. switch_to_blog( $id ); 
  587. $value = get_option( $option, $default ); 
  588. restore_current_blog(); 
  589.  
  590. /** 
  591. * Filters a blog option value. 
  592. * 
  593. * The dynamic portion of the hook name, `$option`, refers to the blog option name. 
  594. * 
  595. * @since 3.5.0 
  596. * 
  597. * @param string $value The option value. 
  598. * @param int $id Blog ID. 
  599. */ 
  600. return apply_filters( "blog_option_{$option}", $value, $id ); 
  601.  
  602. /** 
  603. * Add a new option for a given blog id. 
  604. * 
  605. * You do not need to serialize values. If the value needs to be serialized, then 
  606. * it will be serialized before it is inserted into the database. Remember,  
  607. * resources can not be serialized or added as an option. 
  608. * 
  609. * You can create options without values and then update the values later. 
  610. * Existing options will not be updated and checks are performed to ensure that you 
  611. * aren't adding a protected WordPress option. Care should be taken to not name 
  612. * options the same as the ones which are protected. 
  613. * 
  614. * @since MU 
  615. * 
  616. * @param int $id A blog ID. Can be null to refer to the current blog. 
  617. * @param string $option Name of option to add. Expected to not be SQL-escaped. 
  618. * @param mixed $value Optional. Option value, can be anything. Expected to not be SQL-escaped. 
  619. * @return bool False if option was not added and true if option was added. 
  620. */ 
  621. function add_blog_option( $id, $option, $value ) { 
  622. $id = (int) $id; 
  623.  
  624. if ( empty( $id ) ) 
  625. $id = get_current_blog_id(); 
  626.  
  627. if ( get_current_blog_id() == $id ) 
  628. return add_option( $option, $value ); 
  629.  
  630. switch_to_blog( $id ); 
  631. $return = add_option( $option, $value ); 
  632. restore_current_blog(); 
  633.  
  634. return $return; 
  635.  
  636. /** 
  637. * Removes option by name for a given blog id. Prevents removal of protected WordPress options. 
  638. * 
  639. * @since MU 
  640. * 
  641. * @param int $id A blog ID. Can be null to refer to the current blog. 
  642. * @param string $option Name of option to remove. Expected to not be SQL-escaped. 
  643. * @return bool True, if option is successfully deleted. False on failure. 
  644. */ 
  645. function delete_blog_option( $id, $option ) { 
  646. $id = (int) $id; 
  647.  
  648. if ( empty( $id ) ) 
  649. $id = get_current_blog_id(); 
  650.  
  651. if ( get_current_blog_id() == $id ) 
  652. return delete_option( $option ); 
  653.  
  654. switch_to_blog( $id ); 
  655. $return = delete_option( $option ); 
  656. restore_current_blog(); 
  657.  
  658. return $return; 
  659.  
  660. /** 
  661. * Update an option for a particular blog. 
  662. * 
  663. * @since MU 
  664. * 
  665. * @param int $id The blog id. 
  666. * @param string $option The option key. 
  667. * @param mixed $value The option value. 
  668. * @param mixed $deprecated Not used. 
  669. * @return bool True on success, false on failure. 
  670. */ 
  671. function update_blog_option( $id, $option, $value, $deprecated = null ) { 
  672. $id = (int) $id; 
  673.  
  674. if ( null !== $deprecated ) 
  675. _deprecated_argument( __FUNCTION__, '3.1.0' ); 
  676.  
  677. if ( get_current_blog_id() == $id ) 
  678. return update_option( $option, $value ); 
  679.  
  680. switch_to_blog( $id ); 
  681. $return = update_option( $option, $value ); 
  682. restore_current_blog(); 
  683.  
  684. refresh_blog_details( $id ); 
  685.  
  686. return $return; 
  687.  
  688. /** 
  689. * Switch the current blog. 
  690. * 
  691. * This function is useful if you need to pull posts, or other information,  
  692. * from other blogs. You can switch back afterwards using restore_current_blog(). 
  693. * 
  694. * Things that aren't switched: 
  695. * - autoloaded options. See #14992 
  696. * - plugins. See #14941 
  697. * 
  698. * @see restore_current_blog() 
  699. * @since MU 
  700. * 
  701. * @global wpdb $wpdb 
  702. * @global int $blog_id 
  703. * @global array $_wp_switched_stack 
  704. * @global bool $switched 
  705. * @global string $table_prefix 
  706. * @global WP_Object_Cache $wp_object_cache 
  707. * 
  708. * @param int $new_blog The id of the blog you want to switch to. Default: current blog 
  709. * @param bool $deprecated Deprecated argument 
  710. * @return true Always returns True. 
  711. */ 
  712. function switch_to_blog( $new_blog, $deprecated = null ) { 
  713. global $wpdb, $wp_roles; 
  714.  
  715. $blog_id = get_current_blog_id(); 
  716. if ( empty( $new_blog ) ) { 
  717. $new_blog = $blog_id; 
  718.  
  719. $GLOBALS['_wp_switched_stack'][] = $blog_id; 
  720.  
  721. /** 
  722. * If we're switching to the same blog id that we're on,  
  723. * set the right vars, do the associated actions, but skip 
  724. * the extra unnecessary work 
  725. */ 
  726. if ( $new_blog == $blog_id ) { 
  727. /** 
  728. * Fires when the blog is switched. 
  729. * 
  730. * @since MU 
  731. * 
  732. * @param int $new_blog New blog ID. 
  733. * @param int $new_blog Blog ID. 
  734. */ 
  735. do_action( 'switch_blog', $new_blog, $new_blog ); 
  736. $GLOBALS['switched'] = true; 
  737. return true; 
  738.  
  739. $wpdb->set_blog_id( $new_blog ); 
  740. $GLOBALS['table_prefix'] = $wpdb->get_blog_prefix(); 
  741. $prev_blog_id = $blog_id; 
  742. $GLOBALS['blog_id'] = $new_blog; 
  743.  
  744. if ( function_exists( 'wp_cache_switch_to_blog' ) ) { 
  745. wp_cache_switch_to_blog( $new_blog ); 
  746. } else { 
  747. global $wp_object_cache; 
  748.  
  749. if ( is_object( $wp_object_cache ) && isset( $wp_object_cache->global_groups ) ) { 
  750. $global_groups = $wp_object_cache->global_groups; 
  751. } else { 
  752. $global_groups = false; 
  753. wp_cache_init(); 
  754.  
  755. if ( function_exists( 'wp_cache_add_global_groups' ) ) { 
  756. if ( is_array( $global_groups ) ) { 
  757. wp_cache_add_global_groups( $global_groups ); 
  758. } else { 
  759. wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'useremail', 'userslugs', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache', 'networks', 'sites', 'site-details' ) ); 
  760. wp_cache_add_non_persistent_groups( array( 'counts', 'plugins' ) ); 
  761.  
  762. if ( did_action( 'init' ) ) { 
  763. $wp_roles = new WP_Roles(); 
  764. $current_user = wp_get_current_user(); 
  765. $current_user->for_blog( $new_blog ); 
  766.  
  767. /** This filter is documented in wp-includes/ms-blogs.php */ 
  768. do_action( 'switch_blog', $new_blog, $prev_blog_id ); 
  769. $GLOBALS['switched'] = true; 
  770.  
  771. return true; 
  772.  
  773. /** 
  774. * Restore the current blog, after calling switch_to_blog() 
  775. * 
  776. * @see switch_to_blog() 
  777. * @since MU 
  778. * 
  779. * @global wpdb $wpdb 
  780. * @global array $_wp_switched_stack 
  781. * @global int $blog_id 
  782. * @global bool $switched 
  783. * @global string $table_prefix 
  784. * @global WP_Object_Cache $wp_object_cache 
  785. * 
  786. * @return bool True on success, false if we're already on the current blog 
  787. */ 
  788. function restore_current_blog() { 
  789. global $wpdb, $wp_roles; 
  790.  
  791. if ( empty( $GLOBALS['_wp_switched_stack'] ) ) { 
  792. return false; 
  793.  
  794. $blog = array_pop( $GLOBALS['_wp_switched_stack'] ); 
  795. $blog_id = get_current_blog_id(); 
  796.  
  797. if ( $blog_id == $blog ) { 
  798. /** This filter is documented in wp-includes/ms-blogs.php */ 
  799. do_action( 'switch_blog', $blog, $blog ); 
  800. // If we still have items in the switched stack, consider ourselves still 'switched' 
  801. $GLOBALS['switched'] = ! empty( $GLOBALS['_wp_switched_stack'] ); 
  802. return true; 
  803.  
  804. $wpdb->set_blog_id( $blog ); 
  805. $prev_blog_id = $blog_id; 
  806. $GLOBALS['blog_id'] = $blog; 
  807. $GLOBALS['table_prefix'] = $wpdb->get_blog_prefix(); 
  808.  
  809. if ( function_exists( 'wp_cache_switch_to_blog' ) ) { 
  810. wp_cache_switch_to_blog( $blog ); 
  811. } else { 
  812. global $wp_object_cache; 
  813.  
  814. if ( is_object( $wp_object_cache ) && isset( $wp_object_cache->global_groups ) ) { 
  815. $global_groups = $wp_object_cache->global_groups; 
  816. } else { 
  817. $global_groups = false; 
  818.  
  819. wp_cache_init(); 
  820.  
  821. if ( function_exists( 'wp_cache_add_global_groups' ) ) { 
  822. if ( is_array( $global_groups ) ) { 
  823. wp_cache_add_global_groups( $global_groups ); 
  824. } else { 
  825. wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'useremail', 'userslugs', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache', 'networks', 'sites', 'site-details' ) ); 
  826. wp_cache_add_non_persistent_groups( array( 'counts', 'plugins' ) ); 
  827.  
  828. if ( did_action( 'init' ) ) { 
  829. $wp_roles = new WP_Roles(); 
  830. $current_user = wp_get_current_user(); 
  831. $current_user->for_blog( $blog ); 
  832.  
  833. /** This filter is documented in wp-includes/ms-blogs.php */ 
  834. do_action( 'switch_blog', $blog, $prev_blog_id ); 
  835.  
  836. // If we still have items in the switched stack, consider ourselves still 'switched' 
  837. $GLOBALS['switched'] = ! empty( $GLOBALS['_wp_switched_stack'] ); 
  838.  
  839. return true; 
  840.  
  841. /** 
  842. * Determines if switch_to_blog() is in effect 
  843. * 
  844. * @since 3.5.0 
  845. * 
  846. * @global array $_wp_switched_stack 
  847. * 
  848. * @return bool True if switched, false otherwise. 
  849. */ 
  850. function ms_is_switched() { 
  851. return ! empty( $GLOBALS['_wp_switched_stack'] ); 
  852.  
  853. /** 
  854. * Check if a particular blog is archived. 
  855. * 
  856. * @since MU 
  857. * 
  858. * @param int $id The blog id 
  859. * @return string Whether the blog is archived or not 
  860. */ 
  861. function is_archived( $id ) { 
  862. return get_blog_status($id, 'archived'); 
  863.  
  864. /** 
  865. * Update the 'archived' status of a particular blog. 
  866. * 
  867. * @since MU 
  868. * 
  869. * @param int $id The blog id 
  870. * @param string $archived The new status 
  871. * @return string $archived 
  872. */ 
  873. function update_archived( $id, $archived ) { 
  874. update_blog_status($id, 'archived', $archived); 
  875. return $archived; 
  876.  
  877. /** 
  878. * Update a blog details field. 
  879. * 
  880. * @since MU 
  881. * 
  882. * @global wpdb $wpdb WordPress database abstraction object. 
  883. * 
  884. * @param int $blog_id BLog ID 
  885. * @param string $pref A field name 
  886. * @param string $value Value for $pref 
  887. * @param null $deprecated 
  888. * @return string|false $value 
  889. */ 
  890. function update_blog_status( $blog_id, $pref, $value, $deprecated = null ) { 
  891. global $wpdb; 
  892.  
  893. if ( null !== $deprecated ) 
  894. _deprecated_argument( __FUNCTION__, '3.1.0' ); 
  895.  
  896. if ( ! in_array( $pref, array( 'site_id', 'domain', 'path', 'registered', 'last_updated', 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id') ) ) 
  897. return $value; 
  898.  
  899. $result = $wpdb->update( $wpdb->blogs, array($pref => $value, 'last_updated' => current_time('mysql', true)), array('blog_id' => $blog_id) ); 
  900.  
  901. if ( false === $result ) 
  902. return false; 
  903.  
  904. refresh_blog_details( $blog_id ); 
  905.  
  906. if ( 'spam' == $pref ) { 
  907. if ( $value == 1 ) { 
  908. /** This filter is documented in wp-includes/ms-blogs.php */ 
  909. do_action( 'make_spam_blog', $blog_id ); 
  910. } else { 
  911. /** This filter is documented in wp-includes/ms-blogs.php */ 
  912. do_action( 'make_ham_blog', $blog_id ); 
  913. } elseif ( 'mature' == $pref ) { 
  914. if ( $value == 1 ) { 
  915. /** This filter is documented in wp-includes/ms-blogs.php */ 
  916. do_action( 'mature_blog', $blog_id ); 
  917. } else { 
  918. /** This filter is documented in wp-includes/ms-blogs.php */ 
  919. do_action( 'unmature_blog', $blog_id ); 
  920. } elseif ( 'archived' == $pref ) { 
  921. if ( $value == 1 ) { 
  922. /** This filter is documented in wp-includes/ms-blogs.php */ 
  923. do_action( 'archive_blog', $blog_id ); 
  924. } else { 
  925. /** This filter is documented in wp-includes/ms-blogs.php */ 
  926. do_action( 'unarchive_blog', $blog_id ); 
  927. } elseif ( 'deleted' == $pref ) { 
  928. if ( $value == 1 ) { 
  929. /** This filter is documented in wp-includes/ms-blogs.php */ 
  930. do_action( 'make_delete_blog', $blog_id ); 
  931. } else { 
  932. /** This filter is documented in wp-includes/ms-blogs.php */ 
  933. do_action( 'make_undelete_blog', $blog_id ); 
  934. } elseif ( 'public' == $pref ) { 
  935. /** 
  936. * Fires after the current blog's 'public' setting is updated. 
  937. * 
  938. * @since MU 
  939. * 
  940. * @param int $blog_id Blog ID. 
  941. * @param string $value The value of blog status. 
  942. */ 
  943. do_action( 'update_blog_public', $blog_id, $value ); // Moved here from update_blog_public(). 
  944.  
  945. return $value; 
  946.  
  947. /** 
  948. * Get a blog details field. 
  949. * 
  950. * @since MU 
  951. * 
  952. * @global wpdb $wpdb WordPress database abstraction object. 
  953. * 
  954. * @param int $id The blog id 
  955. * @param string $pref A field name 
  956. * @return bool|string|null $value 
  957. */ 
  958. function get_blog_status( $id, $pref ) { 
  959. global $wpdb; 
  960.  
  961. $details = get_site( $id ); 
  962. if ( $details ) 
  963. return $details->$pref; 
  964.  
  965. return $wpdb->get_var( $wpdb->prepare("SELECT %s FROM {$wpdb->blogs} WHERE blog_id = %d", $pref, $id) ); 
  966.  
  967. /** 
  968. * Get a list of most recently updated blogs. 
  969. * 
  970. * @since MU 
  971. * 
  972. * @global wpdb $wpdb WordPress database abstraction object. 
  973. * 
  974. * @param mixed $deprecated Not used 
  975. * @param int $start The offset 
  976. * @param int $quantity The maximum number of blogs to retrieve. Default is 40. 
  977. * @return array The list of blogs 
  978. */ 
  979. function get_last_updated( $deprecated = '', $start = 0, $quantity = 40 ) { 
  980. global $wpdb; 
  981.  
  982. if ( ! empty( $deprecated ) ) 
  983. _deprecated_argument( __FUNCTION__, 'MU' ); // never used 
  984.  
  985. return $wpdb->get_results( $wpdb->prepare("SELECT blog_id, domain, path FROM $wpdb->blogs WHERE site_id = %d AND public = '1' AND archived = '0' AND mature = '0' AND spam = '0' AND deleted = '0' AND last_updated != '0000-00-00 00:00:00' ORDER BY last_updated DESC limit %d, %d", $wpdb->siteid, $start, $quantity ) , ARRAY_A ); 
  986.  
  987. /** 
  988. * Retrieves a list of networks. 
  989. * 
  990. * @since 4.6.0 
  991. * 
  992. * @param string|array $args Optional. Array or string of arguments. See WP_Network_Query::parse_query() 
  993. * for information on accepted arguments. Default empty array. 
  994. * @return int|array List of networks or number of found networks if `$count` argument is true. 
  995. */ 
  996. function get_networks( $args = array() ) { 
  997. $query = new WP_Network_Query(); 
  998.  
  999. return $query->query( $args ); 
  1000.  
  1001. /** 
  1002. * Retrieves network data given a network ID or network object. 
  1003. * 
  1004. * Network data will be cached and returned after being passed through a filter. 
  1005. * If the provided network is empty, the current network global will be used. 
  1006. * 
  1007. * @since 4.6.0 
  1008. * 
  1009. * @global WP_Network $current_site 
  1010. * 
  1011. * @param WP_Network|int|null $network Optional. Network to retrieve. Default is the current network. 
  1012. * @return WP_Network|null The network object or null if not found. 
  1013. */ 
  1014. function get_network( $network = null ) { 
  1015. global $current_site; 
  1016. if ( empty( $network ) && isset( $current_site ) ) { 
  1017. $network = $current_site; 
  1018.  
  1019. if ( $network instanceof WP_Network ) { 
  1020. $_network = $network; 
  1021. } elseif ( is_object( $network ) ) { 
  1022. $_network = new WP_Network( $network ); 
  1023. } else { 
  1024. $_network = WP_Network::get_instance( $network ); 
  1025.  
  1026. if ( ! $_network ) { 
  1027. return null; 
  1028.  
  1029. /** 
  1030. * Fires after a network is retrieved. 
  1031. * 
  1032. * @since 4.6.0 
  1033. * 
  1034. * @param WP_Network $_network Network data. 
  1035. */ 
  1036. $_network = apply_filters( 'get_network', $_network ); 
  1037.  
  1038. return $_network; 
  1039.  
  1040. /** 
  1041. * Removes a network from the object cache. 
  1042. * 
  1043. * @since 4.6.0 
  1044. * 
  1045. * @param int|array $ids Network ID or an array of network IDs to remove from cache. 
  1046. */ 
  1047. function clean_network_cache( $ids ) { 
  1048. foreach ( (array) $ids as $id ) { 
  1049. wp_cache_delete( $id, 'networks' ); 
  1050.  
  1051. /** 
  1052. * Fires immediately after a network has been removed from the object cache. 
  1053. * 
  1054. * @since 4.6.0 
  1055. * 
  1056. * @param int $id Network ID. 
  1057. */ 
  1058. do_action( 'clean_network_cache', $id ); 
  1059.  
  1060. wp_cache_set( 'last_changed', microtime(), 'networks' ); 
  1061.  
  1062. /** 
  1063. * Updates the network cache of given networks. 
  1064. * 
  1065. * Will add the networks in $networks to the cache. If network ID already exists 
  1066. * in the network cache then it will not be updated. The network is added to the 
  1067. * cache using the network group with the key using the ID of the networks. 
  1068. * 
  1069. * @since 4.6.0 
  1070. * 
  1071. * @param array $networks Array of network row objects. 
  1072. */ 
  1073. function update_network_cache( $networks ) { 
  1074. foreach ( (array) $networks as $network ) { 
  1075. wp_cache_add( $network->id, $network, 'networks' ); 
  1076.  
  1077. /** 
  1078. * Adds any networks from the given IDs to the cache that do not already exist in cache. 
  1079. * 
  1080. * @since 4.6.0 
  1081. * @access private 
  1082. * 
  1083. * @see update_network_cache() 
  1084. * @global wpdb $wpdb WordPress database abstraction object. 
  1085. * 
  1086. * @param array $network_ids Array of network IDs. 
  1087. */ 
  1088. function _prime_network_caches( $network_ids ) { 
  1089. global $wpdb; 
  1090.  
  1091. $non_cached_ids = _get_non_cached_ids( $network_ids, 'networks' ); 
  1092. if ( !empty( $non_cached_ids ) ) { 
  1093. $fresh_networks = $wpdb->get_results( sprintf( "SELECT $wpdb->site.* FROM $wpdb->site WHERE id IN (%s)", join( ", ", array_map( 'intval', $non_cached_ids ) ) ) ); 
  1094.  
  1095. update_network_cache( $fresh_networks ); 
  1096.  
  1097. /** 
  1098. * Handler for updating the blog date when a post is published or an already published post is changed. 
  1099. * 
  1100. * @since 3.3.0 
  1101. * 
  1102. * @param string $new_status The new post status 
  1103. * @param string $old_status The old post status 
  1104. * @param object $post Post object 
  1105. */ 
  1106. function _update_blog_date_on_post_publish( $new_status, $old_status, $post ) { 
  1107. $post_type_obj = get_post_type_object( $post->post_type ); 
  1108. if ( ! $post_type_obj || ! $post_type_obj->public ) { 
  1109. return; 
  1110.  
  1111. if ( 'publish' != $new_status && 'publish' != $old_status ) { 
  1112. return; 
  1113.  
  1114. // Post was freshly published, published post was saved, or published post was unpublished. 
  1115.  
  1116. wpmu_update_blogs_date(); 
  1117.  
  1118. /** 
  1119. * Handler for updating the blog date when a published post is deleted. 
  1120. * 
  1121. * @since 3.4.0 
  1122. * 
  1123. * @param int $post_id Post ID 
  1124. */ 
  1125. function _update_blog_date_on_post_delete( $post_id ) { 
  1126. $post = get_post( $post_id ); 
  1127.  
  1128. $post_type_obj = get_post_type_object( $post->post_type ); 
  1129. if ( ! $post_type_obj || ! $post_type_obj->public ) { 
  1130. return; 
  1131.  
  1132. if ( 'publish' != $post->post_status ) { 
  1133. return; 
  1134.  
  1135. wpmu_update_blogs_date(); 
  1136.  
  1137. /** 
  1138. * Handler for updating the blog posts count date when a post is deleted. 
  1139. * 
  1140. * @since 4.0.0 
  1141. * 
  1142. * @param int $post_id Post ID. 
  1143. */ 
  1144. function _update_posts_count_on_delete( $post_id ) { 
  1145. $post = get_post( $post_id ); 
  1146.  
  1147. if ( ! $post || 'publish' !== $post->post_status ) { 
  1148. return; 
  1149.  
  1150. update_posts_count(); 
  1151.  
  1152. /** 
  1153. * Handler for updating the blog posts count date when a post status changes. 
  1154. * 
  1155. * @since 4.0.0 
  1156. * 
  1157. * @param string $new_status The status the post is changing to. 
  1158. * @param string $old_status The status the post is changing from. 
  1159. */ 
  1160. function _update_posts_count_on_transition_post_status( $new_status, $old_status ) { 
  1161. if ( $new_status === $old_status ) { 
  1162. return; 
  1163.  
  1164. if ( 'publish' !== $new_status && 'publish' !== $old_status ) { 
  1165. return; 
  1166.  
  1167. update_posts_count(); 
.