function wp_guess_url() {
if ( defined( 'WP_SITEURL' ) && '' !== WP_SITEURL ) {
$abspath_fix = str_replace( '\\', '/', ABSPATH );
$script_filename_dir = dirname( $_SERVER['SCRIPT_FILENAME'] );
// The request is for the admin.
if ( strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) !== false || strpos( $_SERVER['REQUEST_URI'], 'wp-login.php' ) !== false ) {
$path = preg_replace( '#/(wp-admin/.*|wp-login.php)#i', '', $_SERVER['REQUEST_URI'] );
// The request is for a file in ABSPATH.
} elseif ( $script_filename_dir . '/' === $abspath_fix ) {
// Strip off any file/query params in the path.
$path = preg_replace( '#/[^/]*$#i', '', $_SERVER['PHP_SELF'] );
if ( false !== strpos( $_SERVER['SCRIPT_FILENAME'], $abspath_fix ) ) {
// Request is hitting a file inside ABSPATH.
$directory = str_replace( ABSPATH, '', $script_filename_dir );
// Strip off the subdirectory, and any file/query params.
$path = preg_replace( '#/' . preg_quote( $directory, '#' ) . '/[^/]*$#i', '', $_SERVER['REQUEST_URI'] );
} elseif ( false !== strpos( $abspath_fix, $script_filename_dir ) ) {
// Request is hitting a file above ABSPATH.
$subdirectory = substr( $abspath_fix, strpos( $abspath_fix, $script_filename_dir ) + strlen( $script_filename_dir ) );
// Strip off any file/query params from the path, appending the subdirectory to the installation.
$path = preg_replace( '#/[^/]*$#i', '', $_SERVER['REQUEST_URI'] ) . $subdirectory;
$path = $_SERVER['REQUEST_URI'];
$schema = is_ssl() ? 'https://' : 'http://'; // set_url_scheme() is not defined yet.
$url = $schema . $_SERVER['HTTP_HOST'] . $path;
return rtrim( $url, '/' );
* Temporarily suspend cache additions.
* Stops more data being added to the cache, but still allows cache retrieval.
* This is useful for actions, such as imports, when a lot of data would otherwise
* be almost uselessly added to the cache.
* Suspension lasts for a single page load at most. Remember to call this
* function again if you wish to re-enable cache adds earlier.
* @param bool $suspend Optional. Suspends additions if true, re-enables them if false.
* @return bool The current suspend setting
function wp_suspend_cache_addition( $suspend = null ) {
static $_suspend = false;
if ( is_bool( $suspend ) ) {
* Suspend cache invalidation.
* Turns cache invalidation on and off. Useful during imports where you don't want to do
* invalidations every time a post is inserted. Callers must be sure that what they are
* doing won't lead to an inconsistent cache when invalidation is suspended.
* @global bool $_wp_suspend_cache_invalidation
* @param bool $suspend Optional. Whether to suspend or enable cache invalidation. Default true.
* @return bool The current suspend setting.
function wp_suspend_cache_invalidation( $suspend = true ) {
global $_wp_suspend_cache_invalidation;
$current_suspend = $_wp_suspend_cache_invalidation;
$_wp_suspend_cache_invalidation = $suspend;
* Determine whether a site is the main site of the current network.
* @since 4.9.0 The `$network_id` parameter was added.
* @param int $site_id Optional. Site ID to test. Defaults to current site.
* @param int $network_id Optional. Network ID of the network to check for.
* Defaults to current network.
* @return bool True if $site_id is the main site of the network, or if not
function is_main_site( $site_id = null, $network_id = null ) {
if ( ! is_multisite() ) {
$site_id = get_current_blog_id();
$site_id = (int) $site_id;
return get_main_site_id( $network_id ) === $site_id;
* @param int $network_id Optional. The ID of the network for which to get the main site.
* Defaults to the current network.
* @return int The ID of the main site.
function get_main_site_id( $network_id = null ) {
if ( ! is_multisite() ) {
return get_current_blog_id();
$network = get_network( $network_id );
return $network->site_id;
* Determine whether a network is the main network of the Multisite installation.
* @param int $network_id Optional. Network ID to test. Defaults to current network.
* @return bool True if $network_id is the main network, or if not running Multisite.
function is_main_network( $network_id = null ) {
if ( ! is_multisite() ) {
if ( null === $network_id ) {
$network_id = get_current_network_id();
$network_id = (int) $network_id;
return ( get_main_network_id() === $network_id );
* Get the main network ID.
* @return int The ID of the main network.
function get_main_network_id() {
if ( ! is_multisite() ) {
$current_network = get_network();
if ( defined( 'PRIMARY_NETWORK_ID' ) ) {
$main_network_id = PRIMARY_NETWORK_ID;
} elseif ( isset( $current_network->id ) && 1 === (int) $current_network->id ) {
// If the current network has an ID of 1, assume it is the main network.
$_networks = get_networks(
$main_network_id = array_shift( $_networks );
* Filters the main network ID.
* @param int $main_network_id The ID of the main network.
return (int) apply_filters( 'get_main_network_id', $main_network_id );
* Determine whether global terms are enabled.
* @return bool True if multisite and global terms enabled.
function global_terms_enabled() {
if ( ! is_multisite() ) {
static $global_terms = null;
if ( is_null( $global_terms ) ) {
* Filters whether global terms are enabled.
* Returning a non-null value from the filter will effectively short-circuit the function
* and return the value of the 'global_terms_enabled' site option instead.
* @param null $enabled Whether global terms are enabled.
$filter = apply_filters( 'global_terms_enabled', null );
if ( ! is_null( $filter ) ) {
$global_terms = (bool) $filter;
$global_terms = (bool) get_site_option( 'global_terms_enabled', false );
* Determines whether site meta is enabled.
* This function checks whether the 'blogmeta' database table exists. The result is saved as
* a setting for the main network, making it essentially a global setting. Subsequent requests
* will refer to this setting instead of running the query.
* @global wpdb $wpdb WordPress database abstraction object.
* @return bool True if site meta is supported, false otherwise.
function is_site_meta_supported() {
if ( ! is_multisite() ) {
$network_id = get_main_network_id();
$supported = get_network_option( $network_id, 'site_meta_supported', false );
if ( false === $supported ) {
$supported = $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->blogmeta}'" ) ? 1 : 0;
update_network_option( $network_id, 'site_meta_supported', $supported );
return (bool) $supported;
* gmt_offset modification for smart timezone handling.
* Overrides the gmt_offset option if we have a timezone_string available.
* @return float|false Timezone GMT offset, false otherwise.
function wp_timezone_override_offset() {
$timezone_string = get_option( 'timezone_string' );
if ( ! $timezone_string ) {
$timezone_object = timezone_open( $timezone_string );
$datetime_object = date_create();
if ( false === $timezone_object || false === $datetime_object ) {
return round( timezone_offset_get( $timezone_object, $datetime_object ) / HOUR_IN_SECONDS, 2 );
* Sort-helper for timezones.
function _wp_timezone_choice_usort_callback( $a, $b ) {
// Don't use translated versions of Etc.
if ( 'Etc' === $a['continent'] && 'Etc' === $b['continent'] ) {
// Make the order of these more like the old dropdown.
if ( 'GMT+' === substr( $a['city'], 0, 4 ) && 'GMT+' === substr( $b['city'], 0, 4 ) ) {
return -1 * ( strnatcasecmp( $a['city'], $b['city'] ) );
if ( 'UTC' === $a['city'] ) {
if ( 'GMT+' === substr( $b['city'], 0, 4 ) ) {
if ( 'UTC' === $b['city'] ) {
if ( 'GMT+' === substr( $a['city'], 0, 4 ) ) {
return strnatcasecmp( $a['city'], $b['city'] );
if ( $a['t_continent'] == $b['t_continent'] ) {
if ( $a['t_city'] == $b['t_city'] ) {
return strnatcasecmp( $a['t_subcity'], $b['t_subcity'] );
return strnatcasecmp( $a['t_city'], $b['t_city'] );
// Force Etc to the bottom of the list.
if ( 'Etc' === $a['continent'] ) {
if ( 'Etc' === $b['continent'] ) {
return strnatcasecmp( $a['t_continent'], $b['t_continent'] );
* Gives a nicely-formatted list of timezone strings.
* @since 4.7.0 Added the `$locale` parameter.
* @param string $selected_zone Selected timezone.
* @param string $locale Optional. Locale to load the timezones in. Default current site locale.
function wp_timezone_choice( $selected_zone, $locale = null ) {
static $mo_loaded = false, $locale_loaded = null;
$continents = array( 'Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific' );
// Load translations for continents and cities.
if ( ! $mo_loaded || $locale !== $locale_loaded ) {
$locale_loaded = $locale ? $locale : get_locale();
$mofile = WP_LANG_DIR . '/continents-cities-' . $locale_loaded . '.mo';
unload_textdomain( 'continents-cities' );
load_textdomain( 'continents-cities', $mofile );
foreach ( timezone_identifiers_list() as $zone ) {
$zone = explode( '/', $zone );
if ( ! in_array( $zone[0], $continents, true ) ) {
// This determines what gets set and translated - we don't translate Etc/* strings here, they are done later.
0 => ( isset( $zone[0] ) && $zone[0] ),
1 => ( isset( $zone[1] ) && $zone[1] ),
2 => ( isset( $zone[2] ) && $zone[2] ),
$exists[3] = ( $exists[0] && 'Etc' !== $zone[0] );
$exists[4] = ( $exists[1] && $exists[3] );
$exists[5] = ( $exists[2] && $exists[3] );
// phpcs:disable WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText
'continent' => ( $exists[0] ? $zone[0] : '' ),
'city' => ( $exists[1] ? $zone[1] : '' ),
'subcity' => ( $exists[2] ? $zone[2] : '' ),
't_continent' => ( $exists[3] ? translate( str_replace( '_', ' ', $zone[0] ), 'continents-cities' ) : '' ),
't_city' => ( $exists[4] ? translate( str_replace( '_', ' ', $zone[1] ), 'continents-cities' ) : '' ),
't_subcity' => ( $exists[5] ? translate( str_replace( '_', ' ', $zone[2] ), 'continents-cities' ) : '' ),
usort( $zonen, '_wp_timezone_choice_usort_callback' );
if ( empty( $selected_zone ) ) {
$structure[] = '<option selected="selected" value="">' . __( 'Select a city' ) . '</option>';
foreach ( $zonen as $key => $zone ) {
// Build value in an array to join later.
$value = array( $zone['continent'] );
if ( empty( $zone['city'] ) ) {
// It's at the continent level (generally won't happen).
$display = $zone['t_continent'];
// It's inside a continent group.
if ( ! isset( $zonen[ $key - 1 ] ) || $zonen[ $key - 1 ]['continent'] !== $zone['continent'] ) {
$label = $zone['t_continent'];
$structure[] = '<optgroup label="' . esc_attr( $label ) . '">';
// Add the city to the value.
$value[] = $zone['city'];
$display = $zone['t_city'];
if ( ! empty( $zone['subcity'] ) ) {
// Add the subcity to the value.
$value[] = $zone['subcity'];
$display .= ' - ' . $zone['t_subcity'];
$value = implode( '/', $value );
if ( $value === $selected_zone ) {
$selected = 'selected="selected" ';
$structure[] = '<option ' . $selected . 'value="' . esc_attr( $value ) . '">' . esc_html( $display ) . '</option>';
// Close continent optgroup.
if ( ! empty( $zone['city'] ) && ( ! isset( $zonen[ $key + 1 ] ) || ( isset( $zonen[ $key + 1 ] ) && $zonen[ $key + 1 ]['continent'] !== $zone['continent'] ) ) ) {
$structure[] = '</optgroup>';
$structure[] = '<optgroup label="' . esc_attr__( 'UTC' ) . '">';
if ( 'UTC' === $selected_zone ) {
$selected = 'selected="selected" ';
$structure[] = '<option ' . $selected . 'value="' . esc_attr( 'UTC' ) . '">' . __( 'UTC' ) . '</option>';
$structure[] = '</optgroup>';
// Do manual UTC offsets.
$structure[] = '<optgroup label="' . esc_attr__( 'Manual Offsets' ) . '">';