/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. * Cleans the site details cache for a site. 
  435. * 
  436. * @since 4.7.4 
  437. * 
  438. * @param int $site_id Optional. Site ID. Default is the current site ID. 
  439. */ 
  440. function clean_site_details_cache( $site_id = 0 ) { 
  441. $site_id = (int) $site_id; 
  442. if ( ! $site_id ) { 
  443. $site_id = get_current_blog_id(); 
  444.  
  445. wp_cache_delete( $site_id, 'site-details' ); 
  446. wp_cache_delete( $site_id, 'blog-details' ); 
  447.  
  448. /** 
  449. * Retrieves site data given a site ID or site object. 
  450. * 
  451. * Site data will be cached and returned after being passed through a filter. 
  452. * If the provided site is empty, the current site global will be used. 
  453. * 
  454. * @since 4.6.0 
  455. * 
  456. * @param WP_Site|int|null $site Optional. Site to retrieve. Default is the current site. 
  457. * @return WP_Site|null The site object or null if not found. 
  458. */ 
  459. function get_site( $site = null ) { 
  460. if ( empty( $site ) ) { 
  461. $site = get_current_blog_id(); 
  462.  
  463. if ( $site instanceof WP_Site ) { 
  464. $_site = $site; 
  465. } elseif ( is_object( $site ) ) { 
  466. $_site = new WP_Site( $site ); 
  467. } else { 
  468. $_site = WP_Site::get_instance( $site ); 
  469.  
  470. if ( ! $_site ) { 
  471. return null; 
  472.  
  473. /** 
  474. * Fires after a site is retrieved. 
  475. * 
  476. * @since 4.6.0 
  477. * 
  478. * @param WP_Site $_site Site data. 
  479. */ 
  480. $_site = apply_filters( 'get_site', $_site ); 
  481.  
  482. return $_site; 
  483.  
  484. /** 
  485. * Adds any sites from the given ids to the cache that do not already exist in cache. 
  486. * 
  487. * @since 4.6.0 
  488. * @access private 
  489. * 
  490. * @see update_site_cache() 
  491. * @global wpdb $wpdb WordPress database abstraction object. 
  492. * 
  493. * @param array $ids ID list. 
  494. */ 
  495. function _prime_site_caches( $ids ) { 
  496. global $wpdb; 
  497.  
  498. $non_cached_ids = _get_non_cached_ids( $ids, 'sites' ); 
  499. if ( ! empty( $non_cached_ids ) ) { 
  500. $fresh_sites = $wpdb->get_results( sprintf( "SELECT * FROM $wpdb->blogs WHERE blog_id IN (%s)", join( ", ", array_map( 'intval', $non_cached_ids ) ) ) ); 
  501.  
  502. update_site_cache( $fresh_sites ); 
  503.  
  504. /** 
  505. * Updates sites in cache. 
  506. * 
  507. * @since 4.6.0 
  508. * 
  509. * @param array $sites Array of site objects. 
  510. */ 
  511. function update_site_cache( $sites ) { 
  512. if ( ! $sites ) { 
  513. return; 
  514.  
  515. foreach ( $sites as $site ) { 
  516. wp_cache_add( $site->blog_id, $site, 'sites' ); 
  517. wp_cache_add( $site->blog_id . 'short', $site, 'blog-details' ); 
  518.  
  519. /** 
  520. * Retrieves a list of sites matching requested arguments. 
  521. * 
  522. * @since 4.6.0 
  523. * 
  524. * @see WP_Site_Query::parse_query() 
  525. * 
  526. * @param string|array $args { 
  527. * Optional. Array or query string of site query parameters. Default empty. 
  528. * 
  529. * @type array $site__in Array of site IDs to include. Default empty. 
  530. * @type array $site__not_in Array of site IDs to exclude. Default empty. 
  531. * @type bool $count Whether to return a site count (true) or array of site objects. 
  532. * Default false. 
  533. * @type array $date_query Date query clauses to limit sites by. See WP_Date_Query. 
  534. * Default null. 
  535. * @type string $fields Site fields to return. Accepts 'ids' (returns an array of site IDs) 
  536. * or empty (returns an array of complete site objects). Default empty. 
  537. * @type int $ID A site ID to only return that site. Default empty. 
  538. * @type int $number Maximum number of sites to retrieve. Default 100. 
  539. * @type int $offset Number of sites to offset the query. Used to build LIMIT clause. 
  540. * Default 0. 
  541. * @type bool $no_found_rows Whether to disable the `SQL_CALC_FOUND_ROWS` query. Default true. 
  542. * @type string|array $orderby Site status or array of statuses. Accepts 'id', 'domain', 'path',  
  543. * 'network_id', 'last_updated', 'registered', 'domain_length',  
  544. * 'path_length', 'site__in' and 'network__in'. Also accepts false,  
  545. * an empty array, or 'none' to disable `ORDER BY` clause. 
  546. * Default 'id'. 
  547. * @type string $order How to order retrieved sites. Accepts 'ASC', 'DESC'. Default 'ASC'. 
  548. * @type int $network_id Limit results to those affiliated with a given network ID. If 0,  
  549. * include all networks. Default 0. 
  550. * @type array $network__in Array of network IDs to include affiliated sites for. Default empty. 
  551. * @type array $network__not_in Array of network IDs to exclude affiliated sites for. Default empty. 
  552. * @type string $domain Limit results to those affiliated with a given domain. Default empty. 
  553. * @type array $domain__in Array of domains to include affiliated sites for. Default empty. 
  554. * @type array $domain__not_in Array of domains to exclude affiliated sites for. Default empty. 
  555. * @type string $path Limit results to those affiliated with a given path. Default empty. 
  556. * @type array $path__in Array of paths to include affiliated sites for. Default empty. 
  557. * @type array $path__not_in Array of paths to exclude affiliated sites for. Default empty. 
  558. * @type int $public Limit results to public sites. Accepts '1' or '0'. Default empty. 
  559. * @type int $archived Limit results to archived sites. Accepts '1' or '0'. Default empty. 
  560. * @type int $mature Limit results to mature sites. Accepts '1' or '0'. Default empty. 
  561. * @type int $spam Limit results to spam sites. Accepts '1' or '0'. Default empty. 
  562. * @type int $deleted Limit results to deleted sites. Accepts '1' or '0'. Default empty. 
  563. * @type string $search Search term(s) to retrieve matching sites for. Default empty. 
  564. * @type array $search_columns Array of column names to be searched. Accepts 'domain' and 'path'. 
  565. * Default empty array. 
  566. * @type bool $update_site_cache Whether to prime the cache for found sites. Default false. 
  567. * } 
  568. * @return array List of sites. 
  569. */ 
  570. function get_sites( $args = array() ) { 
  571. $query = new WP_Site_Query(); 
  572.  
  573. return $query->query( $args ); 
  574.  
  575. /** 
  576. * Retrieve option value for a given blog id based on name of option. 
  577. * 
  578. * If the option does not exist or does not have a value, then the return value 
  579. * will be false. This is useful to check whether you need to install an option 
  580. * and is commonly used during installation of plugin options and to test 
  581. * whether upgrading is required. 
  582. * 
  583. * If the option was serialized then it will be unserialized when it is returned. 
  584. * 
  585. * @since MU 
  586. * 
  587. * @param int $id A blog ID. Can be null to refer to the current blog. 
  588. * @param string $option Name of option to retrieve. Expected to not be SQL-escaped. 
  589. * @param mixed $default Optional. Default value to return if the option does not exist. 
  590. * @return mixed Value set for the option. 
  591. */ 
  592. function get_blog_option( $id, $option, $default = false ) { 
  593. $id = (int) $id; 
  594.  
  595. if ( empty( $id ) ) 
  596. $id = get_current_blog_id(); 
  597.  
  598. if ( get_current_blog_id() == $id ) 
  599. return get_option( $option, $default ); 
  600.  
  601. switch_to_blog( $id ); 
  602. $value = get_option( $option, $default ); 
  603. restore_current_blog(); 
  604.  
  605. /** 
  606. * Filters a blog option value. 
  607. * 
  608. * The dynamic portion of the hook name, `$option`, refers to the blog option name. 
  609. * 
  610. * @since 3.5.0 
  611. * 
  612. * @param string $value The option value. 
  613. * @param int $id Blog ID. 
  614. */ 
  615. return apply_filters( "blog_option_{$option}", $value, $id ); 
  616.  
  617. /** 
  618. * Add a new option for a given blog id. 
  619. * 
  620. * You do not need to serialize values. If the value needs to be serialized, then 
  621. * it will be serialized before it is inserted into the database. Remember,  
  622. * resources can not be serialized or added as an option. 
  623. * 
  624. * You can create options without values and then update the values later. 
  625. * Existing options will not be updated and checks are performed to ensure that you 
  626. * aren't adding a protected WordPress option. Care should be taken to not name 
  627. * options the same as the ones which are protected. 
  628. * 
  629. * @since MU 
  630. * 
  631. * @param int $id A blog ID. Can be null to refer to the current blog. 
  632. * @param string $option Name of option to add. Expected to not be SQL-escaped. 
  633. * @param mixed $value Optional. Option value, can be anything. Expected to not be SQL-escaped. 
  634. * @return bool False if option was not added and true if option was added. 
  635. */ 
  636. function add_blog_option( $id, $option, $value ) { 
  637. $id = (int) $id; 
  638.  
  639. if ( empty( $id ) ) 
  640. $id = get_current_blog_id(); 
  641.  
  642. if ( get_current_blog_id() == $id ) 
  643. return add_option( $option, $value ); 
  644.  
  645. switch_to_blog( $id ); 
  646. $return = add_option( $option, $value ); 
  647. restore_current_blog(); 
  648.  
  649. return $return; 
  650.  
  651. /** 
  652. * Removes option by name for a given blog id. Prevents removal of protected WordPress options. 
  653. * 
  654. * @since MU 
  655. * 
  656. * @param int $id A blog ID. Can be null to refer to the current blog. 
  657. * @param string $option Name of option to remove. Expected to not be SQL-escaped. 
  658. * @return bool True, if option is successfully deleted. False on failure. 
  659. */ 
  660. function delete_blog_option( $id, $option ) { 
  661. $id = (int) $id; 
  662.  
  663. if ( empty( $id ) ) 
  664. $id = get_current_blog_id(); 
  665.  
  666. if ( get_current_blog_id() == $id ) 
  667. return delete_option( $option ); 
  668.  
  669. switch_to_blog( $id ); 
  670. $return = delete_option( $option ); 
  671. restore_current_blog(); 
  672.  
  673. return $return; 
  674.  
  675. /** 
  676. * Update an option for a particular blog. 
  677. * 
  678. * @since MU 
  679. * 
  680. * @param int $id The blog id. 
  681. * @param string $option The option key. 
  682. * @param mixed $value The option value. 
  683. * @param mixed $deprecated Not used. 
  684. * @return bool True on success, false on failure. 
  685. */ 
  686. function update_blog_option( $id, $option, $value, $deprecated = null ) { 
  687. $id = (int) $id; 
  688.  
  689. if ( null !== $deprecated ) 
  690. _deprecated_argument( __FUNCTION__, '3.1.0' ); 
  691.  
  692. if ( get_current_blog_id() == $id ) 
  693. return update_option( $option, $value ); 
  694.  
  695. switch_to_blog( $id ); 
  696. $return = update_option( $option, $value ); 
  697. restore_current_blog(); 
  698.  
  699. return $return; 
  700.  
  701. /** 
  702. * Switch the current blog. 
  703. * 
  704. * This function is useful if you need to pull posts, or other information,  
  705. * from other blogs. You can switch back afterwards using restore_current_blog(). 
  706. * 
  707. * Things that aren't switched: 
  708. * - autoloaded options. See #14992 
  709. * - plugins. See #14941 
  710. * 
  711. * @see restore_current_blog() 
  712. * @since MU 
  713. * 
  714. * @global wpdb $wpdb 
  715. * @global int $blog_id 
  716. * @global array $_wp_switched_stack 
  717. * @global bool $switched 
  718. * @global string $table_prefix 
  719. * @global WP_Object_Cache $wp_object_cache 
  720. * 
  721. * @param int $new_blog The id of the blog you want to switch to. Default: current blog 
  722. * @param bool $deprecated Deprecated argument 
  723. * @return true Always returns True. 
  724. */ 
  725. function switch_to_blog( $new_blog, $deprecated = null ) { 
  726. global $wpdb, $wp_roles; 
  727.  
  728. $blog_id = get_current_blog_id(); 
  729. if ( empty( $new_blog ) ) { 
  730. $new_blog = $blog_id; 
  731.  
  732. $GLOBALS['_wp_switched_stack'][] = $blog_id; 
  733.  
  734. /** 
  735. * If we're switching to the same blog id that we're on,  
  736. * set the right vars, do the associated actions, but skip 
  737. * the extra unnecessary work 
  738. */ 
  739. if ( $new_blog == $blog_id ) { 
  740. /** 
  741. * Fires when the blog is switched. 
  742. * 
  743. * @since MU 
  744. * 
  745. * @param int $new_blog New blog ID. 
  746. * @param int $new_blog Blog ID. 
  747. */ 
  748. do_action( 'switch_blog', $new_blog, $new_blog ); 
  749. $GLOBALS['switched'] = true; 
  750. return true; 
  751.  
  752. $wpdb->set_blog_id( $new_blog ); 
  753. $GLOBALS['table_prefix'] = $wpdb->get_blog_prefix(); 
  754. $prev_blog_id = $blog_id; 
  755. $GLOBALS['blog_id'] = $new_blog; 
  756.  
  757. if ( function_exists( 'wp_cache_switch_to_blog' ) ) { 
  758. wp_cache_switch_to_blog( $new_blog ); 
  759. } else { 
  760. global $wp_object_cache; 
  761.  
  762. if ( is_object( $wp_object_cache ) && isset( $wp_object_cache->global_groups ) ) { 
  763. $global_groups = $wp_object_cache->global_groups; 
  764. } else { 
  765. $global_groups = false; 
  766. wp_cache_init(); 
  767.  
  768. if ( function_exists( 'wp_cache_add_global_groups' ) ) { 
  769. if ( is_array( $global_groups ) ) { 
  770. wp_cache_add_global_groups( $global_groups ); 
  771. } else { 
  772. 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' ) ); 
  773. wp_cache_add_non_persistent_groups( array( 'counts', 'plugins' ) ); 
  774.  
  775. if ( did_action( 'init' ) ) { 
  776. $wp_roles = new WP_Roles(); 
  777. $current_user = wp_get_current_user(); 
  778. $current_user->for_blog( $new_blog ); 
  779.  
  780. /** This filter is documented in wp-includes/ms-blogs.php */ 
  781. do_action( 'switch_blog', $new_blog, $prev_blog_id ); 
  782. $GLOBALS['switched'] = true; 
  783.  
  784. return true; 
  785.  
  786. /** 
  787. * Restore the current blog, after calling switch_to_blog() 
  788. * 
  789. * @see switch_to_blog() 
  790. * @since MU 
  791. * 
  792. * @global wpdb $wpdb 
  793. * @global array $_wp_switched_stack 
  794. * @global int $blog_id 
  795. * @global bool $switched 
  796. * @global string $table_prefix 
  797. * @global WP_Object_Cache $wp_object_cache 
  798. * 
  799. * @return bool True on success, false if we're already on the current blog 
  800. */ 
  801. function restore_current_blog() { 
  802. global $wpdb, $wp_roles; 
  803.  
  804. if ( empty( $GLOBALS['_wp_switched_stack'] ) ) { 
  805. return false; 
  806.  
  807. $blog = array_pop( $GLOBALS['_wp_switched_stack'] ); 
  808. $blog_id = get_current_blog_id(); 
  809.  
  810. if ( $blog_id == $blog ) { 
  811. /** This filter is documented in wp-includes/ms-blogs.php */ 
  812. do_action( 'switch_blog', $blog, $blog ); 
  813. // If we still have items in the switched stack, consider ourselves still 'switched' 
  814. $GLOBALS['switched'] = ! empty( $GLOBALS['_wp_switched_stack'] ); 
  815. return true; 
  816.  
  817. $wpdb->set_blog_id( $blog ); 
  818. $prev_blog_id = $blog_id; 
  819. $GLOBALS['blog_id'] = $blog; 
  820. $GLOBALS['table_prefix'] = $wpdb->get_blog_prefix(); 
  821.  
  822. if ( function_exists( 'wp_cache_switch_to_blog' ) ) { 
  823. wp_cache_switch_to_blog( $blog ); 
  824. } else { 
  825. global $wp_object_cache; 
  826.  
  827. if ( is_object( $wp_object_cache ) && isset( $wp_object_cache->global_groups ) ) { 
  828. $global_groups = $wp_object_cache->global_groups; 
  829. } else { 
  830. $global_groups = false; 
  831.  
  832. wp_cache_init(); 
  833.  
  834. if ( function_exists( 'wp_cache_add_global_groups' ) ) { 
  835. if ( is_array( $global_groups ) ) { 
  836. wp_cache_add_global_groups( $global_groups ); 
  837. } else { 
  838. 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' ) ); 
  839. wp_cache_add_non_persistent_groups( array( 'counts', 'plugins' ) ); 
  840.  
  841. if ( did_action( 'init' ) ) { 
  842. $wp_roles = new WP_Roles(); 
  843. $current_user = wp_get_current_user(); 
  844. $current_user->for_blog( $blog ); 
  845.  
  846. /** This filter is documented in wp-includes/ms-blogs.php */ 
  847. do_action( 'switch_blog', $blog, $prev_blog_id ); 
  848.  
  849. // If we still have items in the switched stack, consider ourselves still 'switched' 
  850. $GLOBALS['switched'] = ! empty( $GLOBALS['_wp_switched_stack'] ); 
  851.  
  852. return true; 
  853.  
  854. /** 
  855. * Determines if switch_to_blog() is in effect 
  856. * 
  857. * @since 3.5.0 
  858. * 
  859. * @global array $_wp_switched_stack 
  860. * 
  861. * @return bool True if switched, false otherwise. 
  862. */ 
  863. function ms_is_switched() { 
  864. return ! empty( $GLOBALS['_wp_switched_stack'] ); 
  865.  
  866. /** 
  867. * Check if a particular blog is archived. 
  868. * 
  869. * @since MU 
  870. * 
  871. * @param int $id The blog id 
  872. * @return string Whether the blog is archived or not 
  873. */ 
  874. function is_archived( $id ) { 
  875. return get_blog_status($id, 'archived'); 
  876.  
  877. /** 
  878. * Update the 'archived' status of a particular blog. 
  879. * 
  880. * @since MU 
  881. * 
  882. * @param int $id The blog id 
  883. * @param string $archived The new status 
  884. * @return string $archived 
  885. */ 
  886. function update_archived( $id, $archived ) { 
  887. update_blog_status($id, 'archived', $archived); 
  888. return $archived; 
  889.  
  890. /** 
  891. * Update a blog details field. 
  892. * 
  893. * @since MU 
  894. * 
  895. * @global wpdb $wpdb WordPress database abstraction object. 
  896. * 
  897. * @param int $blog_id BLog ID 
  898. * @param string $pref A field name 
  899. * @param string $value Value for $pref 
  900. * @param null $deprecated 
  901. * @return string|false $value 
  902. */ 
  903. function update_blog_status( $blog_id, $pref, $value, $deprecated = null ) { 
  904. global $wpdb; 
  905.  
  906. if ( null !== $deprecated ) 
  907. _deprecated_argument( __FUNCTION__, '3.1.0' ); 
  908.  
  909. if ( ! in_array( $pref, array( 'site_id', 'domain', 'path', 'registered', 'last_updated', 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id') ) ) 
  910. return $value; 
  911.  
  912. $result = $wpdb->update( $wpdb->blogs, array($pref => $value, 'last_updated' => current_time('mysql', true)), array('blog_id' => $blog_id) ); 
  913.  
  914. if ( false === $result ) 
  915. return false; 
  916.  
  917. refresh_blog_details( $blog_id ); 
  918.  
  919. if ( 'spam' == $pref ) { 
  920. if ( $value == 1 ) { 
  921. /** This filter is documented in wp-includes/ms-blogs.php */ 
  922. do_action( 'make_spam_blog', $blog_id ); 
  923. } else { 
  924. /** This filter is documented in wp-includes/ms-blogs.php */ 
  925. do_action( 'make_ham_blog', $blog_id ); 
  926. } elseif ( 'mature' == $pref ) { 
  927. if ( $value == 1 ) { 
  928. /** This filter is documented in wp-includes/ms-blogs.php */ 
  929. do_action( 'mature_blog', $blog_id ); 
  930. } else { 
  931. /** This filter is documented in wp-includes/ms-blogs.php */ 
  932. do_action( 'unmature_blog', $blog_id ); 
  933. } elseif ( 'archived' == $pref ) { 
  934. if ( $value == 1 ) { 
  935. /** This filter is documented in wp-includes/ms-blogs.php */ 
  936. do_action( 'archive_blog', $blog_id ); 
  937. } else { 
  938. /** This filter is documented in wp-includes/ms-blogs.php */ 
  939. do_action( 'unarchive_blog', $blog_id ); 
  940. } elseif ( 'deleted' == $pref ) { 
  941. if ( $value == 1 ) { 
  942. /** This filter is documented in wp-includes/ms-blogs.php */ 
  943. do_action( 'make_delete_blog', $blog_id ); 
  944. } else { 
  945. /** This filter is documented in wp-includes/ms-blogs.php */ 
  946. do_action( 'make_undelete_blog', $blog_id ); 
  947. } elseif ( 'public' == $pref ) { 
  948. /** 
  949. * Fires after the current blog's 'public' setting is updated. 
  950. * 
  951. * @since MU 
  952. * 
  953. * @param int $blog_id Blog ID. 
  954. * @param string $value The value of blog status. 
  955. */ 
  956. do_action( 'update_blog_public', $blog_id, $value ); // Moved here from update_blog_public(). 
  957.  
  958. return $value; 
  959.  
  960. /** 
  961. * Get a blog details field. 
  962. * 
  963. * @since MU 
  964. * 
  965. * @global wpdb $wpdb WordPress database abstraction object. 
  966. * 
  967. * @param int $id The blog id 
  968. * @param string $pref A field name 
  969. * @return bool|string|null $value 
  970. */ 
  971. function get_blog_status( $id, $pref ) { 
  972. global $wpdb; 
  973.  
  974. $details = get_site( $id ); 
  975. if ( $details ) 
  976. return $details->$pref; 
  977.  
  978. return $wpdb->get_var( $wpdb->prepare("SELECT %s FROM {$wpdb->blogs} WHERE blog_id = %d", $pref, $id) ); 
  979.  
  980. /** 
  981. * Get a list of most recently updated blogs. 
  982. * 
  983. * @since MU 
  984. * 
  985. * @global wpdb $wpdb WordPress database abstraction object. 
  986. * 
  987. * @param mixed $deprecated Not used 
  988. * @param int $start The offset 
  989. * @param int $quantity The maximum number of blogs to retrieve. Default is 40. 
  990. * @return array The list of blogs 
  991. */ 
  992. function get_last_updated( $deprecated = '', $start = 0, $quantity = 40 ) { 
  993. global $wpdb; 
  994.  
  995. if ( ! empty( $deprecated ) ) 
  996. _deprecated_argument( __FUNCTION__, 'MU' ); // never used 
  997.  
  998. 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 ); 
  999.  
  1000. /** 
  1001. * Retrieves a list of networks. 
  1002. * 
  1003. * @since 4.6.0 
  1004. * 
  1005. * @param string|array $args Optional. Array or string of arguments. See WP_Network_Query::parse_query() 
  1006. * for information on accepted arguments. Default empty array. 
  1007. * @return int|array List of networks or number of found networks if `$count` argument is true. 
  1008. */ 
  1009. function get_networks( $args = array() ) { 
  1010. $query = new WP_Network_Query(); 
  1011.  
  1012. return $query->query( $args ); 
  1013.  
  1014. /** 
  1015. * Retrieves network data given a network ID or network object. 
  1016. * 
  1017. * Network data will be cached and returned after being passed through a filter. 
  1018. * If the provided network is empty, the current network global will be used. 
  1019. * 
  1020. * @since 4.6.0 
  1021. * 
  1022. * @global WP_Network $current_site 
  1023. * 
  1024. * @param WP_Network|int|null $network Optional. Network to retrieve. Default is the current network. 
  1025. * @return WP_Network|null The network object or null if not found. 
  1026. */ 
  1027. function get_network( $network = null ) { 
  1028. global $current_site; 
  1029. if ( empty( $network ) && isset( $current_site ) ) { 
  1030. $network = $current_site; 
  1031.  
  1032. if ( $network instanceof WP_Network ) { 
  1033. $_network = $network; 
  1034. } elseif ( is_object( $network ) ) { 
  1035. $_network = new WP_Network( $network ); 
  1036. } else { 
  1037. $_network = WP_Network::get_instance( $network ); 
  1038.  
  1039. if ( ! $_network ) { 
  1040. return null; 
  1041.  
  1042. /** 
  1043. * Fires after a network is retrieved. 
  1044. * 
  1045. * @since 4.6.0 
  1046. * 
  1047. * @param WP_Network $_network Network data. 
  1048. */ 
  1049. $_network = apply_filters( 'get_network', $_network ); 
  1050.  
  1051. return $_network; 
  1052.  
  1053. /** 
  1054. * Removes a network from the object cache. 
  1055. * 
  1056. * @since 4.6.0 
  1057. * 
  1058. * @param int|array $ids Network ID or an array of network IDs to remove from cache. 
  1059. */ 
  1060. function clean_network_cache( $ids ) { 
  1061. foreach ( (array) $ids as $id ) { 
  1062. wp_cache_delete( $id, 'networks' ); 
  1063.  
  1064. /** 
  1065. * Fires immediately after a network has been removed from the object cache. 
  1066. * 
  1067. * @since 4.6.0 
  1068. * 
  1069. * @param int $id Network ID. 
  1070. */ 
  1071. do_action( 'clean_network_cache', $id ); 
  1072.  
  1073. wp_cache_set( 'last_changed', microtime(), 'networks' ); 
  1074.  
  1075. /** 
  1076. * Updates the network cache of given networks. 
  1077. * 
  1078. * Will add the networks in $networks to the cache. If network ID already exists 
  1079. * in the network cache then it will not be updated. The network is added to the 
  1080. * cache using the network group with the key using the ID of the networks. 
  1081. * 
  1082. * @since 4.6.0 
  1083. * 
  1084. * @param array $networks Array of network row objects. 
  1085. */ 
  1086. function update_network_cache( $networks ) { 
  1087. foreach ( (array) $networks as $network ) { 
  1088. wp_cache_add( $network->id, $network, 'networks' ); 
  1089.  
  1090. /** 
  1091. * Adds any networks from the given IDs to the cache that do not already exist in cache. 
  1092. * 
  1093. * @since 4.6.0 
  1094. * @access private 
  1095. * 
  1096. * @see update_network_cache() 
  1097. * @global wpdb $wpdb WordPress database abstraction object. 
  1098. * 
  1099. * @param array $network_ids Array of network IDs. 
  1100. */ 
  1101. function _prime_network_caches( $network_ids ) { 
  1102. global $wpdb; 
  1103.  
  1104. $non_cached_ids = _get_non_cached_ids( $network_ids, 'networks' ); 
  1105. if ( !empty( $non_cached_ids ) ) { 
  1106. $fresh_networks = $wpdb->get_results( sprintf( "SELECT $wpdb->site.* FROM $wpdb->site WHERE id IN (%s)", join( ", ", array_map( 'intval', $non_cached_ids ) ) ) ); 
  1107.  
  1108. update_network_cache( $fresh_networks ); 
  1109.  
  1110. /** 
  1111. * Handler for updating the blog date when a post is published or an already published post is changed. 
  1112. * 
  1113. * @since 3.3.0 
  1114. * 
  1115. * @param string $new_status The new post status 
  1116. * @param string $old_status The old post status 
  1117. * @param object $post Post object 
  1118. */ 
  1119. function _update_blog_date_on_post_publish( $new_status, $old_status, $post ) { 
  1120. $post_type_obj = get_post_type_object( $post->post_type ); 
  1121. if ( ! $post_type_obj || ! $post_type_obj->public ) { 
  1122. return; 
  1123.  
  1124. if ( 'publish' != $new_status && 'publish' != $old_status ) { 
  1125. return; 
  1126.  
  1127. // Post was freshly published, published post was saved, or published post was unpublished. 
  1128.  
  1129. wpmu_update_blogs_date(); 
  1130.  
  1131. /** 
  1132. * Handler for updating the blog date when a published post is deleted. 
  1133. * 
  1134. * @since 3.4.0 
  1135. * 
  1136. * @param int $post_id Post ID 
  1137. */ 
  1138. function _update_blog_date_on_post_delete( $post_id ) { 
  1139. $post = get_post( $post_id ); 
  1140.  
  1141. $post_type_obj = get_post_type_object( $post->post_type ); 
  1142. if ( ! $post_type_obj || ! $post_type_obj->public ) { 
  1143. return; 
  1144.  
  1145. if ( 'publish' != $post->post_status ) { 
  1146. return; 
  1147.  
  1148. wpmu_update_blogs_date(); 
  1149.  
  1150. /** 
  1151. * Handler for updating the blog posts count date when a post is deleted. 
  1152. * 
  1153. * @since 4.0.0 
  1154. * 
  1155. * @param int $post_id Post ID. 
  1156. */ 
  1157. function _update_posts_count_on_delete( $post_id ) { 
  1158. $post = get_post( $post_id ); 
  1159.  
  1160. if ( ! $post || 'publish' !== $post->post_status ) { 
  1161. return; 
  1162.  
  1163. update_posts_count(); 
  1164.  
  1165. /** 
  1166. * Handler for updating the blog posts count date when a post status changes. 
  1167. * 
  1168. * @since 4.0.0 
  1169. * 
  1170. * @param string $new_status The status the post is changing to. 
  1171. * @param string $old_status The status the post is changing from. 
  1172. */ 
  1173. function _update_posts_count_on_transition_post_status( $new_status, $old_status ) { 
  1174. if ( $new_status === $old_status ) { 
  1175. return; 
  1176.  
  1177. if ( 'publish' !== $new_status && 'publish' !== $old_status ) { 
  1178. return; 
  1179.  
  1180. update_posts_count(); 
.