You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1273 lines
36 KiB

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