Ticket #31985: 31985.3.diff
File 31985.3.diff, 41.3 KB (added by , 10 years ago) |
---|
-
src/wp-includes/class-wp-network.php
1 <?php 2 3 /** 4 * Main network class 5 * 6 * This class contains the values and functional methods for interacting with 7 * a network of WordPress sites. Traditionally used for multisite, this class 8 * is used by the $current_site global to setup the current network. 9 * 10 * This class is most useful in WordPress multi-network installations where the 11 * ability to interact with any network of sites is required. 12 * 13 * @since 4.3.0 14 */ 15 class WP_Network { 16 17 /** 18 * Unique numerical ID. 19 * 20 * @since 4.3.0 21 * 22 * @var int 23 */ 24 public $id = 0; 25 26 /** 27 * Domain of this network. 28 * 29 * @since 4.3.0 30 * 31 * @var string 32 */ 33 public $domain = ''; 34 35 /** 36 * Path of this network 37 * 38 * @since 4.3.0 39 * 40 * @var string 41 */ 42 public $path = ''; 43 44 /** 45 * The ID of the network's main site. 46 * 47 * Named "blog" vs. "site" for legacy reasons. This site is 48 * mapped to the network on network creation. 49 * 50 * @since 4.3.0 51 * 52 * @var int 53 */ 54 public $blog_id = 0; 55 56 /** 57 * Domain used to set cookies for this network. 58 * 59 * @since 4.3.0 60 * 61 * @var int 62 */ 63 public $cookie_domain = ''; 64 65 /** 66 * Array of core options for this network. 67 * 68 * @since 4.3.0 69 * 70 * @var array 71 */ 72 public $core_options = array(); 73 74 /** 75 * Name of this network. 76 * 77 * Named "site" vs. "network" for legacy reasons. 78 * 79 * @since 4.3.0 80 * 81 * @var string 82 */ 83 public $site_name = ''; 84 85 /** 86 * Create a new WP_Network object. 87 * 88 * Will populate all relevant data if a network ID or object is passed. 89 * 90 * @since 4.3.0 91 * 92 * @param mixed $network stdClass object or network ID 93 * @return WP_Network|null 94 */ 95 public function __construct( $network = false ) { 96 // Bail if not populating from an existing network 97 if ( empty( $network ) ) { 98 return; 99 } 100 101 // Get the network ID. 102 if ( is_object( $network ) && isset( $network->id ) ) { 103 $network_id = $network->id; 104 } elseif ( is_numeric( $network ) ) { 105 $network_id = (int) $network; 106 } else { 107 return; 108 } 109 110 // Populate network object and return it 111 if ( ! empty( $network_id ) ) { 112 $this->populate( $network_id ); 113 return $this; 114 } 115 116 return; 117 } 118 119 /** 120 * Fill the properties of the network object. 121 * 122 * @since 4.3.0 123 * 124 * @param int $network_id ID of the network. 125 * @return bool False if no network is available to update. True otherwise. 126 */ 127 public function populate( $network_id = 0 ) { 128 // Query for the network by ID. 129 $network = self::get_by_id( $network_id ); 130 131 // Bail if no matching network exists. 132 if ( false === $network ) { 133 return false; 134 } 135 136 // Set the main data. 137 $this->set_main_data( $network ); 138 139 // Set supplemental data based on the needs of multisite. 140 $this->set_cookie_domain(); 141 $this->set_core_options(); 142 $this->set_site_name(); 143 144 return true; 145 } 146 147 /** 148 * Set the network ID, domain, and path properties. 149 * 150 * @since 4.3.0 151 */ 152 private function set_main_data( $network ) { 153 $this->id = $network->id; 154 $this->domain = $network->domain; 155 $this->path = $network->path; 156 } 157 158 /** 159 * Set the cookie domain, based on the network domain. 160 * 161 * @todo What if the domain of the network doesn't match the current site? 162 * 163 * @since 4.3.0 164 */ 165 private function set_cookie_domain() { 166 $this->cookie_domain = $this->domain; 167 if ( 'www.' === substr( $this->cookie_domain, 0, 4 ) ) { 168 $this->cookie_domain = substr( $this->cookie_domain, 4 ); 169 } 170 } 171 172 /** 173 * Set the core options for this network object. 174 * 175 * @since 4.3.0 176 */ 177 private function set_core_options() { 178 $this->core_options = self::get_core_options( $this->id ); 179 } 180 181 /** 182 * Set the name for this network's object. 183 * 184 * @todo What if the domain of the network doesn't match the current site? 185 * 186 * @since 4.3.0 187 */ 188 private function set_site_name() { 189 // Attempt to use core option 190 if ( ! empty( $this->core_options['site_name'] ) ) { 191 $this->site_name = $this->core_options['site_name']; 192 193 // Fallback to domain 194 } else { 195 $this->site_name = ucfirst( $this->domain ); 196 } 197 } 198 199 /** 200 * Retrieve a network from the database by its ID. 201 * 202 * @since 4.3.0 203 * 204 * @global wpdb $wpdb 205 * 206 * @param int $network_id The ID of the network to retrieve. 207 * 208 * @return bool|object 209 */ 210 public static function get_by_id( $network_id = 0 ) { 211 global $wpdb; 212 213 // Check cache 214 $network = wp_cache_get( $network_id, 'networks' ); 215 216 // Cache miss 217 if ( false === $network ) { 218 // Query for network data 219 $network = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->site} WHERE id = %d", $network_id ) ); 220 221 // Bail if network cannot be found 222 if ( empty( $network ) || is_wp_error( $network ) ) { 223 $network = false; 224 } 225 226 // Add network to cache 227 wp_cache_add( $network_id, $network, 'networks' ); 228 } 229 230 // Return the network 231 return $network; 232 } 233 234 /** 235 * Retrieve a network by its domain and path. 236 * 237 * @since 4.3.0 238 * 239 * @param string $domain Domain to check. 240 * @param string $path Path to check. 241 * @param int|null $segments Path segments to use. Defaults to null, or the full path. 242 * 243 * @return object|bool Network object if successful. False when no network is found. 244 */ 245 public static function get_by_path( $domain = '', $path = '', $segments = null ) { 246 global $wpdb; 247 248 $domains = array( $domain ); 249 $pieces = explode( '.', $domain ); 250 251 /* 252 * It's possible one domain to search is 'com', but it might as well 253 * be 'localhost' or some other locally mapped domain. 254 */ 255 while ( array_shift( $pieces ) ) { 256 if ( ! empty( $pieces ) ) { 257 $domains[] = implode( '.', $pieces ); 258 } 259 } 260 261 /* 262 * If we've gotten to this function during normal execution, there is 263 * more than one network installed. At this point, who knows how many 264 * we have. Attempt to optimize for the situation where networks are 265 * only domains, thus meaning paths never need to be considered. 266 * 267 * This is a very basic optimization; anything further could have 268 * drawbacks depending on the setup, so this is best done per-install. 269 */ 270 $using_paths = true; 271 if ( wp_using_ext_object_cache() ) { 272 $using_paths = wp_cache_get( 'networks_have_paths', 'site-options' ); 273 if ( false === $using_paths ) { 274 $using_paths = (bool) $wpdb->get_var( "SELECT id FROM {$wpdb->site} WHERE path <> '/' LIMIT 1" ); 275 wp_cache_add( 'networks_have_paths', (int) $using_paths, 'site-options' ); 276 } 277 } 278 279 $paths = array(); 280 if ( true === $using_paths ) { 281 $path_segments = array_filter( explode( '/', trim( $path, '/' ) ) ); 282 283 /** 284 * Filter the number of path segments to consider when searching for a site. 285 * 286 * @since 3.9.0 287 * 288 * @param int|null $segments The number of path segments to consider. WordPress by default looks at 289 * one path segment. The function default of null only makes sense when you 290 * know the requested path should match a network. 291 * @param string $domain The requested domain. 292 * @param string $path The requested path, in full. 293 */ 294 $segments = apply_filters( 'network_by_path_segments_count', $segments, $domain, $path ); 295 296 if ( ( null !== $segments ) && count( $path_segments ) > $segments ) { 297 $path_segments = array_slice( $path_segments, 0, $segments ); 298 } 299 300 while ( count( $path_segments ) ) { 301 $paths[] = '/' . implode( '/', $path_segments ) . '/'; 302 array_pop( $path_segments ); 303 } 304 305 $paths[] = '/'; 306 } 307 308 /** 309 * Determine a network by its domain and path. 310 * 311 * This allows one to short-circuit the default logic, perhaps by 312 * replacing it with a routine that is more optimal for your setup. 313 * 314 * Return null to avoid the short-circuit. Return false if no network 315 * can be found at the requested domain and path. Otherwise, return 316 * an object from wp_get_network(). 317 * 318 * @since 3.9.0 319 * 320 * @param null|bool|object $network Network value to return by path. 321 * @param string $domain The requested domain. 322 * @param string $path The requested path, in full. 323 * @param int|null $segments The suggested number of paths to consult. 324 * Default null, meaning the entire path was to be consulted. 325 * @param array $paths The paths to search for, based on $path and $segments. 326 */ 327 $pre = apply_filters( 'pre_get_network_by_path', null, $domain, $path, $segments, $paths ); 328 if ( null !== $pre ) { 329 return $pre; 330 } 331 332 // @todo Consider additional optimization routes, perhaps as an opt-in for plugins. 333 // We already have paths covered. What about how far domains should be drilled down (including www)? 334 335 $search_domains = "'" . implode( "', '", $wpdb->_escape( $domains ) ) . "'"; 336 337 if ( false === $using_paths ) { 338 $network = $wpdb->get_row( "SELECT * FROM {$wpdb->site} 339 WHERE domain IN ({$search_domains}) 340 ORDER BY CHAR_LENGTH(domain) 341 DESC LIMIT 1" ); 342 343 if ( ! empty( $network ) && ! is_wp_error( $network ) ) { 344 return new WP_Network( $network->id ); 345 } 346 347 return false; 348 349 } else { 350 $search_paths = "'" . implode( "', '", $wpdb->_escape( $paths ) ) . "'"; 351 $networks = $wpdb->get_results( "SELECT * FROM {$wpdb->site} 352 WHERE domain IN ({$search_domains}) 353 AND path IN ({$search_paths}) 354 ORDER BY CHAR_LENGTH(domain) DESC, CHAR_LENGTH(path) DESC" ); 355 } 356 357 /* 358 * Domains are sorted by length of domain, then by length of path. 359 * The domain must match for the path to be considered. Otherwise, 360 * a network with the path of / will suffice. 361 */ 362 $found = false; 363 foreach ( $networks as $network ) { 364 if ( ( $network->domain === $domain ) || ( "www.{$network->domain}" === $domain ) ) { 365 if ( in_array( $network->path, $paths, true ) ) { 366 $found = true; 367 break; 368 } 369 } 370 if ( $network->path === '/' ) { 371 $found = true; 372 break; 373 } 374 } 375 376 if ( true === $found ) { 377 return new WP_Network( $network->id ); 378 } 379 380 return false; 381 } 382 383 /** 384 * Get the set of core options for the network from the database. 385 * 386 * @since 4.3.0 387 * 388 * @param int $network_id 389 * 390 * @return array 391 */ 392 public static function get_core_options( $network_id = 0 ) { 393 global $wpdb; 394 395 // Setup core options query 396 $meta_keys = self::get_core_option_keys(); 397 $core_options_in = "'" . implode( "', '", $meta_keys ) . "'"; 398 $sql = $wpdb->prepare( "SELECT meta_key, meta_value 399 FROM {$wpdb->sitemeta} 400 WHERE meta_key IN ({$core_options_in}) 401 AND site_id = %d", $network_id ); 402 403 // Query for core network options 404 $options = $wpdb->get_results( $sql ); 405 406 // Bail if no options found 407 if ( empty( $options ) || is_wp_error( $options ) ) { 408 return array(); 409 } 410 411 // Setup return value array 412 $retval = array(); 413 414 // Loop through options and add them to the object cache 415 foreach ( $options as $option ) { 416 417 // Setup option values to cache 418 $key = $option->meta_key; 419 $cache_key = "{$network_id}:$key"; 420 $option->meta_value = maybe_unserialize( $option->meta_value ); 421 422 // Cache the option value 423 wp_cache_set( $cache_key, $option->meta_value, 'site-options' ); 424 425 // Add option to array 426 $retval[ $option->meta_key ] = $option->meta_value; 427 } 428 429 // Return the options 430 return $retval; 431 } 432 433 /* 434 * Provide a list of core option keys used for network metadata. 435 * 436 * @since 4.3.0 437 * 438 * @return array 439 */ 440 public static function get_core_option_keys() { 441 return array( 442 'site_name', 443 'siteurl', 444 'active_sitewide_plugins', 445 '_site_transient_timeout_theme_roots', 446 '_site_transient_theme_roots', 447 'site_admins', 448 'can_compress_scripts', 449 'global_terms_enabled', 450 'ms_files_rewriting' 451 ); 452 } 453 454 /** 455 * Get all active network-wide plugins for this network. 456 * 457 * @since 4.3.0 458 * 459 * @param int $network_id 460 * @return array 461 */ 462 public static function get_active_network_plugins( $network_id = 0 ) { 463 $network_options = self::get_core_options( $network_id ); 464 465 if ( empty( $network_options['active_sitewide_plugins'] ) ) { 466 return array(); 467 } 468 $active_plugins = $network_options['active_sitewide_plugins']; 469 470 // Setup the plugins array 471 $plugins = array(); 472 $active_plugins = array_keys( $active_plugins ); 473 474 // Sort plugins array 475 sort( $active_plugins ); 476 477 foreach ( $active_plugins as $plugin ) { 478 if ( self::validate_network_plugin( $plugin ) ) { 479 $plugins[] = WP_PLUGIN_DIR . '/' . $plugin; 480 } 481 } 482 483 return $plugins; 484 } 485 486 /** 487 * Ensure a single network-wide plugin is valid. 488 * 489 * @since 4.3.0 490 * 491 * @param string $plugin 492 * 493 * @return bool True if the plugin specified is valid. False if it is not. 494 */ 495 private static function validate_network_plugin( $plugin = '' ) { 496 497 // $plugin must validate as file 498 if ( ! validate_file( $plugin ) ) { 499 return false; 500 } 501 502 // $plugin must end with '.php' 503 if ( '.php' !== substr( $plugin, -4 ) ) { 504 return false; 505 } 506 507 // $plugin must exist 508 if ( ! file_exists( WP_PLUGIN_DIR . '/' . $plugin ) ) { 509 return false; 510 } 511 512 return true; 513 } 514 515 public static function add( $domain = '', $path = '' ) { 516 517 } 518 519 /** 520 * Update a networks domain & path based on its ID. 521 * 522 * @since 4.3.0 523 * 524 * @global wpdb $wpdb 525 * 526 * @param int $network_id Existing network ID. 527 * @param string $domain New network domain. 528 * @param string $path New network path. 529 * 530 * @return mixed False if network not found. Results of query if updated. 531 */ 532 public static function update( $network_id = 0, $domain = '', $path = '' ) { 533 global $wpdb; 534 535 // Does network exist 536 $network = self::get_by_id( $network_id ); 537 538 // Bail if no network to update 539 if ( false === $network ) { 540 return false; 541 } 542 543 // Set the domain 544 if ( ! empty( $domain ) ) { 545 $network->domain = $domain; 546 } 547 548 // Set the path 549 if ( ! empty( $path ) ) { 550 $network->path = $path; 551 } 552 553 // Query for network data 554 $sql = $wpdb->prepare( "UPDATE {$wpdb->site} SET domain = %s, path = %s WHERE id = %d", $network->domain, $network->path, $network->id ); 555 $network = $wpdb->query( $sql ); 556 557 // Bail if network cannot be found 558 if ( empty( $network ) || is_wp_error( $network ) ) { 559 return false; 560 } 561 562 // Return results of WPDB::query() 563 return $network; 564 } 565 566 public static function delete( $network_id = 0 ) { 567 global $wpdb; 568 569 // Does network exist 570 $network = self::get_by_id( $network_id ); 571 572 // Bail if no network to delete 573 if ( false === $network ) { 574 return false; 575 } 576 577 // Query for network data 578 $sql = $wpdb->prepare( "DELETE FROM {$wpdb->site} WHERE id = %d", $network->id ); 579 $network = $wpdb->query( $sql ); 580 } 581 } -
src/wp-includes/ms-load.php
16 16 * @return bool True if subdomain configuration is enabled, false otherwise. 17 17 */ 18 18 function is_subdomain_install() { 19 if ( defined( 'SUBDOMAIN_INSTALL') )19 if ( defined( 'SUBDOMAIN_INSTALL' ) ) { 20 20 return SUBDOMAIN_INSTALL; 21 } 21 22 22 23 return ( defined( 'VHOST' ) && VHOST == 'yes' ); 23 24 } … … 44 45 45 46 foreach ( $active_plugins as $plugin ) { 46 47 if ( ! validate_file( $plugin ) // $plugin must validate as file 47 48 49 50 $plugins[] = WP_PLUGIN_DIR . '/' . $plugin;48 && '.php' == substr( $plugin, -4 ) // $plugin must end with '.php' 49 && file_exists( WP_PLUGIN_DIR . '/' . $plugin ) // $plugin must exist 50 ) 51 $plugins[] = WP_PLUGIN_DIR . '/' . $plugin; 51 52 } 52 53 return $plugins; 53 54 } … … 110 111 } 111 112 112 113 /** 113 * Retrieve a network object by its domain and path.114 * Setup multisite globals. 114 115 * 115 * @since 3.9.0116 * @since 4.3.0 116 117 * 117 * @global wpdb $wpdb 118 * @global object $current_site 119 * @global object $current_blog 120 * @global wpdb $wpdb 118 121 * 119 * @param string $domain Domain to check. 120 * @param string $path Path to check. 121 * @param int|null $segments Path segments to use. Defaults to null, or the full path. 122 * @return object|false Network object if successful. False when no network is found. 122 * @return null If already set by sunrise.php. 123 123 */ 124 function get_network_by_path( $domain, $path, $segments = null) {125 global $ wpdb;124 function ms_set_current_globals() { 125 global $current_site, $current_blog, $wpdb; 126 126 127 $domains = array( $domain ); 128 $pieces = explode( '.', $domain ); 127 // Bail if network and site are already set 128 if ( isset( $current_site ) && isset( $current_blog ) ) { 129 return; 130 } 129 131 130 /* 131 * It's possible one domain to search is 'com', but it might as well 132 * be 'localhost' or some other locally mapped domain. 133 */ 134 while ( array_shift( $pieces ) ) { 135 if ( $pieces ) { 136 $domains[] = implode( '.', $pieces ); 137 } 132 // Given the domain and path, let's try to identify the network and site. 133 // Usually, it's easier to query the site first, which declares its network. 134 // In limited situations, though, we either can or must find the network first. 135 136 $domain = strtolower( stripslashes( $_SERVER['HTTP_HOST'] ) ); 137 if ( substr( $domain, -3 ) == ':80' ) { 138 $domain = substr( $domain, 0, -3 ); 139 $_SERVER['HTTP_HOST'] = substr( $_SERVER['HTTP_HOST'], 0, -3 ); 140 } elseif ( substr( $domain, -4 ) == ':443' ) { 141 $domain = substr( $domain, 0, -4 ); 142 $_SERVER['HTTP_HOST'] = substr( $_SERVER['HTTP_HOST'], 0, -4 ); 138 143 } 139 144 145 $path = stripslashes( $_SERVER['REQUEST_URI'] ); 146 if ( is_admin() ) { 147 $path = preg_replace( '#(.*)/wp-admin/.*#', '$1/', $path ); 148 } 149 list( $path ) = explode( '?', $path ); 150 151 // If the network is defined in wp-config.php, we can simply use that. 152 if ( defined( 'DOMAIN_CURRENT_SITE' ) && defined( 'PATH_CURRENT_SITE' ) ) { 153 $current_site = new WP_Network(); 154 $current_site->id = defined( 'SITE_ID_CURRENT_SITE' ) ? SITE_ID_CURRENT_SITE : 1; 155 $current_site->domain = DOMAIN_CURRENT_SITE; 156 $current_site->path = PATH_CURRENT_SITE; 157 158 if ( defined( 'BLOG_ID_CURRENT_SITE' ) ) { 159 $current_site->blog_id = BLOG_ID_CURRENT_SITE; 160 } elseif ( defined( 'BLOGID_CURRENT_SITE' ) ) { // deprecated. 161 $current_site->blog_id = BLOGID_CURRENT_SITE; 162 } 163 164 if ( 0 === strcasecmp( $current_site->domain, $domain ) && 0 === strcasecmp( $current_site->path, $path ) ) { 165 $current_blog = get_site_by_path( $domain, $path ); 166 167 // If the current network has a path and also matches the domain and 168 // path of the request, we need to look for a site using the first path 169 // segment following the network's path. 170 } elseif ( '/' !== $current_site->path && 0 === strcasecmp( $current_site->domain, $domain ) && 0 === stripos( $path, $current_site->path ) ) { 171 $current_blog = get_site_by_path( $domain, $path, 1 + count( explode( '/', trim( $current_site->path, '/' ) ) ) ); 172 173 // Otherwise, use the first path segment (as usual). 174 } else { 175 $current_blog = get_site_by_path( $domain, $path, 1 ); 176 } 177 140 178 /* 141 * If we've gotten to this function during normal execution, there is 142 * more than one network installed. At this point, who knows how many 143 * we have. Attempt to optimize for the situation where networks are 144 * only domains, thus meaning paths never need to be considered. 145 * 146 * This is a very basic optimization; anything further could have drawbacks 147 * depending on the setup, so this is best done per-install. 179 * A "subdomain" install can be re-interpreted to mean "can support anydomain". 180 * If we're not dealing with one of these installs, then the important part 181 * is determining the network first, because we need the network's path to 182 * identify any sites. 148 183 */ 149 $using_paths = true; 150 if ( wp_using_ext_object_cache() ) { 151 $using_paths = wp_cache_get( 'networks_have_paths', 'site-options' ); 152 if ( false === $using_paths ) { 153 $using_paths = (bool) $wpdb->get_var( "SELECT id FROM $wpdb->site WHERE path <> '/' LIMIT 1" ); 154 wp_cache_add( 'networks_have_paths', (int) $using_paths, 'site-options' ); 184 } elseif ( ! is_subdomain_install() ) { 185 186 // Attempt to get the current network from cache 187 $current_site = wp_cache_get( 'current_network', 'site-options' ); 188 if ( false === $current_site ) { 189 190 // Are there even two networks installed? 191 $one_network = $wpdb->get_row( "SELECT * FROM {$wpdb->site} LIMIT 2" ); 192 if ( 1 === $wpdb->num_rows ) { 193 $current_site = new WP_Network( $one_network ); 194 wp_cache_add( 'current_network', $current_site, 'site-options' ); 195 } elseif ( 0 === $wpdb->num_rows ) { 196 ms_not_installed(); 197 } 155 198 } 156 }157 199 158 $paths = array(); 159 if ( $using_paths ) { 160 $path_segments = array_filter( explode( '/', trim( $path, "/" ) ) ); 200 // No network found, so attempt to query it by path 201 if ( empty( $current_site ) ) { 202 $current_site = get_network_by_path( $domain, $path, 1 ); 203 } 161 204 162 /** 163 * Filter the number of path segments to consider when searching for a site. 164 * 165 * @since 3.9.0 166 * 167 * @param int|null $segments The number of path segments to consider. WordPress by default looks at 168 * one path segment. The function default of null only makes sense when you 169 * know the requested path should match a network. 170 * @param string $domain The requested domain. 171 * @param string $path The requested path, in full. 172 */ 173 $segments = apply_filters( 'network_by_path_segments_count', $segments, $domain, $path ); 205 // Bail if no network found 206 if ( empty( $current_site ) ) { 207 ms_not_installed(); 208 209 // Set current site if path matches 210 } elseif ( $path === $current_site->path ) { 211 $current_blog = get_site_by_path( $domain, $path ); 174 212 175 if ( null !== $segments && count($path_segments ) > $segments ) { 176 $path_segments = array_slice( $path_segments, 0, $segments ); 213 // Search the network path + one more path segment (on top of the network path). 214 } else { 215 $current_blog = get_site_by_path( $domain, $path, substr_count( $current_site->path, '/' ) ); 177 216 } 217 } else { 178 218 179 while ( count( $path_segments ) ) { 180 $paths[] = '/' . implode( '/', $path_segments ) . '/'; 181 array_pop( $path_segments ); 219 // Find the site by the domain and at most the first path segment. 220 $current_blog = get_site_by_path( $domain, $path, 1 ); 221 if ( ! empty( $current_blog ) ) { 222 $network_id = $current_blog->site_id ? $current_blog->site_id : 1; 223 $current_site = new WP_Network( $network_id ); 224 225 // If you don't have a site with the same domain/path as a network, 226 // you're pretty screwed, but... 227 } else { 228 $current_site = get_network_by_path( $domain, $path, 1 ); 182 229 } 230 } 183 231 184 $paths[] = '/'; 232 // The network declared by the site trumps any constants. 233 if ( ! empty( $current_blog ) && ( $current_blog->site_id !== $current_site->id ) ) { 234 $current_site = new WP_Network( $current_blog->site_id ); 185 235 } 186 236 187 /** 188 * Determine a network by its domain and path. 189 * 190 * This allows one to short-circuit the default logic, perhaps by 191 * replacing it with a routine that is more optimal for your setup. 192 * 193 * Return null to avoid the short-circuit. Return false if no network 194 * can be found at the requested domain and path. Otherwise, return 195 * an object from wp_get_network(). 196 * 197 * @since 3.9.0 198 * 199 * @param null|bool|object $network Network value to return by path. 200 * @param string $domain The requested domain. 201 * @param string $path The requested path, in full. 202 * @param int|null $segments The suggested number of paths to consult. 203 * Default null, meaning the entire path was to be consulted. 204 * @param array $paths The paths to search for, based on $path and $segments. 205 */ 206 $pre = apply_filters( 'pre_get_network_by_path', null, $domain, $path, $segments, $paths ); 207 if ( null !== $pre ) { 208 return $pre; 237 // Bail if no network has been found by now 238 if ( empty( $current_site ) ) { 239 ms_not_installed(); 209 240 } 210 241 211 // @todo Consider additional optimization routes, perhaps as an opt-in for plugins. 212 // We already have paths covered. What about how far domains should be drilled down (including www)? 242 // @todo Investigate when exactly this can occur. 243 if ( empty( $current_blog ) && defined( 'WP_INSTALLING' ) ) { 244 $current_blog = new stdClass; 245 $current_blog->blog_id = $blog_id = 1; 246 } 213 247 214 $search_domains = "'" . implode( "', '", $wpdb->_escape( $domains ) ) . "'"; 248 // No site has been found, bail. 249 if ( empty( $current_blog ) ) { 215 250 216 if ( ! $using_paths ) { 217 $network = $wpdb->get_row( "SELECT id, domain, path FROM $wpdb->site 218 WHERE domain IN ($search_domains) ORDER BY CHAR_LENGTH(domain) DESC LIMIT 1" ); 219 if ( $network ) { 220 return wp_get_network( $network ); 221 } 222 return false; 251 // We're going to redirect to the network URL, with some possible modifications. 252 $scheme = is_ssl() ? 'https' : 'http'; 253 $destination = "$scheme://{$current_site->domain}{$current_site->path}"; 223 254 224 } else { 225 $search_paths = "'" . implode( "', '", $wpdb->_escape( $paths ) ) . "'"; 226 $networks = $wpdb->get_results( "SELECT id, domain, path FROM $wpdb->site 227 WHERE domain IN ($search_domains) AND path IN ($search_paths) 228 ORDER BY CHAR_LENGTH(domain) DESC, CHAR_LENGTH(path) DESC" ); 229 } 255 /** 256 * Fires when a network can be determined but a site cannot. 257 * 258 * At the time of this action, the only recourse is to redirect somewhere 259 * and exit. If you want to declare a particular site, do so earlier. 260 * 261 * @since 3.9.0 262 * 263 * @param object $current_site The network that had been determined. 264 * @param string $domain The domain used to search for a site. 265 * @param string $path The path used to search for a site. 266 */ 267 do_action( 'ms_site_not_found', $current_site, $domain, $path ); 230 268 231 /* 232 * Domains are sorted by length of domain, then by length of path. 233 * The domain must match for the path to be considered. Otherwise, 234 * a network with the path of / will suffice. 235 */ 236 $found = false; 237 foreach ( $networks as $network ) { 238 if ( $network->domain === $domain || "www.$network->domain" === $domain ) { 239 if ( in_array( $network->path, $paths, true ) ) { 240 $found = true; 241 break; 269 // For a "subdomain" install, redirect to the signup form specifically. 270 if ( is_subdomain_install() && ! defined( 'NOBLOGREDIRECT' ) ) { 271 $destination .= 'wp-signup.php?new=' . str_replace( '.' . $current_site->domain, '', $domain ); 272 273 // For a "subdomain" install, the NOBLOGREDIRECT constant 274 // can be used to avoid a redirect to the signup form. 275 // Using the ms_site_not_found action is preferred to the constant. 276 } elseif ( is_subdomain_install() ) { 277 if ( '%siteurl%' !== NOBLOGREDIRECT ) { 278 $destination = NOBLOGREDIRECT; 242 279 } 280 281 // If the domain we were searching for matches the network's domain, 282 // it's no use redirecting back to ourselves -- it'll cause a loop. 283 // As we couldn't find a site, we're simply not installed. 284 } elseif ( 0 === strcasecmp( $current_site->domain, $domain ) ) { 285 ms_not_installed(); 243 286 } 244 if ( $network->path === '/' ) { 245 $found = true; 246 break; 247 } 287 288 header( 'Location: ' . $destination ); 289 exit; 248 290 } 249 291 250 if ( $found ) { 251 return wp_get_network( $network ); 292 // Figure out the current network's main site. 293 if ( ! isset( $current_site->blog_id ) || 0 === $current_site->blog_id ) { 294 if ( ( $current_blog->domain === $current_site->domain ) && ( $current_blog->path === $current_site->path ) ) { 295 $current_site->blog_id = $current_blog->blog_id; 296 } elseif ( ! $current_site->blog_id = wp_cache_get( 'network:' . $current_site->id . ':main_site', 'site-options' ) ) { 297 $current_site->blog_id = $wpdb->get_var( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE domain = %s AND path = %s", $current_site->domain, $current_site->path ) ); 298 wp_cache_add( 'network:' . $current_site->id . ':main_site', $current_site->blog_id, 'site-options' ); 299 } 252 300 } 253 301 254 return false; 302 // Set some legacy globals 303 $GLOBALS['blog_id'] = $current_blog->blog_id; 304 $GLOBALS['public'] = $current_blog->public; 305 $GLOBALS['site_id'] = $current_blog->site_id; 306 307 // Load the site options 308 wp_load_core_site_options( $current_site->id ); 255 309 } 256 310 257 311 /** 312 * Set the table prefix according to current site 313 * 314 * @since 4.3.0 315 * 316 * @global object $wpdb 317 * @global string $table_prefix 318 * @global object $current_blog 319 */ 320 function ms_set_table_prefix() { 321 global $wpdb, $table_prefix, $current_blog; 322 323 $wpdb->set_prefix( $table_prefix, false ); 324 $wpdb->set_blog_id( $current_blog->blog_id, $current_blog->site_id ); 325 $table_prefix = $wpdb->get_blog_prefix(); 326 } 327 328 /** 329 * Set globals used when switching between sites 330 * 331 * @since 4.3.0 332 * 333 * @see switch_to_blog() 334 * @see restore_current_blog() 335 */ 336 function ms_set_switched_stacks() { 337 $GLOBALS['_wp_switched_stack'] = array(); 338 $GLOBALS['switched'] = false; 339 } 340 341 /** 342 * Retrieve a network object by its domain and path. 343 * 344 * @since 3.9.0 345 * 346 * @param string $domain Domain to check. 347 * @param string $path Path to check. 348 * @param int|null $segments Path segments to use. Defaults to null, or the full path. 349 * @return object|bool Network object if successful. False when no network is found. 350 */ 351 function get_network_by_path( $domain, $path, $segments = null ) { 352 return WP_Network::get_by_path( $domain, $path, $segments ); 353 } 354 355 /** 258 356 * Retrieve an object containing information about the requested network. 259 357 * 260 358 * @since 3.9.0 261 359 * 262 * @global wpdb $wpdb263 *264 360 * @param object|int $network The network's database row or ID. 265 361 * @return object|false Object containing network information if found, false if not. 266 362 */ 267 363 function wp_get_network( $network ) { 268 global $wpdb; 269 270 if ( ! is_object( $network ) ) { 271 $network = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->site WHERE id = %d", $network ) ); 272 if ( ! $network ) { 273 return false; 274 } 275 } 276 277 return $network; 364 return new WP_Network( $network ); 278 365 } 279 366 280 367 /** -
src/wp-includes/ms-settings.php
10 10 * @since 3.0.0 11 11 */ 12 12 13 /** Include Multisite initialization functions */ 13 // Require multisite initialization functions 14 require_once( ABSPATH . WPINC . '/class-wp-network.php' ); 14 15 require_once( ABSPATH . WPINC . '/ms-load.php' ); 15 16 require_once( ABSPATH . WPINC . '/ms-default-constants.php' ); 16 17 18 // Allow custom multisite/network detection & configuration 17 19 if ( defined( 'SUNRISE' ) ) { 18 20 include_once( WP_CONTENT_DIR . '/sunrise.php' ); 19 21 } 20 22 21 / ** Check for and define SUBDOMAIN_INSTALL and the deprecated VHOST constant. */23 // Check for and define SUBDOMAIN_INSTALL (and the deprecated VHOST constant) 22 24 ms_subdomain_constants(); 23 25 24 if ( !isset( $current_site ) || !isset( $current_blog ) ) { 26 // Attempt to set the relevant globals 27 ms_set_current_globals(); 25 28 26 // Given the domain and path, let's try to identify the network and site. 27 // Usually, it's easier to query the site first, which declares its network. 28 // In limited situations, though, we either can or must find the network first. 29 // $table_prefix can be set in sunrise.php 30 ms_set_table_prefix(); 29 31 30 $domain = strtolower( stripslashes( $_SERVER['HTTP_HOST'] ) ); 31 if ( substr( $domain, -3 ) == ':80' ) { 32 $domain = substr( $domain, 0, -3 ); 33 $_SERVER['HTTP_HOST'] = substr( $_SERVER['HTTP_HOST'], 0, -3 ); 34 } elseif ( substr( $domain, -4 ) == ':443' ) { 35 $domain = substr( $domain, 0, -4 ); 36 $_SERVER['HTTP_HOST'] = substr( $_SERVER['HTTP_HOST'], 0, -4 ); 37 } 32 // Setup site-switching globals 33 ms_set_switched_stacks(); 38 34 39 $path = stripslashes( $_SERVER['REQUEST_URI'] );40 if ( is_admin() ) {41 $path = preg_replace( '#(.*)/wp-admin/.*#', '$1/', $path );42 }43 list( $path ) = explode( '?', $path );44 45 // If the network is defined in wp-config.php, we can simply use that.46 if ( defined( 'DOMAIN_CURRENT_SITE' ) && defined( 'PATH_CURRENT_SITE' ) ) {47 $current_site = new stdClass;48 $current_site->id = defined( 'SITE_ID_CURRENT_SITE' ) ? SITE_ID_CURRENT_SITE : 1;49 $current_site->domain = DOMAIN_CURRENT_SITE;50 $current_site->path = PATH_CURRENT_SITE;51 if ( defined( 'BLOG_ID_CURRENT_SITE' ) ) {52 $current_site->blog_id = BLOG_ID_CURRENT_SITE;53 } elseif ( defined( 'BLOGID_CURRENT_SITE' ) ) { // deprecated.54 $current_site->blog_id = BLOGID_CURRENT_SITE;55 }56 57 if ( 0 === strcasecmp( $current_site->domain, $domain ) && 0 === strcasecmp( $current_site->path, $path ) ) {58 $current_blog = get_site_by_path( $domain, $path );59 } elseif ( '/' !== $current_site->path && 0 === strcasecmp( $current_site->domain, $domain ) && 0 === stripos( $path, $current_site->path ) ) {60 // If the current network has a path and also matches the domain and path of the request,61 // we need to look for a site using the first path segment following the network's path.62 $current_blog = get_site_by_path( $domain, $path, 1 + count( explode( '/', trim( $current_site->path, '/' ) ) ) );63 } else {64 // Otherwise, use the first path segment (as usual).65 $current_blog = get_site_by_path( $domain, $path, 1 );66 }67 68 } elseif ( ! is_subdomain_install() ) {69 /*70 * A "subdomain" install can be re-interpreted to mean "can support any domain".71 * If we're not dealing with one of these installs, then the important part is determining72 * the network first, because we need the network's path to identify any sites.73 */74 if ( ! $current_site = wp_cache_get( 'current_network', 'site-options' ) ) {75 // Are there even two networks installed?76 $one_network = $wpdb->get_row( "SELECT * FROM $wpdb->site LIMIT 2" ); // [sic]77 if ( 1 === $wpdb->num_rows ) {78 $current_site = wp_get_network( $one_network );79 wp_cache_add( 'current_network', $current_site, 'site-options' );80 } elseif ( 0 === $wpdb->num_rows ) {81 ms_not_installed();82 }83 }84 if ( empty( $current_site ) ) {85 $current_site = get_network_by_path( $domain, $path, 1 );86 }87 88 if ( empty( $current_site ) ) {89 ms_not_installed();90 } elseif ( $path === $current_site->path ) {91 $current_blog = get_site_by_path( $domain, $path );92 } else {93 // Search the network path + one more path segment (on top of the network path).94 $current_blog = get_site_by_path( $domain, $path, substr_count( $current_site->path, '/' ) );95 }96 } else {97 // Find the site by the domain and at most the first path segment.98 $current_blog = get_site_by_path( $domain, $path, 1 );99 if ( $current_blog ) {100 $current_site = wp_get_network( $current_blog->site_id ? $current_blog->site_id : 1 );101 } else {102 // If you don't have a site with the same domain/path as a network, you're pretty screwed, but:103 $current_site = get_network_by_path( $domain, $path, 1 );104 }105 }106 107 // The network declared by the site trumps any constants.108 if ( $current_blog && $current_blog->site_id != $current_site->id ) {109 $current_site = wp_get_network( $current_blog->site_id );110 }111 112 // No network has been found, bail.113 if ( empty( $current_site ) ) {114 ms_not_installed();115 }116 117 // @todo Investigate when exactly this can occur.118 if ( empty( $current_blog ) && defined( 'WP_INSTALLING' ) ) {119 $current_blog = new stdClass;120 $current_blog->blog_id = $blog_id = 1;121 }122 123 // No site has been found, bail.124 if ( empty( $current_blog ) ) {125 // We're going to redirect to the network URL, with some possible modifications.126 $scheme = is_ssl() ? 'https' : 'http';127 $destination = "$scheme://{$current_site->domain}{$current_site->path}";128 129 /**130 * Fires when a network can be determined but a site cannot.131 *132 * At the time of this action, the only recourse is to redirect somewhere133 * and exit. If you want to declare a particular site, do so earlier.134 *135 * @since 3.9.0136 *137 * @param object $current_site The network that had been determined.138 * @param string $domain The domain used to search for a site.139 * @param string $path The path used to search for a site.140 */141 do_action( 'ms_site_not_found', $current_site, $domain, $path );142 143 if ( is_subdomain_install() && ! defined( 'NOBLOGREDIRECT' ) ) {144 // For a "subdomain" install, redirect to the signup form specifically.145 $destination .= 'wp-signup.php?new=' . str_replace( '.' . $current_site->domain, '', $domain );146 } elseif ( is_subdomain_install() ) {147 // For a "subdomain" install, the NOBLOGREDIRECT constant148 // can be used to avoid a redirect to the signup form.149 // Using the ms_site_not_found action is preferred to the constant.150 if ( '%siteurl%' !== NOBLOGREDIRECT ) {151 $destination = NOBLOGREDIRECT;152 }153 } elseif ( 0 === strcasecmp( $current_site->domain, $domain ) ) {154 /*155 * If the domain we were searching for matches the network's domain,156 * it's no use redirecting back to ourselves -- it'll cause a loop.157 * As we couldn't find a site, we're simply not installed.158 */159 ms_not_installed();160 }161 162 header( 'Location: ' . $destination );163 exit;164 }165 166 // @todo What if the domain of the network doesn't match the current site?167 $current_site->cookie_domain = $current_site->domain;168 if ( 'www.' === substr( $current_site->cookie_domain, 0, 4 ) ) {169 $current_site->cookie_domain = substr( $current_site->cookie_domain, 4 );170 }171 172 // Figure out the current network's main site.173 if ( ! isset( $current_site->blog_id ) ) {174 if ( $current_blog->domain === $current_site->domain && $current_blog->path === $current_site->path ) {175 $current_site->blog_id = $current_blog->blog_id;176 } elseif ( ! $current_site->blog_id = wp_cache_get( 'network:' . $current_site->id . ':main_site', 'site-options' ) ) {177 $current_site->blog_id = $wpdb->get_var( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE domain = %s AND path = %s",178 $current_site->domain, $current_site->path ) );179 wp_cache_add( 'network:' . $current_site->id . ':main_site', $current_site->blog_id, 'site-options' );180 }181 }182 183 $blog_id = $current_blog->blog_id;184 $public = $current_blog->public;185 186 if ( empty( $current_blog->site_id ) ) {187 // This dates to [MU134] and shouldn't be relevant anymore,188 // but it could be possible for arguments passed to insert_blog() etc.189 $current_blog->site_id = 1;190 }191 192 $site_id = $current_blog->site_id;193 wp_load_core_site_options( $site_id );194 }195 196 $wpdb->set_prefix( $table_prefix, false ); // $table_prefix can be set in sunrise.php197 $wpdb->set_blog_id( $current_blog->blog_id, $current_blog->site_id );198 $table_prefix = $wpdb->get_blog_prefix();199 $_wp_switched_stack = array();200 $switched = false;201 202 35 // need to init cache again after blog_id is set 203 36 wp_start_object_cache(); 204 37 205 if ( ! isset( $current_site->site_name ) ) {206 $current_site->site_name = get_site_option( 'site_name' );207 if ( ! $current_site->site_name ) {208 $current_site->site_name = ucfirst( $current_site->domain );209 }210 }211 212 38 // Define upload directory constants 213 39 ms_upload_constants(); -
src/wp-includes/option.php
184 184 } 185 185 186 186 /** 187 * Loads and caches certain often requested site options if is_multisite() and a persistent cache is not being used. 187 * Loads and caches certain often requested site options if is_multisite() and 188 * a persistent cache is not being used. 188 189 * 189 190 * @since 3.0.0 190 191 * 191 192 * @global wpdb $wpdb 192 193 * 193 * @param int $site_id Optional site ID for which to query the options. Defaults to the current site. 194 * @param int $network_id Optional site ID for which to query the options. 195 * Defaults to the current site. 194 196 */ 195 function wp_load_core_site_options( $ site_id = null ) {197 function wp_load_core_site_options( $network_id = null ) { 196 198 global $wpdb; 197 199 198 if ( !is_multisite() || wp_using_ext_object_cache() || defined( 'WP_INSTALLING' ) ) 200 // Bail if not multisite 201 if ( ! is_multisite() || wp_using_ext_object_cache() || defined( 'WP_INSTALLING' ) ) { 199 202 return; 203 } 200 204 201 if ( empty($site_id) ) 202 $site_id = $wpdb->siteid; 205 // Use the current 206 if ( empty( $network_id ) ) { 207 $network_id = $wpdb->siteid; 208 } 203 209 204 $core_options = array('site_name', 'siteurl', 'active_sitewide_plugins', '_site_transient_timeout_theme_roots', '_site_transient_theme_roots', 'site_admins', 'can_compress_scripts', 'global_terms_enabled', 'ms_files_rewriting' ); 205 206 $core_options_in = "'" . implode("', '", $core_options) . "'"; 207 $options = $wpdb->get_results( $wpdb->prepare("SELECT meta_key, meta_value FROM $wpdb->sitemeta WHERE meta_key IN ($core_options_in) AND site_id = %d", $site_id) ); 208 209 foreach ( $options as $option ) { 210 $key = $option->meta_key; 211 $cache_key = "{$site_id}:$key"; 212 $option->meta_value = maybe_unserialize( $option->meta_value ); 213 214 wp_cache_set( $cache_key, $option->meta_value, 'site-options' ); 215 } 210 // Load core options for this network 211 WP_Network::get_core_options( $network_id ); 216 212 } 217 213 218 214 /**