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