PageRenderTime 41ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://gitlab.com/Fullerton/PolitePressCore
PHP | 408 lines | 157 code | 41 blank | 210 comment | 26 complexity | 83a781eb688f1935fa29926642497bcf 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. $domains = array( $domain );
  245. $pieces = explode( '.', $domain );
  246. /*
  247. * It's possible one domain to search is 'com', but it might as well
  248. * be 'localhost' or some other locally mapped domain.
  249. */
  250. while ( array_shift( $pieces ) ) {
  251. if ( ! empty( $pieces ) ) {
  252. $domains[] = implode( '.', $pieces );
  253. }
  254. }
  255. /*
  256. * If we've gotten to this function during normal execution, there is
  257. * more than one network installed. At this point, who knows how many
  258. * we have. Attempt to optimize for the situation where networks are
  259. * only domains, thus meaning paths never need to be considered.
  260. *
  261. * This is a very basic optimization; anything further could have
  262. * drawbacks depending on the setup, so this is best done per-install.
  263. */
  264. $using_paths = true;
  265. if ( wp_using_ext_object_cache() ) {
  266. $using_paths = wp_cache_get( 'networks_have_paths', 'site-options' );
  267. if ( false === $using_paths ) {
  268. $using_paths = get_networks( array(
  269. 'number' => 1,
  270. 'count' => true,
  271. 'path__not_in' => '/',
  272. ) );
  273. wp_cache_add( 'networks_have_paths', $using_paths, 'site-options' );
  274. }
  275. }
  276. $paths = array();
  277. if ( $using_paths ) {
  278. $path_segments = array_filter( explode( '/', trim( $path, '/' ) ) );
  279. /**
  280. * Filters the number of path segments to consider when searching for a site.
  281. *
  282. * @since 3.9.0
  283. *
  284. * @param int|null $segments The number of path segments to consider. WordPress by default looks at
  285. * one path segment. The function default of null only makes sense when you
  286. * know the requested path should match a network.
  287. * @param string $domain The requested domain.
  288. * @param string $path The requested path, in full.
  289. */
  290. $segments = apply_filters( 'network_by_path_segments_count', $segments, $domain, $path );
  291. if ( ( null !== $segments ) && count( $path_segments ) > $segments ) {
  292. $path_segments = array_slice( $path_segments, 0, $segments );
  293. }
  294. while ( count( $path_segments ) ) {
  295. $paths[] = '/' . implode( '/', $path_segments ) . '/';
  296. array_pop( $path_segments );
  297. }
  298. $paths[] = '/';
  299. }
  300. /**
  301. * Determine a network by its domain and path.
  302. *
  303. * This allows one to short-circuit the default logic, perhaps by
  304. * replacing it with a routine that is more optimal for your setup.
  305. *
  306. * Return null to avoid the short-circuit. Return false if no network
  307. * can be found at the requested domain and path. Otherwise, return
  308. * an object from wp_get_network().
  309. *
  310. * @since 3.9.0
  311. *
  312. * @param null|bool|object $network Network value to return by path.
  313. * @param string $domain The requested domain.
  314. * @param string $path The requested path, in full.
  315. * @param int|null $segments The suggested number of paths to consult.
  316. * Default null, meaning the entire path was to be consulted.
  317. * @param array $paths The paths to search for, based on $path and $segments.
  318. */
  319. $pre = apply_filters( 'pre_get_network_by_path', null, $domain, $path, $segments, $paths );
  320. if ( null !== $pre ) {
  321. return $pre;
  322. }
  323. if ( ! $using_paths ) {
  324. $networks = get_networks( array(
  325. 'number' => 1,
  326. 'orderby' => array(
  327. 'domain_length' => 'DESC',
  328. ),
  329. 'domain__in' => $domains,
  330. ) );
  331. if ( ! empty( $networks ) ) {
  332. return array_shift( $networks );
  333. }
  334. return false;
  335. }
  336. $networks = get_networks( array(
  337. 'orderby' => array(
  338. 'domain_length' => 'DESC',
  339. 'path_length' => 'DESC',
  340. ),
  341. 'domain__in' => $domains,
  342. 'path__in' => $paths,
  343. ) );
  344. /*
  345. * Domains are sorted by length of domain, then by length of path.
  346. * The domain must match for the path to be considered. Otherwise,
  347. * a network with the path of / will suffice.
  348. */
  349. $found = false;
  350. foreach ( $networks as $network ) {
  351. if ( ( $network->domain === $domain ) || ( "www.{$network->domain}" === $domain ) ) {
  352. if ( in_array( $network->path, $paths, true ) ) {
  353. $found = true;
  354. break;
  355. }
  356. }
  357. if ( $network->path === '/' ) {
  358. $found = true;
  359. break;
  360. }
  361. }
  362. if ( true === $found ) {
  363. return $network;
  364. }
  365. return false;
  366. }
  367. }