111 |
111 |
112 return true; |
112 return true; |
113 } |
113 } |
114 |
114 |
115 /** |
115 /** |
116 * Sets current site name. |
116 * Retrieve a network object by its domain and path. |
117 * |
117 * |
118 * @access private |
118 * @since 3.9.0 |
119 * @since 3.0.0 |
119 * |
120 * @return object $current_site object with site_name |
120 * @param string $domain Domain to check. |
121 */ |
121 * @param string $path Path to check. |
122 function get_current_site_name( $current_site ) { |
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. |
|
124 */ |
|
125 function get_network_by_path( $domain, $path, $segments = null ) { |
123 global $wpdb; |
126 global $wpdb; |
124 |
127 |
125 $current_site->site_name = wp_cache_get( $current_site->id . ':site_name', 'site-options' ); |
128 $domains = array( $domain ); |
126 if ( ! $current_site->site_name ) { |
129 $pieces = explode( '.', $domain ); |
127 $current_site->site_name = $wpdb->get_var( $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE site_id = %d AND meta_key = 'site_name'", $current_site->id ) ); |
130 |
128 if ( ! $current_site->site_name ) |
131 /* |
129 $current_site->site_name = ucfirst( $current_site->domain ); |
132 * It's possible one domain to search is 'com', but it might as well |
130 wp_cache_set( $current_site->id . ':site_name', $current_site->site_name, 'site-options' ); |
133 * be 'localhost' or some other locally mapped domain. |
131 } |
134 */ |
132 |
135 while ( array_shift( $pieces ) ) { |
133 return $current_site; |
136 if ( $pieces ) { |
134 } |
137 $domains[] = implode( '.', $pieces ); |
135 |
138 } |
136 /** |
139 } |
137 * Sets current_site object. |
140 |
138 * |
141 /* |
139 * @access private |
142 * If we've gotten to this function during normal execution, there is |
140 * @since 3.0.0 |
143 * more than one network installed. At this point, who knows how many |
141 * @return object $current_site object |
144 * we have. Attempt to optimize for the situation where networks are |
142 */ |
145 * only domains, thus meaning paths never need to be considered. |
143 function wpmu_current_site() { |
146 * |
144 global $wpdb, $current_site, $domain, $path, $sites, $cookie_domain; |
147 * This is a very basic optimization; anything further could have drawbacks |
145 |
148 * depending on the setup, so this is best done per-install. |
146 if ( empty( $current_site ) ) |
149 */ |
147 $current_site = new stdClass; |
150 $using_paths = true; |
148 |
151 if ( wp_using_ext_object_cache() ) { |
149 if ( defined( 'DOMAIN_CURRENT_SITE' ) && defined( 'PATH_CURRENT_SITE' ) ) { |
152 $using_paths = wp_cache_get( 'networks_have_paths', 'site-options' ); |
150 $current_site->id = defined( 'SITE_ID_CURRENT_SITE' ) ? SITE_ID_CURRENT_SITE : 1; |
153 if ( false === $using_paths ) { |
151 $current_site->domain = DOMAIN_CURRENT_SITE; |
154 $using_paths = (bool) $wpdb->get_var( "SELECT id FROM $wpdb->site WHERE path <> '/' LIMIT 1" ); |
152 $current_site->path = $path = PATH_CURRENT_SITE; |
155 wp_cache_add( 'networks_have_paths', (int) $using_paths, 'site-options' ); |
153 if ( defined( 'BLOG_ID_CURRENT_SITE' ) ) |
156 } |
154 $current_site->blog_id = BLOG_ID_CURRENT_SITE; |
157 } |
155 elseif ( defined( 'BLOGID_CURRENT_SITE' ) ) // deprecated. |
158 |
156 $current_site->blog_id = BLOGID_CURRENT_SITE; |
159 $paths = array(); |
157 if ( DOMAIN_CURRENT_SITE == $domain ) |
160 if ( $using_paths ) { |
158 $current_site->cookie_domain = $cookie_domain; |
161 $path_segments = array_filter( explode( '/', trim( $path, "/" ) ) ); |
159 elseif ( substr( $current_site->domain, 0, 4 ) == 'www.' ) |
162 |
160 $current_site->cookie_domain = substr( $current_site->domain, 4 ); |
163 /** |
161 else |
164 * Filter the number of path segments to consider when searching for a site. |
162 $current_site->cookie_domain = $current_site->domain; |
165 * |
163 |
166 * @since 3.9.0 |
164 wp_load_core_site_options( $current_site->id ); |
167 * |
165 |
168 * @param int|null $segments The number of path segments to consider. WordPress by default looks at |
166 return $current_site; |
169 * one path segment. The function default of null only makes sense when you |
167 } |
170 * know the requested path should match a network. |
168 |
171 * @param string $domain The requested domain. |
169 $current_site = wp_cache_get( 'current_site', 'site-options' ); |
172 * @param string $path The requested path, in full. |
170 if ( $current_site ) |
173 */ |
171 return $current_site; |
174 $segments = apply_filters( 'network_by_path_segments_count', $segments, $domain, $path ); |
172 |
175 |
173 $sites = $wpdb->get_results( "SELECT * FROM $wpdb->site" ); // usually only one site |
176 if ( null !== $segments && count($path_segments ) > $segments ) { |
174 if ( 1 == count( $sites ) ) { |
177 $path_segments = array_slice( $path_segments, 0, $segments ); |
175 $current_site = $sites[0]; |
178 } |
176 wp_load_core_site_options( $current_site->id ); |
179 |
177 $path = $current_site->path; |
180 while ( count( $path_segments ) ) { |
178 $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 ) ); |
181 $paths[] = '/' . implode( '/', $path_segments ) . '/'; |
179 $current_site = get_current_site_name( $current_site ); |
182 array_pop( $path_segments ); |
180 if ( substr( $current_site->domain, 0, 4 ) == 'www.' ) |
183 } |
181 $current_site->cookie_domain = substr( $current_site->domain, 4 ); |
184 |
182 wp_cache_set( 'current_site', $current_site, 'site-options' ); |
185 $paths[] = '/'; |
183 return $current_site; |
186 } |
184 } |
187 |
185 $path = substr( $_SERVER[ 'REQUEST_URI' ], 0, 1 + strpos( $_SERVER[ 'REQUEST_URI' ], '/', 1 ) ); |
188 /** |
186 |
189 * Determine a network by its domain and path. |
187 if ( $domain == $cookie_domain ) |
190 * |
188 $current_site = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->site WHERE domain = %s AND path = %s", $domain, $path ) ); |
191 * This allows one to short-circuit the default logic, perhaps by |
189 else |
192 * replacing it with a routine that is more optimal for your setup. |
190 $current_site = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->site WHERE domain IN ( %s, %s ) AND path = %s ORDER BY CHAR_LENGTH( domain ) DESC LIMIT 1", $domain, $cookie_domain, $path ) ); |
193 * |
191 |
194 * Return null to avoid the short-circuit. Return false if no network |
192 if ( ! $current_site ) { |
195 * can be found at the requested domain and path. Otherwise, return |
193 if ( $domain == $cookie_domain ) |
196 * an object from wp_get_network(). |
194 $current_site = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->site WHERE domain = %s AND path='/'", $domain ) ); |
197 * |
195 else |
198 * @since 3.9.0 |
196 $current_site = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->site WHERE domain IN ( %s, %s ) AND path = '/' ORDER BY CHAR_LENGTH( domain ) DESC LIMIT 1", $domain, $cookie_domain, $path ) ); |
199 * |
197 } |
200 * @param null|bool|object $network Network value to return by path. |
198 |
201 * @param string $domain The requested domain. |
199 if ( $current_site ) { |
202 * @param string $path The requested path, in full. |
200 $path = $current_site->path; |
203 * @param int|null $segments The suggested number of paths to consult. |
201 $current_site->cookie_domain = $cookie_domain; |
204 * Default null, meaning the entire path was to be consulted. |
202 return $current_site; |
205 * @param array $paths The paths to search for, based on $path and $segments. |
203 } |
206 */ |
204 |
207 $pre = apply_filters( 'pre_get_network_by_path', null, $domain, $path, $segments, $paths ); |
205 if ( is_subdomain_install() ) { |
208 if ( null !== $pre ) { |
206 $sitedomain = substr( $domain, 1 + strpos( $domain, '.' ) ); |
209 return $pre; |
207 $current_site = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->site WHERE domain = %s AND path = %s", $sitedomain, $path) ); |
210 } |
208 if ( $current_site ) { |
211 |
209 $current_site->cookie_domain = $current_site->domain; |
212 // @todo Consider additional optimization routes, perhaps as an opt-in for plugins. |
210 return $current_site; |
213 // We already have paths covered. What about how far domains should be drilled down (including www)? |
211 } |
214 |
212 |
215 $search_domains = "'" . implode( "', '", $wpdb->_escape( $domains ) ) . "'"; |
213 $current_site = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->site WHERE domain = %s AND path='/'", $sitedomain) ); |
216 |
214 } |
217 if ( ! $using_paths ) { |
215 |
218 $network = $wpdb->get_row( "SELECT id, domain, path FROM $wpdb->site |
216 if ( $current_site || defined( 'WP_INSTALLING' ) ) { |
219 WHERE domain IN ($search_domains) ORDER BY CHAR_LENGTH(domain) DESC LIMIT 1" ); |
217 $path = '/'; |
220 if ( $network ) { |
218 return $current_site; |
221 return wp_get_network( $network ); |
219 } |
222 } |
220 |
223 return false; |
221 // Still no dice. |
224 |
222 wp_load_translations_early(); |
225 } else { |
223 |
226 $search_paths = "'" . implode( "', '", $wpdb->_escape( $paths ) ) . "'"; |
224 if ( 1 == count( $sites ) ) |
227 $networks = $wpdb->get_results( "SELECT id, domain, path FROM $wpdb->site |
225 wp_die( sprintf( __( 'That site does not exist. Please try <a href="%s">%s</a>.' ), 'http://' . $sites[0]->domain . $sites[0]->path ) ); |
228 WHERE domain IN ($search_domains) AND path IN ($search_paths) |
226 else |
229 ORDER BY CHAR_LENGTH(domain) DESC, CHAR_LENGTH(path) DESC" ); |
227 wp_die( __( 'No site defined on this host. If you are the owner of this site, please check <a href="http://codex.wordpress.org/Debugging_a_WordPress_Network">Debugging a WordPress Network</a> for help.' ) ); |
230 } |
|
231 |
|
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; |
|
243 } |
|
244 } |
|
245 if ( $network->path === '/' ) { |
|
246 $found = true; |
|
247 break; |
|
248 } |
|
249 } |
|
250 |
|
251 if ( $found ) { |
|
252 return wp_get_network( $network ); |
|
253 } |
|
254 |
|
255 return false; |
|
256 } |
|
257 |
|
258 /** |
|
259 * Retrieve an object containing information about the requested network. |
|
260 * |
|
261 * @since 3.9.0 |
|
262 * |
|
263 * @param object|int $network The network's database row or ID. |
|
264 * @return object|bool Object containing network information if found, false if not. |
|
265 */ |
|
266 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; |
|
277 } |
|
278 |
|
279 /** |
|
280 * Retrieve a site object by its domain and path. |
|
281 * |
|
282 * @since 3.9.0 |
|
283 * |
|
284 * @param string $domain Domain to check. |
|
285 * @param string $path Path to check. |
|
286 * @param int|null $segments Path segments to use. Defaults to null, or the full path. |
|
287 * @return object|bool Site object if successful. False when no site is found. |
|
288 */ |
|
289 function get_site_by_path( $domain, $path, $segments = null ) { |
|
290 global $wpdb; |
|
291 |
|
292 $path_segments = array_filter( explode( '/', trim( $path, '/' ) ) ); |
|
293 |
|
294 /** |
|
295 * Filter the number of path segments to consider when searching for a site. |
|
296 * |
|
297 * @since 3.9.0 |
|
298 * |
|
299 * @param int|null $segments The number of path segments to consider. WordPress by default looks at |
|
300 * one path segment following the network path. The function default of |
|
301 * null only makes sense when you know the requested path should match a site. |
|
302 * @param string $domain The requested domain. |
|
303 * @param string $path The requested path, in full. |
|
304 */ |
|
305 $segments = apply_filters( 'site_by_path_segments_count', $segments, $domain, $path ); |
|
306 |
|
307 if ( null !== $segments && count( $path_segments ) > $segments ) { |
|
308 $path_segments = array_slice( $path_segments, 0, $segments ); |
|
309 } |
|
310 |
|
311 $paths = array(); |
|
312 |
|
313 while ( count( $path_segments ) ) { |
|
314 $paths[] = '/' . implode( '/', $path_segments ) . '/'; |
|
315 array_pop( $path_segments ); |
|
316 } |
|
317 |
|
318 $paths[] = '/'; |
|
319 |
|
320 /** |
|
321 * Determine a site by its domain and path. |
|
322 * |
|
323 * This allows one to short-circuit the default logic, perhaps by |
|
324 * replacing it with a routine that is more optimal for your setup. |
|
325 * |
|
326 * Return null to avoid the short-circuit. Return false if no site |
|
327 * can be found at the requested domain and path. Otherwise, return |
|
328 * a site object. |
|
329 * |
|
330 * @since 3.9.0 |
|
331 * |
|
332 * @param null|bool|object $site Site value to return by path. |
|
333 * @param string $domain The requested domain. |
|
334 * @param string $path The requested path, in full. |
|
335 * @param int|null $segments The suggested number of paths to consult. |
|
336 * Default null, meaning the entire path was to be consulted. |
|
337 * @param array $paths The paths to search for, based on $path and $segments. |
|
338 */ |
|
339 $pre = apply_filters( 'pre_get_site_by_path', null, $domain, $path, $segments, $paths ); |
|
340 if ( null !== $pre ) { |
|
341 return $pre; |
|
342 } |
|
343 |
|
344 /* |
|
345 * @todo |
|
346 * get_blog_details(), caching, etc. Consider alternative optimization routes, |
|
347 * perhaps as an opt-in for plugins, rather than using the pre_* filter. |
|
348 * For example: The segments filter can expand or ignore paths. |
|
349 * If persistent caching is enabled, we could query the DB for a path <> '/' |
|
350 * then cache whether we can just always ignore paths. |
|
351 */ |
|
352 |
|
353 // Either www or non-www is supported, not both. If a www domain is requested, |
|
354 // query for both to provide the proper redirect. |
|
355 $domains = array( $domain ); |
|
356 if ( 'www.' === substr( $domain, 0, 4 ) ) { |
|
357 $domains[] = substr( $domain, 4 ); |
|
358 $search_domains = "'" . implode( "', '", $wpdb->_escape( $domains ) ) . "'"; |
|
359 } |
|
360 |
|
361 if ( count( $paths ) > 1 ) { |
|
362 $search_paths = "'" . implode( "', '", $wpdb->_escape( $paths ) ) . "'"; |
|
363 } |
|
364 |
|
365 if ( count( $domains ) > 1 && count( $paths ) > 1 ) { |
|
366 $site = $wpdb->get_row( "SELECT * FROM $wpdb->blogs WHERE domain IN ($search_domains) AND path IN ($search_paths) ORDER BY CHAR_LENGTH(domain) DESC, CHAR_LENGTH(path) DESC LIMIT 1" ); |
|
367 } elseif ( count( $domains ) > 1 ) { |
|
368 $sql = $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE path = %s", $paths[0] ); |
|
369 $sql .= " AND domain IN ($search_domains) ORDER BY CHAR_LENGTH(domain) DESC LIMIT 1"; |
|
370 $site = $wpdb->get_row( $sql ); |
|
371 } elseif ( count( $paths ) > 1 ) { |
|
372 $sql = $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain = %s", $domains[0] ); |
|
373 $sql .= " AND path IN ($search_paths) ORDER BY CHAR_LENGTH(path) DESC LIMIT 1"; |
|
374 $site = $wpdb->get_row( $sql ); |
|
375 } else { |
|
376 $site = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain = %s AND path = %s", $domains[0], $paths[0] ) ); |
|
377 } |
|
378 |
|
379 if ( $site ) { |
|
380 // @todo get_blog_details() |
|
381 return $site; |
|
382 } |
|
383 |
|
384 return false; |
228 } |
385 } |
229 |
386 |
230 /** |
387 /** |
231 * Displays a failure message. |
388 * Displays a failure message. |
232 * |
389 * |
236 * @since 3.0.0 |
393 * @since 3.0.0 |
237 */ |
394 */ |
238 function ms_not_installed() { |
395 function ms_not_installed() { |
239 global $wpdb, $domain, $path; |
396 global $wpdb, $domain, $path; |
240 |
397 |
|
398 if ( ! is_admin() ) { |
|
399 dead_db(); |
|
400 } |
|
401 |
241 wp_load_translations_early(); |
402 wp_load_translations_early(); |
242 |
403 |
243 $title = __( 'Error establishing a database connection' ); |
404 $title = __( 'Error establishing a database connection' ); |
|
405 |
244 $msg = '<h1>' . $title . '</h1>'; |
406 $msg = '<h1>' . $title . '</h1>'; |
245 if ( ! is_admin() ) |
|
246 die( $msg ); |
|
247 $msg .= '<p>' . __( 'If your site does not display, please contact the owner of this network.' ) . ''; |
407 $msg .= '<p>' . __( 'If your site does not display, please contact the owner of this network.' ) . ''; |
248 $msg .= ' ' . __( 'If you are the owner of this network please check that MySQL is running properly and all tables are error free.' ) . '</p>'; |
408 $msg .= ' ' . __( 'If you are the owner of this network please check that MySQL is running properly and all tables are error free.' ) . '</p>'; |
249 if ( ! $wpdb->get_var( "SHOW TABLES LIKE '$wpdb->site'" ) ) |
409 $query = $wpdb->prepare( "SHOW TABLES LIKE %s", $wpdb->esc_like( $wpdb->site ) ); |
250 $msg .= '<p>' . sprintf( __( '<strong>Database tables are missing.</strong> This means that MySQL is not running, WordPress was not installed properly, or someone deleted <code>%s</code>. You really should look at your database now.' ), $wpdb->site ) . '</p>'; |
410 if ( ! $wpdb->get_var( $query ) ) { |
251 else |
411 $msg .= '<p>' . sprintf( |
252 $msg .= '<p>' . sprintf( __( '<strong>Could not find site <code>%1$s</code>.</strong> Searched for table <code>%2$s</code> in database <code>%3$s</code>. Is that right?' ), rtrim( $domain . $path, '/' ), $wpdb->blogs, DB_NAME ) . '</p>'; |
412 /* translators: %s: table name */ |
|
413 __( '<strong>Database tables are missing.</strong> This means that MySQL is not running, WordPress was not installed properly, or someone deleted %s. You really should look at your database now.' ), |
|
414 '<code>' . $wpdb->site . '</code>' |
|
415 ) . '</p>'; |
|
416 } else { |
|
417 $msg .= '<p>' . sprintf( |
|
418 /* translators: 1: site url, 2: table name, 3: database name */ |
|
419 __( '<strong>Could not find site %1$s.</strong> Searched for table %2$s in database %3$s. Is that right?' ), |
|
420 '<code>' . rtrim( $domain . $path, '/' ) . '</code>', |
|
421 '<code>' . $wpdb->blogs . '</code>', |
|
422 '<code>' . DB_NAME . '</code>' |
|
423 ) . '</p>'; |
|
424 } |
253 $msg .= '<p><strong>' . __( 'What do I do now?' ) . '</strong> '; |
425 $msg .= '<p><strong>' . __( 'What do I do now?' ) . '</strong> '; |
254 $msg .= __( 'Read the <a target="_blank" href="http://codex.wordpress.org/Debugging_a_WordPress_Network">bug report</a> page. Some of the guidelines there may help you figure out what went wrong.' ); |
426 $msg .= __( 'Read the <a target="_blank" href="https://codex.wordpress.org/Debugging_a_WordPress_Network">bug report</a> page. Some of the guidelines there may help you figure out what went wrong.' ); |
255 $msg .= ' ' . __( 'If you’re still stuck with this message, then check that your database contains the following tables:' ) . '</p><ul>'; |
427 $msg .= ' ' . __( 'If you’re still stuck with this message, then check that your database contains the following tables:' ) . '</p><ul>'; |
256 foreach ( $wpdb->tables('global') as $t => $table ) { |
428 foreach ( $wpdb->tables('global') as $t => $table ) { |
257 if ( 'sitecategories' == $t ) |
429 if ( 'sitecategories' == $t ) |
258 continue; |
430 continue; |
259 $msg .= '<li>' . $table . '</li>'; |
431 $msg .= '<li>' . $table . '</li>'; |
260 } |
432 } |
261 $msg .= '</ul>'; |
433 $msg .= '</ul>'; |
262 |
434 |
263 wp_die( $msg, $title ); |
435 wp_die( $msg, $title, array( 'response' => 500 ) ); |
264 } |
436 } |
|
437 |
|
438 /** |
|
439 * This deprecated function formerly set the site_name property of the $current_site object. |
|
440 * |
|
441 * This function simply returns the object, as before. |
|
442 * The bootstrap takes care of setting site_name. |
|
443 * |
|
444 * @access private |
|
445 * @since 3.0.0 |
|
446 * @deprecated 3.9.0 Use get_current_site() instead. |
|
447 * |
|
448 * @param object $current_site |
|
449 * @return object |
|
450 */ |
|
451 function get_current_site_name( $current_site ) { |
|
452 _deprecated_function( __FUNCTION__, '3.9', 'get_current_site()' ); |
|
453 return $current_site; |
|
454 } |
|
455 |
|
456 /** |
|
457 * This deprecated function managed much of the site and network loading in multisite. |
|
458 * |
|
459 * The current bootstrap code is now responsible for parsing the site and network load as |
|
460 * well as setting the global $current_site object. |
|
461 * |
|
462 * @access private |
|
463 * @since 3.0.0 |
|
464 * @deprecated 3.9.0 |
|
465 * |
|
466 * @return object |
|
467 */ |
|
468 function wpmu_current_site() { |
|
469 global $current_site; |
|
470 _deprecated_function( __FUNCTION__, '3.9' ); |
|
471 return $current_site; |
|
472 } |