WP_Network

Core class used for interacting with a multisite network.

Defined (1)

The class is defined in the following location(s).

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