[ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Network API: WP_Network class 4 * 5 * @package WordPress 6 * @subpackage Multisite 7 * @since 4.4.0 8 */ 9 10 /** 11 * Core class used for interacting with a multisite network. 12 * 13 * This class is used during load to populate the `$current_site` global and 14 * setup the current network. 15 * 16 * This class is most useful in WordPress multi-network installations where the 17 * ability to interact with any network of sites is required. 18 * 19 * @since 4.4.0 20 * 21 * @property int $id 22 * @property int $site_id 23 */ 24 class WP_Network { 25 26 /** 27 * Network ID. 28 * 29 * @since 4.4.0 30 * @since 4.6.0 Converted from public to private to explicitly enable more intuitive 31 * access via magic methods. As part of the access change, the type was 32 * also changed from `string` to `int`. 33 * @var int 34 */ 35 private $id; 36 37 /** 38 * Domain of the network. 39 * 40 * @since 4.4.0 41 * @var string 42 */ 43 public $domain = ''; 44 45 /** 46 * Path of the network. 47 * 48 * @since 4.4.0 49 * @var string 50 */ 51 public $path = ''; 52 53 /** 54 * The ID of the network's main site. 55 * 56 * Named "blog" vs. "site" for legacy reasons. A main site is mapped to 57 * the network when the network is created. 58 * 59 * A numeric string, for compatibility reasons. 60 * 61 * @since 4.4.0 62 * @var string 63 */ 64 private $blog_id = '0'; 65 66 /** 67 * Domain used to set cookies for this network. 68 * 69 * @since 4.4.0 70 * @var string 71 */ 72 public $cookie_domain = ''; 73 74 /** 75 * Name of this network. 76 * 77 * Named "site" vs. "network" for legacy reasons. 78 * 79 * @since 4.4.0 80 * @var string 81 */ 82 public $site_name = ''; 83 84 /** 85 * Retrieve a network from the database by its ID. 86 * 87 * @since 4.4.0 88 * 89 * @global wpdb $wpdb WordPress database abstraction object. 90 * 91 * @param int $network_id The ID of the network to retrieve. 92 * @return WP_Network|false The network's object if found. False if not. 93 */ 94 public static function get_instance( $network_id ) { 95 global $wpdb; 96 97 $network_id = (int) $network_id; 98 if ( ! $network_id ) { 99 return false; 100 } 101 102 $_network = wp_cache_get( $network_id, 'networks' ); 103 104 if ( false === $_network ) { 105 $_network = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->site} WHERE id = %d LIMIT 1", $network_id ) ); 106 107 if ( empty( $_network ) || is_wp_error( $_network ) ) { 108 $_network = -1; 109 } 110 111 wp_cache_add( $network_id, $_network, 'networks' ); 112 } 113 114 if ( is_numeric( $_network ) ) { 115 return false; 116 } 117 118 return new WP_Network( $_network ); 119 } 120 121 /** 122 * Create a new WP_Network object. 123 * 124 * Will populate object properties from the object provided and assign other 125 * default properties based on that information. 126 * 127 * @since 4.4.0 128 * 129 * @param WP_Network|object $network A network object. 130 */ 131 public function __construct( $network ) { 132 foreach ( get_object_vars( $network ) as $key => $value ) { 133 $this->$key = $value; 134 } 135 136 $this->_set_site_name(); 137 $this->_set_cookie_domain(); 138 } 139 140 /** 141 * Getter. 142 * 143 * Allows current multisite naming conventions when getting properties. 144 * 145 * @since 4.6.0 146 * 147 * @param string $key Property to get. 148 * @return mixed Value of the property. Null if not available. 149 */ 150 public function __get( $key ) { 151 switch ( $key ) { 152 case 'id': 153 return (int) $this->id; 154 case 'blog_id': 155 return (string) $this->get_main_site_id(); 156 case 'site_id': 157 return $this->get_main_site_id(); 158 } 159 160 return null; 161 } 162 163 /** 164 * Isset-er. 165 * 166 * Allows current multisite naming conventions when checking for properties. 167 * 168 * @since 4.6.0 169 * 170 * @param string $key Property to check if set. 171 * @return bool Whether the property is set. 172 */ 173 public function __isset( $key ) { 174 switch ( $key ) { 175 case 'id': 176 case 'blog_id': 177 case 'site_id': 178 return true; 179 } 180 181 return false; 182 } 183 184 /** 185 * Setter. 186 * 187 * Allows current multisite naming conventions while setting properties. 188 * 189 * @since 4.6.0 190 * 191 * @param string $key Property to set. 192 * @param mixed $value Value to assign to the property. 193 */ 194 public function __set( $key, $value ) { 195 switch ( $key ) { 196 case 'id': 197 $this->id = (int) $value; 198 break; 199 case 'blog_id': 200 case 'site_id': 201 $this->blog_id = (string) $value; 202 break; 203 default: 204 $this->$key = $value; 205 } 206 } 207 208 /** 209 * Returns the main site ID for the network. 210 * 211 * Internal method used by the magic getter for the 'blog_id' and 'site_id' 212 * properties. 213 * 214 * @since 4.9.0 215 * 216 * @return int The ID of the main site. 217 */ 218 private function get_main_site_id() { 219 /** 220 * Filters the main site ID. 221 * 222 * Returning a positive integer will effectively short-circuit the function. 223 * 224 * @since 4.9.0 225 * 226 * @param int|null $main_site_id If a positive integer is returned, it is interpreted as the main site ID. 227 * @param WP_Network $network The network object for which the main site was detected. 228 */ 229 $main_site_id = (int) apply_filters( 'pre_get_main_site_id', null, $this ); 230 if ( 0 < $main_site_id ) { 231 return $main_site_id; 232 } 233 234 if ( 0 < (int) $this->blog_id ) { 235 return (int) $this->blog_id; 236 } 237 238 if ( ( defined( 'DOMAIN_CURRENT_SITE' ) && defined( 'PATH_CURRENT_SITE' ) && DOMAIN_CURRENT_SITE === $this->domain && PATH_CURRENT_SITE === $this->path ) 239 || ( defined( 'SITE_ID_CURRENT_SITE' ) && SITE_ID_CURRENT_SITE == $this->id ) ) { 240 if ( defined( 'BLOG_ID_CURRENT_SITE' ) ) { 241 $this->blog_id = (string) BLOG_ID_CURRENT_SITE; 242 243 return (int) $this->blog_id; 244 } 245 246 if ( defined( 'BLOGID_CURRENT_SITE' ) ) { // Deprecated. 247 $this->blog_id = (string) BLOGID_CURRENT_SITE; 248 249 return (int) $this->blog_id; 250 } 251 } 252 253 $site = get_site(); 254 if ( $site->domain === $this->domain && $site->path === $this->path ) { 255 $main_site_id = (int) $site->id; 256 } else { 257 $cache_key = 'network:' . $this->id . ':main_site'; 258 259 $main_site_id = wp_cache_get( $cache_key, 'site-options' ); 260 if ( false === $main_site_id ) { 261 $_sites = get_sites( 262 array( 263 'fields' => 'ids', 264 'number' => 1, 265 'domain' => $this->domain, 266 'path' => $this->path, 267 'network_id' => $this->id, 268 ) 269 ); 270 $main_site_id = ! empty( $_sites ) ? array_shift( $_sites ) : 0; 271 272 wp_cache_add( $cache_key, $main_site_id, 'site-options' ); 273 } 274 } 275 276 $this->blog_id = (string) $main_site_id; 277 278 return (int) $this->blog_id; 279 } 280 281 /** 282 * Set the site name assigned to the network if one has not been populated. 283 * 284 * @since 4.4.0 285 */ 286 private function _set_site_name() { 287 if ( ! empty( $this->site_name ) ) { 288 return; 289 } 290 291 $default = ucfirst( $this->domain ); 292 $this->site_name = get_network_option( $this->id, 'site_name', $default ); 293 } 294 295 /** 296 * Set the cookie domain based on the network domain if one has 297 * not been populated. 298 * 299 * @todo What if the domain of the network doesn't match the current site? 300 * 301 * @since 4.4.0 302 */ 303 private function _set_cookie_domain() { 304 if ( ! empty( $this->cookie_domain ) ) { 305 return; 306 } 307 308 $this->cookie_domain = $this->domain; 309 if ( 'www.' === substr( $this->cookie_domain, 0, 4 ) ) { 310 $this->cookie_domain = substr( $this->cookie_domain, 4 ); 311 } 312 } 313 314 /** 315 * Retrieve the closest matching network for a domain and path. 316 * 317 * This will not necessarily return an exact match for a domain and path. Instead, it 318 * breaks the domain and path into pieces that are then used to match the closest 319 * possibility from a query. 320 * 321 * The intent of this method is to match a network during bootstrap for a 322 * requested site address. 323 * 324 * @since 4.4.0 325 * 326 * @param string $domain Domain to check. 327 * @param string $path Path to check. 328 * @param int|null $segments Path segments to use. Defaults to null, or the full path. 329 * @return WP_Network|false Network object if successful. False when no network is found. 330 */ 331 public static function get_by_path( $domain = '', $path = '', $segments = null ) { 332 $domains = array( $domain ); 333 $pieces = explode( '.', $domain ); 334 335 /* 336 * It's possible one domain to search is 'com', but it might as well 337 * be 'localhost' or some other locally mapped domain. 338 */ 339 while ( array_shift( $pieces ) ) { 340 if ( ! empty( $pieces ) ) { 341 $domains[] = implode( '.', $pieces ); 342 } 343 } 344 345 /* 346 * If we've gotten to this function during normal execution, there is 347 * more than one network installed. At this point, who knows how many 348 * we have. Attempt to optimize for the situation where networks are 349 * only domains, thus meaning paths never need to be considered. 350 * 351 * This is a very basic optimization; anything further could have 352 * drawbacks depending on the setup, so this is best done per-installation. 353 */ 354 $using_paths = true; 355 if ( wp_using_ext_object_cache() ) { 356 $using_paths = get_networks( 357 array( 358 'number' => 1, 359 'count' => true, 360 'path__not_in' => '/', 361 ) 362 ); 363 } 364 365 $paths = array(); 366 if ( $using_paths ) { 367 $path_segments = array_filter( explode( '/', trim( $path, '/' ) ) ); 368 369 /** 370 * Filters the number of path segments to consider when searching for a site. 371 * 372 * @since 3.9.0 373 * 374 * @param int|null $segments The number of path segments to consider. WordPress by default looks at 375 * one path segment. The function default of null only makes sense when you 376 * know the requested path should match a network. 377 * @param string $domain The requested domain. 378 * @param string $path The requested path, in full. 379 */ 380 $segments = apply_filters( 'network_by_path_segments_count', $segments, $domain, $path ); 381 382 if ( ( null !== $segments ) && count( $path_segments ) > $segments ) { 383 $path_segments = array_slice( $path_segments, 0, $segments ); 384 } 385 386 while ( count( $path_segments ) ) { 387 $paths[] = '/' . implode( '/', $path_segments ) . '/'; 388 array_pop( $path_segments ); 389 } 390 391 $paths[] = '/'; 392 } 393 394 /** 395 * Determine a network by its domain and path. 396 * 397 * This allows one to short-circuit the default logic, perhaps by 398 * replacing it with a routine that is more optimal for your setup. 399 * 400 * Return null to avoid the short-circuit. Return false if no network 401 * can be found at the requested domain and path. Otherwise, return 402 * an object from wp_get_network(). 403 * 404 * @since 3.9.0 405 * 406 * @param null|false|WP_Network $network Network value to return by path. Default null 407 * to continue retrieving the network. 408 * @param string $domain The requested domain. 409 * @param string $path The requested path, in full. 410 * @param int|null $segments The suggested number of paths to consult. 411 * Default null, meaning the entire path was to be consulted. 412 * @param string[] $paths Array of paths to search for, based on `$path` and `$segments`. 413 */ 414 $pre = apply_filters( 'pre_get_network_by_path', null, $domain, $path, $segments, $paths ); 415 if ( null !== $pre ) { 416 return $pre; 417 } 418 419 if ( ! $using_paths ) { 420 $networks = get_networks( 421 array( 422 'number' => 1, 423 'orderby' => array( 424 'domain_length' => 'DESC', 425 ), 426 'domain__in' => $domains, 427 ) 428 ); 429 430 if ( ! empty( $networks ) ) { 431 return array_shift( $networks ); 432 } 433 434 return false; 435 } 436 437 $networks = get_networks( 438 array( 439 'orderby' => array( 440 'domain_length' => 'DESC', 441 'path_length' => 'DESC', 442 ), 443 'domain__in' => $domains, 444 'path__in' => $paths, 445 ) 446 ); 447 448 /* 449 * Domains are sorted by length of domain, then by length of path. 450 * The domain must match for the path to be considered. Otherwise, 451 * a network with the path of / will suffice. 452 */ 453 $found = false; 454 foreach ( $networks as $network ) { 455 if ( ( $network->domain === $domain ) || ( "www.{$network->domain}" === $domain ) ) { 456 if ( in_array( $network->path, $paths, true ) ) { 457 $found = true; 458 break; 459 } 460 } 461 if ( '/' === $network->path ) { 462 $found = true; 463 break; 464 } 465 } 466 467 if ( true === $found ) { 468 return $network; 469 } 470 471 return false; 472 } 473 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Nov 21 01:00:03 2024 | Cross-referenced by PHPXref 0.7.1 |