switch_to_blog( int $new_blog_id, bool $deprecated = null ): true
- Since
- MU (3.0.0)
- Source
wp-includes/ms-blogs.php:495
Repoints WordPress's active site context, including $wpdb's table prefix and the object cache group, to the site identified by $new_blog_id. It only works on a multisite network and only affects data-layer globals for the rest of the request, not PHP code (plugins or theme files) already loaded for the originally requested site. Always pair a call with restore_current_blog() so later code doesn't keep running against the wrong site. The $deprecated parameter is accepted for backward compatibility but ignored.
Description
This function is useful if you need to pull posts, or other information, from other blogs. You can switch back afterwards using restore_current_blog().
PHP code loaded with the originally requested site, such as code from a plugin or theme, does not switch. See #14941.
Compatibility
- WordPress
- since MU (3.0.0)
- PHP
- 7.4–8.6-dev
- 6.7.7
- 6.8.8
- 6.9.7
- 7.0.4
- 7.1.0
Present in every tracked release (6.7.7 to 7.1.0), and compiles on PHP 7.4 through 8.6-dev.
Parameters
$new_blog_idint- The ID of the blog to switch to. Default: current blog.
$deprecatedbooloptional- Not used.Default:
null
Return value
true- Always returns true.
Code examples
Every example is editable and runs in a real WordPress booted in your browser by WordPress Playground. Press Run, then edit the code: clicking away re-runs it. Nothing is sent anywhere until you do.
Read the published post count from another site in the network
Switch into a second site long enough to read its post counts, then restore the original site.
if ( ! is_multisite() ) {
echo esc_html( 'This example requires a WordPress multisite network.' );
} else {
$site_ids = get_sites( array( 'fields' => 'ids', 'number' => 2 ) );
if ( count( $site_ids ) < 2 ) {
echo esc_html( 'Need at least two sites in the network for this example.' );
} else {
$target_site_id = $site_ids[1];
switch_to_blog( $target_site_id );
$counts = wp_count_posts( 'post' );
printf( 'Site %d has %d published posts.', absint( $target_site_id ), (int) $counts->publish );
restore_current_blog();
}
}switch_to_blog() only exists when is_multisite() is true; calling it on a single-site install fatals.
Total published posts across every site on the network
Loop over every registered site, switch into each one just long enough to read its post count, then move on.
if ( ! is_multisite() ) {
echo esc_html( 'This example requires a WordPress multisite network.' );
} else {
$total = 0;
foreach ( get_sites( array( 'fields' => 'ids' ) ) as $site_id ) {
switch_to_blog( $site_id );
$total += (int) wp_count_posts( 'post' )->publish;
restore_current_blog();
}
printf( 'Total published posts across the network: %d', $total );
}Each iteration restores before switching to the next site so the stack never grows deeper than one level.
Common problems and fixes · 4
- Why does calling switch_to_blog() throw a fatal 'call to undefined function' error?
- Why do $post, $wp_query, and other globals still show the old site's data after switching?
- Why is the site still wrong after I finished my code?
- Why does the switch_blog action fire even when I pass the current site's ID?
Why does calling switch_to_blog() throw a fatal 'call to undefined function' error?
Why do $post, $wp_query, and other globals still show the old site's data after switching?
Why is the site still wrong after I finished my code?
Why does the switch_blog action fire even when I pass the current site's ID?
Alternatives and related functions
restore_current_blog- When you're done working on the switched-to site and need to pop the switch stack and put $wpdb, table_prefix, and blog_id back to what they were.
get_sites- When you need the list of site IDs in the network before deciding which ones to switch into.
ms_is_switched- When you need to check whether the current request is presently inside a switch_to_blog() call before running site-sensitive logic.
get_current_blog_id- When you only need to know which site is currently active without changing anything.
Performance profile
How much work a call to switch_to_blog() does, and what it touches: the algorithmic scaling, the Zend instruction count per call across PHP versions, the hooks it hands control to, and the core code that calls it. Measured from the compiled opcodes, not a stopwatch, so every number is identical on any machine running the same PHP version, and every function in core is ranked by cost.
- Cost class
- Light
- Scaling
- Constant
- Instructions
- 22–58
- Plugin surface
- 1 hook
- Called by
- 37
Only touches the object cache, via wp_cache_switch_to_blog().
No loop in the body: the same number of instructions runs whatever you pass in.
Executed per call on PHP 8.5, depending on the branch taken. The body compiles to 75.
Third-party callbacks on 'switch_blog' run inside this call, and their cost is not bounded by anything here.
37 places in core call this, so the cost is paid more often than your own code shows.
What it touches
- hookthird-party callbacks
do_action()called directly - cacheobject cache
wp_cache_switch_to_blog()called directly
What one call costs · 4 distinct outcomes
One number would be a lie: the work depends on which branch runs. These are every distinct cost switch_to_blog() can have, taken from its control-flow graph on PHP 8.5.
| When | Instructions | Calls it makes |
|---|---|---|
$new_blog_id === false | 22–23 | get_current_blog_id(), do_action() |
$new_blog_id !== false && function_exists() | 39–40 | get_current_blog_id(), ->set_blog_id(), ->get_blog_prefix(), function_exists(), wp_cache_switch_to_blog(), do_action() |
$new_blog_id !== false && !function_exists() | 45–49 | get_current_blog_id(), ->set_blog_id(), ->get_blog_prefix(), function_exists(), wp_cache_init(), function_exists(), do_action() |
$new_blog_id !== false | 53–58 | get_current_blog_id(), ->set_blog_id(), ->get_blog_prefix(), function_exists(), wp_cache_init(), function_exists(), wp_cache_add_global_groups(), wp_cache_add_non_persistent_groups(), do_action() |
Across PHP versions
| PHP | Compiled | Executed | Branches | Notes |
|---|---|---|---|---|
| 8.6-dev | 75 | 22–58 | 7 | |
| 8.5 | 75 | 22–58 | 7 | |
| 8.4 | 75 | 22–58 | 7 | |
| 8.3 | 75 | 22–58 | 7 | |
| 8.2 | 75 | 22–58 | 7 | |
| 8.1 | 75 | 22–58 | 7 | 5 fewer instructions than PHP 7.4 |
| 7.4 | 80 | 24–62 | 7 |
An instruction is not a fixed amount of time, so a matching count is not necessarily the same speed; what it rules out is a difference in the work itself.
Hooks and filters fired · 2
2 hooks fire while switch_to_blog() runs, in this order:
Uses · 6
- get_current_blog_id()Retrieves the current site ID.
- do_action()Calls the callback functions that have been added to an action hook.
- wp_cache_switch_to_blog()Switches the internal blog ID.
- wp_cache_init()Sets up Object Cache Global and assigns it.
- wp_cache_add_global_groups()Adds a group or set of groups to the list of global groups.
- wp_cache_add_non_persistent_groups()Adds a group or set of groups to the list of non-persistent groups.
Used by · 37
- WP_Importer::set_blog()
- WP_MS_Sites_List_Table::column_blogname()Handles the site name column output.
- WP_Site::get_details()Retrieves the details for this site.
- WP_Theme::get_allowed_on_site()Returns array of stylesheet names of themes allowed on the site.
- WP_User::get_role_caps()Retrieves all of the capabilities of the user's roles, and merges them with individual user capabilities.
- WP_User_Query::generate_cache_key()Generate cache key.
- WP_Users_List_Table::get_views()Returns an associative array listing all the views that can be used with this table.
- add_blog_option()Adds a new option for a given blog ID.
- add_user_to_blog()Adds a user to a blog, along with specifying the user's role.
- confirm_another_blog_signup()Shows a message confirming that the new site has been created.
- count_users()Counts number of users who have each of the user roles.
- create_empty_blog()Create an empty blog.
Show all 37
- current_user_can_for_site()Returns whether the current user has the specified capability for a given site.
- delete_blog_option()Removes an option by name for a given blog ID. Prevents removal of protected WordPress options.
- get_blog_details()Retrieves the details for a blog from the blogs table and blog options.
- get_blog_option()Retrieves option value for a given blog id based on name of option.
- get_blog_permalink()Gets the permalink for a post on another blog.
- get_blog_post()Gets a blog post from any site on the network.
- get_custom_logo()Returns a custom logo, linked to home unless the theme supports removing the link on the home page.
- get_home_url()Retrieves the URL for a given site where the front end is accessible.
- get_oembed_response_data_for_url()Retrieves the oEmbed response data for a given URL.
- get_site_icon_url()Returns the Site Icon URL.
- get_site_url()Retrieves the URL for a given site where WordPress application files (e.g. wp-blog-header.php or the wp-admin/ folder) are accessible.
- has_custom_logo()Determines whether the site has a custom logo.
- newblog_notify_siteadmin()Notifies the network admin that a new site has been activated.
- remove_user_from_blog()Removes a user from a blog.
- update_blog_option()Updates an option for a particular blog.
- upload_space_setting()Displays the site upload space quota setting form on the Edit Site Settings screen.
- user_can_for_site()Returns whether a particular user has the specified capability for a given site.
- wp_admin_bar_my_sites_menu()Adds the "My Sites/[Site Name]" menu and all submenus.
- wp_get_users_with_no_role()Gets the user IDs of all users with no role on this site.
- wp_initialize_site()Runs the initialization routine for a given site.
- wp_is_site_initialized()Checks whether a site is initialized.
- wp_uninitialize_site()Runs the uninitialization routine for a given site.
- wp_xmlrpc_server::wp_getUsersBlogs()Retrieves the blogs of the user.
- wpmu_delete_blog()Deletes a site.
- wpmu_delete_user()Deletes a user and all of their posts from the network.
Source code
function switch_to_blog( $new_blog_id, $deprecated = null ) { global $wpdb; $prev_blog_id = get_current_blog_id(); if ( empty( $new_blog_id ) ) { $new_blog_id = $prev_blog_id; } $GLOBALS['_wp_switched_stack'][] = $prev_blog_id; /* * If we're switching to the same blog id that we're on, * set the right vars, do the associated actions, but skip * the extra unnecessary work */ if ( $new_blog_id === $prev_blog_id ) { /** * Fires when the blog is switched. * * @since MU (3.0.0) * @since 5.4.0 The `$context` parameter was added. * * @param int $new_blog_id New blog ID. * @param int $prev_blog_id Previous blog ID. * @param string $context Additional context. Accepts 'switch' when called from switch_to_blog() * or 'restore' when called from restore_current_blog(). */ do_action( 'switch_blog', $new_blog_id, $prev_blog_id, 'switch' ); $GLOBALS['switched'] = true; return true; } $wpdb->set_blog_id( $new_blog_id ); $GLOBALS['table_prefix'] = $wpdb->get_blog_prefix(); $GLOBALS['blog_id'] = $new_blog_id; if ( function_exists( 'wp_cache_switch_to_blog' ) ) { wp_cache_switch_to_blog( $new_blog_id ); } else { global $wp_object_cache; if ( is_object( $wp_object_cache ) && isset( $wp_object_cache->global_groups ) ) { $global_groups = $wp_object_cache->global_groups; } else { $global_groups = false; } wp_cache_init(); if ( function_exists( 'wp_cache_add_global_groups' ) ) { if ( is_array( $global_groups ) ) { wp_cache_add_global_groups( $global_groups ); } else { wp_cache_add_global_groups( array( 'blog-details', 'blog-id-cache', 'blog-lookup', 'blog_meta', 'global-posts', 'image_editor', 'networks', 'network-queries', 'sites', 'site-details', 'site-options', 'site-queries', 'site-transient', 'theme_files', 'rss', 'users', 'user-queries', 'user_meta', 'useremail', 'userlogins', 'userslugs', ) );Changelog
Introduced in MU (3.0.0). Unchanged from 6.7.7 through 7.1.0.
Signature, return type and hooks compared across 5 parsed releases.
About this page
- Parsed data
- Generated from the wordpress-develop 6.7.7 tag, from
src/wp-includes/ms-blogs.php, and regenerated for each WordPress release so it tracks the code rather than a snapshot of it. - Corrections
- Something wrong on this page? Report it and it gets fixed in the next regeneration.