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