Ticket #31985: 31985.4.diff
File 31985.4.diff, 21.4 KB (added by , 9 years ago) |
---|
-
src/wp-includes/class-wp-network.php
1 <?php 2 /** 3 * WordPress Network class. 4 * 5 * This class contains the values and functional methods for interacting with 6 * a network of WordPress sites. Traditionally used for multisite, this class 7 * is used by the $current_site global to setup the current network. 8 * 9 * This class is most useful in WordPress multi-network installations where the 10 * ability to interact with any network of sites is required. 11 * 12 * @since 4.4.0 13 * @package WordPress 14 */ 15 class WP_Network { 16 17 /** 18 * Network ID. 19 * 20 * @since 4.4.0 21 * 22 * @var int 23 */ 24 public $id; 25 26 /** 27 * Domain of the network. 28 * 29 * @since 4.4.0 30 * 31 * @var string 32 */ 33 public $domain = ''; 34 35 /** 36 * Path of the network. 37 * 38 * @since 4.4.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. A main site is mapped to 48 * the network when the network is created. 49 * 50 * @since 4.4.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.4.0 60 * 61 * @var int 62 */ 63 public $cookie_domain = ''; 64 65 /** 66 * Name of this network. 67 * 68 * Named "site" vs. "network" for legacy reasons. 69 * 70 * @since 4.4.0 71 * 72 * @var string 73 */ 74 public $site_name = ''; 75 76 /** 77 * Retrieve a network from the database by its ID. 78 * 79 * @since 4.4.0 80 * 81 * @global wpdb $wpdb 82 * 83 * @param int $network_id The ID of the network to retrieve. 84 * 85 * @return WP_Network|bool The network's object if found. False if not. 86 */ 87 public static function get_instance( $network_id ) { 88 global $wpdb; 89 90 $network = wp_cache_get( $network_id, 'networks' ); 91 92 if ( false === $network ) { 93 $network = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->site} WHERE id = %d LIMIT 1", $network_id ) ); 94 95 if ( empty( $network ) || is_wp_error( $network ) ) { 96 return false; 97 } 98 99 wp_cache_add( $network_id, $network, 'networks' ); 100 } 101 102 return new WP_Network( $network ); 103 } 104 105 /** 106 * Create a new WP_Network object. 107 * 108 * Will populate object properties from the object provided and assign other 109 * default properties based on that information. 110 * 111 * @since 4.4.0 112 * 113 * @param WP_Network|object $network A network object. 114 */ 115 public function __construct( $network ) { 116 foreach( get_object_vars( $network ) as $key => $value ) { 117 $this->$key = $value; 118 } 119 120 self::load_core_options( $this->id ); 121 $this->set_cookie_domain(); 122 $this->set_site_name(); 123 } 124 125 /** 126 * Set the cookie domain based on the network domain. 127 * 128 * @todo What if the domain of the network doesn't match the current site? 129 * 130 * @since 4.4.0 131 */ 132 private function set_cookie_domain() { 133 // The cookie domain may already be set during sunrise. 134 if ( ! empty( $this->cookie_domain ) ) { 135 return; 136 } 137 138 $this->cookie_domain = $this->domain; 139 if ( 'www.' === substr( $this->cookie_domain, 0, 4 ) ) { 140 $this->cookie_domain = substr( $this->cookie_domain, 4 ); 141 } 142 } 143 144 /** 145 * Set the name for this network's object. 146 * 147 * @since 4.4.0 148 */ 149 private function set_site_name() { 150 // The site name may already be set during sunrise. 151 if ( ! empty( $this->site_name ) ) { 152 return; 153 } 154 155 $this->site_name = get_site_option( 'site_name' ); 156 if ( empty( $this->site_name ) ) { 157 $this->site_name = ucfirst( $this->domain ); 158 } 159 } 160 161 /** 162 * Retrieve a network by its domain and path. 163 * 164 * @since 4.4.0 165 * 166 * @param string $domain Domain to check. 167 * @param string $path Path to check. 168 * @param int|null $segments Path segments to use. Defaults to null, or the full path. 169 * 170 * @return WP_Network|bool Network object if successful. False when no network is found. 171 */ 172 public static function get_by_path( $domain = '', $path = '', $segments = null ) { 173 global $wpdb; 174 175 $domains = array( $domain ); 176 $pieces = explode( '.', $domain ); 177 178 /* 179 * It's possible one domain to search is 'com', but it might as well 180 * be 'localhost' or some other locally mapped domain. 181 */ 182 while ( array_shift( $pieces ) ) { 183 if ( ! empty( $pieces ) ) { 184 $domains[] = implode( '.', $pieces ); 185 } 186 } 187 188 /* 189 * If we've gotten to this function during normal execution, there is 190 * more than one network installed. At this point, who knows how many 191 * we have. Attempt to optimize for the situation where networks are 192 * only domains, thus meaning paths never need to be considered. 193 * 194 * This is a very basic optimization; anything further could have 195 * drawbacks depending on the setup, so this is best done per-install. 196 */ 197 $using_paths = true; 198 if ( wp_using_ext_object_cache() ) { 199 $using_paths = wp_cache_get( 'networks_have_paths', 'site-options' ); 200 if ( false === $using_paths ) { 201 $using_paths = (bool) $wpdb->get_var( "SELECT id FROM {$wpdb->site} WHERE path <> '/' LIMIT 1" ); 202 wp_cache_add( 'networks_have_paths', (int) $using_paths, 'site-options' ); 203 } 204 } 205 206 $paths = array(); 207 if ( true === $using_paths ) { 208 $path_segments = array_filter( explode( '/', trim( $path, '/' ) ) ); 209 210 /** 211 * Filter the number of path segments to consider when searching for a site. 212 * 213 * @since 3.9.0 214 * 215 * @param int|null $segments The number of path segments to consider. WordPress by default looks at 216 * one path segment. The function default of null only makes sense when you 217 * know the requested path should match a network. 218 * @param string $domain The requested domain. 219 * @param string $path The requested path, in full. 220 */ 221 $segments = apply_filters( 'network_by_path_segments_count', $segments, $domain, $path ); 222 223 if ( ( null !== $segments ) && count( $path_segments ) > $segments ) { 224 $path_segments = array_slice( $path_segments, 0, $segments ); 225 } 226 227 while ( count( $path_segments ) ) { 228 $paths[] = '/' . implode( '/', $path_segments ) . '/'; 229 array_pop( $path_segments ); 230 } 231 232 $paths[] = '/'; 233 } 234 235 /** 236 * Determine a network by its domain and path. 237 * 238 * This allows one to short-circuit the default logic, perhaps by 239 * replacing it with a routine that is more optimal for your setup. 240 * 241 * Return null to avoid the short-circuit. Return false if no network 242 * can be found at the requested domain and path. Otherwise, return 243 * an object from wp_get_network(). 244 * 245 * @since 3.9.0 246 * 247 * @param null|bool|object $network Network value to return by path. 248 * @param string $domain The requested domain. 249 * @param string $path The requested path, in full. 250 * @param int|null $segments The suggested number of paths to consult. 251 * Default null, meaning the entire path was to be consulted. 252 * @param array $paths The paths to search for, based on $path and $segments. 253 */ 254 $pre = apply_filters( 'pre_get_network_by_path', null, $domain, $path, $segments, $paths ); 255 if ( null !== $pre ) { 256 return $pre; 257 } 258 259 // @todo Consider additional optimization routes, perhaps as an opt-in for plugins. 260 // We already have paths covered. What about how far domains should be drilled down (including www)? 261 262 $search_domains = "'" . implode( "', '", $wpdb->_escape( $domains ) ) . "'"; 263 264 if ( false === $using_paths ) { 265 $network = $wpdb->get_row( "SELECT * FROM {$wpdb->site} 266 WHERE domain IN ({$search_domains}) 267 ORDER BY CHAR_LENGTH(domain) 268 DESC LIMIT 1" ); 269 270 if ( ! empty( $network ) && ! is_wp_error( $network ) ) { 271 return new WP_Network( $network ); 272 } 273 274 return false; 275 276 } else { 277 $search_paths = "'" . implode( "', '", $wpdb->_escape( $paths ) ) . "'"; 278 $networks = $wpdb->get_results( "SELECT * FROM {$wpdb->site} 279 WHERE domain IN ({$search_domains}) 280 AND path IN ({$search_paths}) 281 ORDER BY CHAR_LENGTH(domain) DESC, CHAR_LENGTH(path) DESC" ); 282 } 283 284 /* 285 * Domains are sorted by length of domain, then by length of path. 286 * The domain must match for the path to be considered. Otherwise, 287 * a network with the path of / will suffice. 288 */ 289 $found = false; 290 foreach ( $networks as $network ) { 291 if ( ( $network->domain === $domain ) || ( "www.{$network->domain}" === $domain ) ) { 292 if ( in_array( $network->path, $paths, true ) ) { 293 $found = true; 294 break; 295 } 296 } 297 if ( $network->path === '/' ) { 298 $found = true; 299 break; 300 } 301 } 302 303 if ( true === $found ) { 304 return new WP_Network( $network ); 305 } 306 307 return false; 308 } 309 310 /** 311 * Load a set of core site options for the network from the database and 312 * store them in cache for future retrieval. 313 * 314 * @since 4.4.0 315 * 316 * @param int $network_id 317 */ 318 public static function load_core_options( $network_id ) { 319 global $wpdb; 320 321 // Setup core options query 322 $meta_keys = self::get_core_option_keys(); 323 $core_options_in = "'" . implode( "', '", $meta_keys ) . "'"; 324 $sql = $wpdb->prepare( "SELECT meta_key, meta_value 325 FROM {$wpdb->sitemeta} 326 WHERE meta_key IN ({$core_options_in}) 327 AND site_id = %d", $network_id ); 328 329 // Query for core network options 330 $options = $wpdb->get_results( $sql ); 331 332 // Bail if no options found 333 if ( empty( $options ) || is_wp_error( $options ) ) { 334 return; 335 } 336 337 // Loop through options and add them to the object cache 338 foreach ( $options as $option ) { 339 340 // Setup option values to cache 341 $key = $option->meta_key; 342 $cache_key = "{$network_id}:$key"; 343 $option->meta_value = maybe_unserialize( $option->meta_value ); 344 345 // Cache the option value 346 wp_cache_set( $cache_key, $option->meta_value, 'site-options' ); 347 } 348 } 349 350 /* 351 * Provide a list of core option keys used for network metadata. 352 * 353 * @since 4.4.0 354 * 355 * @return array 356 */ 357 private static function get_core_option_keys() { 358 return array( 359 'site_name', 360 'siteurl', 361 'active_sitewide_plugins', 362 '_site_transient_timeout_theme_roots', 363 '_site_transient_theme_roots', 364 'site_admins', 365 'can_compress_scripts', 366 'global_terms_enabled', 367 'ms_files_rewriting' 368 ); 369 } 370 } 371 No newline at end of file -
src/wp-includes/ms-load.php
114 114 * 115 115 * @since 3.9.0 116 116 * 117 * @global wpdb $wpdb118 *119 117 * @param string $domain Domain to check. 120 118 * @param string $path Path to check. 121 119 * @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.120 * @return WP_Network|false Network object if successful. False when no network is found. 123 121 */ 124 122 function get_network_by_path( $domain, $path, $segments = null ) { 125 global $wpdb; 126 127 $domains = array( $domain ); 128 $pieces = explode( '.', $domain ); 129 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 } 138 } 139 140 /* 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. 148 */ 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' ); 155 } 156 } 157 158 $paths = array(); 159 if ( $using_paths ) { 160 $path_segments = array_filter( explode( '/', trim( $path, "/" ) ) ); 161 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 ); 174 175 if ( null !== $segments && count($path_segments ) > $segments ) { 176 $path_segments = array_slice( $path_segments, 0, $segments ); 177 } 178 179 while ( count( $path_segments ) ) { 180 $paths[] = '/' . implode( '/', $path_segments ) . '/'; 181 array_pop( $path_segments ); 182 } 183 184 $paths[] = '/'; 185 } 186 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; 209 } 210 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)? 213 214 $search_domains = "'" . implode( "', '", $wpdb->_escape( $domains ) ) . "'"; 215 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; 223 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 } 230 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; 242 } 243 } 244 if ( $network->path === '/' ) { 245 $found = true; 246 break; 247 } 248 } 249 250 if ( $found ) { 251 return wp_get_network( $network ); 252 } 253 254 return false; 123 return WP_Network::get_by_path( $domain, $path, $segments ); 255 124 } 256 125 257 126 /** … … 259 128 * 260 129 * @since 3.9.0 261 130 * 262 * @global wpdb $wpdb263 *264 131 * @param object|int $network The network's database row or ID. 265 * @return object|false Object containing network information if found, false if not.132 * @return WP_Network|false Object containing network information if found, false if not. 266 133 */ 267 134 function wp_get_network( $network ) { 268 global $wpdb;269 270 135 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 } 136 $network = WP_Network::get_instance( $network ); 137 } else { 138 $network = new WP_Network( $network ); 275 139 } 276 140 277 141 return $network; -
src/wp-includes/ms-settings.php
11 11 */ 12 12 13 13 /** Include 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 … … 75 76 // Are there even two networks installed? 76 77 $one_network = $wpdb->get_row( "SELECT * FROM $wpdb->site LIMIT 2" ); // [sic] 77 78 if ( 1 === $wpdb->num_rows ) { 78 $current_site = wp_get_network( $one_network );79 $current_site = new WP_Network( $one_network ); 79 80 wp_cache_add( 'current_network', $current_site, 'site-options' ); 80 81 } elseif ( 0 === $wpdb->num_rows ) { 81 82 ms_not_installed(); 82 83 } 83 84 } 84 85 if ( empty( $current_site ) ) { 85 $current_site = get_network_by_path( $domain, $path, 1 );86 $current_site = WP_Network::get_by_path( $domain, $path, 1 ); 86 87 } 87 88 88 89 if ( empty( $current_site ) ) { … … 97 98 // Find the site by the domain and at most the first path segment. 98 99 $current_blog = get_site_by_path( $domain, $path, 1 ); 99 100 if ( $current_blog ) { 100 $current_site = wp_get_network( $current_blog->site_id ? $current_blog->site_id : 1 );101 $current_site = WP_Network::get_instance( $current_blog->site_id ? $current_blog->site_id : 1 ); 101 102 } else { 102 103 // 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 $current_site = WP_Network::get_by_path( $domain, $path, 1 ); 104 105 } 105 106 } 106 107 107 108 // The network declared by the site trumps any constants. 108 109 if ( $current_blog && $current_blog->site_id != $current_site->id ) { 109 $current_site = wp_get_network( $current_blog->site_id );110 $current_site = WP_Network::get_instance( $current_blog->site_id ); 110 111 } 111 112 112 113 // No network has been found, bail. … … 163 164 exit; 164 165 } 165 166 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 167 // Figure out the current network's main site. 173 if ( ! isset( $current_site->blog_id ) ) {168 if ( empty( $current_site->blog_id ) ) { 174 169 if ( $current_blog->domain === $current_site->domain && $current_blog->path === $current_site->path ) { 175 170 $current_site->blog_id = $current_blog->blog_id; 176 171 } elseif ( ! $current_site->blog_id = wp_cache_get( 'network:' . $current_site->id . ':main_site', 'site-options' ) ) { … … 190 185 } 191 186 192 187 $site_id = $current_blog->site_id; 193 wp_load_core_site_options( $site_id );194 188 } 195 189 196 190 $wpdb->set_prefix( $table_prefix, false ); // $table_prefix can be set in sunrise.php … … 202 196 // need to init cache again after blog_id is set 203 197 wp_start_object_cache(); 204 198 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 } 199 if ( ! $current_site instanceof WP_Network ) { 200 $current_site = new WP_Network( $current_site ); 210 201 } 211 202 212 203 // Define upload directory constants -
src/wp-includes/option.php
199 199 * 200 200 * @global wpdb $wpdb 201 201 * 202 * @param int $ site_id Optional site ID for which to query the options. Defaults to the current site.202 * @param int $network_id Optional. ID of the network for which to load options. Defaults to the current network. 203 203 */ 204 function wp_load_core_site_options( $ site_id = null ) {204 function wp_load_core_site_options( $network_id = null ) { 205 205 global $wpdb; 206 206 207 207 if ( !is_multisite() || wp_using_ext_object_cache() || defined( 'WP_INSTALLING' ) ) 208 208 return; 209 209 210 if ( empty($site_id) ) 211 $site_id = $wpdb->siteid; 212 213 $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' ); 214 215 $core_options_in = "'" . implode("', '", $core_options) . "'"; 216 $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) ); 217 218 foreach ( $options as $option ) { 219 $key = $option->meta_key; 220 $cache_key = "{$site_id}:$key"; 221 $option->meta_value = maybe_unserialize( $option->meta_value ); 222 223 wp_cache_set( $cache_key, $option->meta_value, 'site-options' ); 210 if ( empty( $network_id ) ) { 211 $network_id = $wpdb->siteid; 224 212 } 213 214 WP_Network::load_core_options( $network_id ); 225 215 } 226 216 227 217 /**