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

/wp-includes/class-wp-network.php

https://gitlab.com/hop23typhu/bryepoxy
PHP | 410 lines | 154 code | 44 blank | 212 comment | 28 complexity | cc3ed1d2e2c47fb9c4efa84768c2da75 MD5 | raw file
  1. <?php
  2. /**
  3. * Network API: WP_Network class
  4. *
  5. * @package WordPress
  6. * @subpackage Multisite
  7. * @since 4.4.0
  8. */
  9. /**
  10. * Core class used for interacting with a multisite network.
  11. *
  12. * This class is used during load to populate the `$current_site` global and
  13. * setup the current network.
  14. *
  15. * This class is most useful in WordPress multi-network installations where the
  16. * ability to interact with any network of sites is required.
  17. *
  18. * @since 4.4.0
  19. *
  20. * @property int $id
  21. * @property int $site_id
  22. */
  23. class WP_Network {
  24. /**
  25. * Network ID.
  26. *
  27. * @since 4.4.0
  28. * @since 4.6.0 Converted from public to private to explicitly enable more intuitive
  29. * access via magic methods. As part of the access change, the type was
  30. * also changed from `string` to `int`.
  31. * @access private
  32. * @var int
  33. */
  34. private $id;
  35. /**
  36. * Domain of the network.
  37. *
  38. * @since 4.4.0
  39. * @access public
  40. * @var string
  41. */
  42. public $domain = '';
  43. /**
  44. * Path of the network.
  45. *
  46. * @since 4.4.0
  47. * @access public
  48. * @var string
  49. */
  50. public $path = '';
  51. /**
  52. * The ID of the network's main site.
  53. *
  54. * Named "blog" vs. "site" for legacy reasons. A main site is mapped to
  55. * the network when the network is created.
  56. *
  57. * A numeric string, for compatibility reasons.
  58. *
  59. * @since 4.4.0
  60. * @access private
  61. * @var string
  62. */
  63. private $blog_id = '0';
  64. /**
  65. * Domain used to set cookies for this network.
  66. *
  67. * @since 4.4.0
  68. * @access public
  69. * @var string
  70. */
  71. public $cookie_domain = '';
  72. /**
  73. * Name of this network.
  74. *
  75. * Named "site" vs. "network" for legacy reasons.
  76. *
  77. * @since 4.4.0
  78. * @access public
  79. * @var string
  80. */
  81. public $site_name = '';
  82. /**
  83. * Retrieve a network from the database by its ID.
  84. *
  85. * @since 4.4.0
  86. * @access public
  87. *
  88. * @global wpdb $wpdb WordPress database abstraction object.
  89. *
  90. * @param int $network_id The ID of the network to retrieve.
  91. * @return WP_Network|bool The network's object if found. False if not.
  92. */
  93. public static function get_instance( $network_id ) {
  94. global $wpdb;
  95. $network_id = (int) $network_id;
  96. if ( ! $network_id ) {
  97. return false;
  98. }
  99. $_network = wp_cache_get( $network_id, 'networks' );
  100. if ( ! $_network ) {
  101. $_network = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->site} WHERE id = %d LIMIT 1", $network_id ) );
  102. if ( empty( $_network ) || is_wp_error( $_network ) ) {
  103. return false;
  104. }
  105. wp_cache_add( $network_id, $_network, 'networks' );
  106. }
  107. return new WP_Network( $_network );
  108. }
  109. /**
  110. * Create a new WP_Network object.
  111. *
  112. * Will populate object properties from the object provided and assign other
  113. * default properties based on that information.
  114. *
  115. * @since 4.4.0
  116. * @access public
  117. *
  118. * @param WP_Network|object $network A network object.
  119. */
  120. public function __construct( $network ) {
  121. foreach( get_object_vars( $network ) as $key => $value ) {
  122. $this->$key = $value;
  123. }
  124. $this->_set_site_name();
  125. $this->_set_cookie_domain();
  126. }
  127. /**
  128. * Getter.
  129. *
  130. * Allows current multisite naming conventions when getting properties.
  131. *
  132. * @since 4.6.0
  133. * @access public
  134. *
  135. * @param string $key Property to get.
  136. * @return mixed Value of the property. Null if not available.
  137. */
  138. public function __get( $key ) {
  139. switch ( $key ) {
  140. case 'id';
  141. return (int) $this->id;
  142. case 'blog_id':
  143. return $this->blog_id;
  144. case 'site_id':
  145. return (int) $this->blog_id;
  146. }
  147. return null;
  148. }
  149. /**
  150. * Isset-er.
  151. *
  152. * Allows current multisite naming conventions when checking for properties.
  153. *
  154. * @since 4.6.0
  155. * @access public
  156. *
  157. * @param string $key Property to check if set.
  158. * @return bool Whether the property is set.
  159. */
  160. public function __isset( $key ) {
  161. switch ( $key ) {
  162. case 'id':
  163. case 'blog_id':
  164. case 'site_id':
  165. return true;
  166. }
  167. return false;
  168. }
  169. /**
  170. * Setter.
  171. *
  172. * Allows current multisite naming conventions while setting properties.
  173. *
  174. * @since 4.6.0
  175. * @access public
  176. *
  177. * @param string $key Property to set.
  178. * @param mixed $value Value to assign to the property.
  179. */
  180. public function __set( $key, $value ) {
  181. switch ( $key ) {
  182. case 'id':
  183. $this->id = (int) $value;
  184. break;
  185. case 'blog_id':
  186. case 'site_id':
  187. $this->blog_id = (string) $value;
  188. break;
  189. default:
  190. $this->$key = $value;
  191. }
  192. }
  193. /**
  194. * Set the site name assigned to the network if one has not been populated.
  195. *
  196. * @since 4.4.0
  197. * @access private
  198. */
  199. private function _set_site_name() {
  200. if ( ! empty( $this->site_name ) ) {
  201. return;
  202. }
  203. $default = ucfirst( $this->domain );
  204. $this->site_name = get_network_option( $this->id, 'site_name', $default );
  205. }
  206. /**
  207. * Set the cookie domain based on the network domain if one has
  208. * not been populated.
  209. *
  210. * @todo What if the domain of the network doesn't match the current site?
  211. *
  212. * @since 4.4.0
  213. * @access private
  214. */
  215. private function _set_cookie_domain() {
  216. if ( ! empty( $this->cookie_domain ) ) {
  217. return;
  218. }
  219. $this->cookie_domain = $this->domain;
  220. if ( 'www.' === substr( $this->cookie_domain, 0, 4 ) ) {
  221. $this->cookie_domain = substr( $this->cookie_domain, 4 );
  222. }
  223. }
  224. /**
  225. * Retrieve the closest matching network for a domain and path.
  226. *
  227. * This will not necessarily return an exact match for a domain and path. Instead, it
  228. * breaks the domain and path into pieces that are then used to match the closest
  229. * possibility from a query.
  230. *
  231. * The intent of this method is to match a network during bootstrap for a
  232. * requested site address.
  233. *
  234. * @since 4.4.0
  235. * @access public
  236. * @static
  237. *
  238. * @param string $domain Domain to check.
  239. * @param string $path Path to check.
  240. * @param int|null $segments Path segments to use. Defaults to null, or the full path.
  241. * @return WP_Network|bool Network object if successful. False when no network is found.
  242. */
  243. public static function get_by_path( $domain = '', $path = '', $segments = null ) {
  244. global $wpdb;
  245. $domains = array( $domain );
  246. $pieces = explode( '.', $domain );
  247. /*
  248. * It's possible one domain to search is 'com', but it might as well
  249. * be 'localhost' or some other locally mapped domain.
  250. */
  251. while ( array_shift( $pieces ) ) {
  252. if ( ! empty( $pieces ) ) {
  253. $domains[] = implode( '.', $pieces );
  254. }
  255. }
  256. /*
  257. * If we've gotten to this function during normal execution, there is
  258. * more than one network installed. At this point, who knows how many
  259. * we have. Attempt to optimize for the situation where networks are
  260. * only domains, thus meaning paths never need to be considered.
  261. *
  262. * This is a very basic optimization; anything further could have
  263. * drawbacks depending on the setup, so this is best done per-install.
  264. */
  265. $using_paths = true;
  266. if ( wp_using_ext_object_cache() ) {
  267. $using_paths = wp_cache_get( 'networks_have_paths', 'site-options' );
  268. if ( false === $using_paths ) {
  269. $using_paths = (int) $wpdb->get_var( "SELECT id FROM {$wpdb->site} WHERE path <> '/' LIMIT 1" );
  270. wp_cache_add( 'networks_have_paths', $using_paths, 'site-options' );
  271. }
  272. }
  273. $paths = array();
  274. if ( $using_paths ) {
  275. $path_segments = array_filter( explode( '/', trim( $path, '/' ) ) );
  276. /**
  277. * Filters the number of path segments to consider when searching for a site.
  278. *
  279. * @since 3.9.0
  280. *
  281. * @param int|null $segments The number of path segments to consider. WordPress by default looks at
  282. * one path segment. The function default of null only makes sense when you
  283. * know the requested path should match a network.
  284. * @param string $domain The requested domain.
  285. * @param string $path The requested path, in full.
  286. */
  287. $segments = apply_filters( 'network_by_path_segments_count', $segments, $domain, $path );
  288. if ( ( null !== $segments ) && count( $path_segments ) > $segments ) {
  289. $path_segments = array_slice( $path_segments, 0, $segments );
  290. }
  291. while ( count( $path_segments ) ) {
  292. $paths[] = '/' . implode( '/', $path_segments ) . '/';
  293. array_pop( $path_segments );
  294. }
  295. $paths[] = '/';
  296. }
  297. /**
  298. * Determine a network by its domain and path.
  299. *
  300. * This allows one to short-circuit the default logic, perhaps by
  301. * replacing it with a routine that is more optimal for your setup.
  302. *
  303. * Return null to avoid the short-circuit. Return false if no network
  304. * can be found at the requested domain and path. Otherwise, return
  305. * an object from wp_get_network().
  306. *
  307. * @since 3.9.0
  308. *
  309. * @param null|bool|object $network Network value to return by path.
  310. * @param string $domain The requested domain.
  311. * @param string $path The requested path, in full.
  312. * @param int|null $segments The suggested number of paths to consult.
  313. * Default null, meaning the entire path was to be consulted.
  314. * @param array $paths The paths to search for, based on $path and $segments.
  315. */
  316. $pre = apply_filters( 'pre_get_network_by_path', null, $domain, $path, $segments, $paths );
  317. if ( null !== $pre ) {
  318. return $pre;
  319. }
  320. // @todo Consider additional optimization routes, perhaps as an opt-in for plugins.
  321. // We already have paths covered. What about how far domains should be drilled down (including www)?
  322. $search_domains = "'" . implode( "', '", $wpdb->_escape( $domains ) ) . "'";
  323. if ( ! $using_paths ) {
  324. $network = $wpdb->get_row( "
  325. SELECT * FROM {$wpdb->site}
  326. WHERE domain IN ({$search_domains})
  327. ORDER BY CHAR_LENGTH(domain)
  328. DESC LIMIT 1
  329. " );
  330. if ( ! empty( $network ) && ! is_wp_error( $network ) ) {
  331. return new WP_Network( $network );
  332. }
  333. return false;
  334. } else {
  335. $search_paths = "'" . implode( "', '", $wpdb->_escape( $paths ) ) . "'";
  336. $networks = $wpdb->get_results( "
  337. SELECT * FROM {$wpdb->site}
  338. WHERE domain IN ({$search_domains})
  339. AND path IN ({$search_paths})
  340. ORDER BY CHAR_LENGTH(domain) DESC, CHAR_LENGTH(path) DESC
  341. " );
  342. }
  343. /*
  344. * Domains are sorted by length of domain, then by length of path.
  345. * The domain must match for the path to be considered. Otherwise,
  346. * a network with the path of / will suffice.
  347. */
  348. $found = false;
  349. foreach ( $networks as $network ) {
  350. if ( ( $network->domain === $domain ) || ( "www.{$network->domain}" === $domain ) ) {
  351. if ( in_array( $network->path, $paths, true ) ) {
  352. $found = true;
  353. break;
  354. }
  355. }
  356. if ( $network->path === '/' ) {
  357. $found = true;
  358. break;
  359. }
  360. }
  361. if ( true === $found ) {
  362. return new WP_Network( $network );
  363. }
  364. return false;
  365. }
  366. }