| | 1 | <?php |
| | 2 | /** |
| | 3 | * State API: WP_State class |
| | 4 | * |
| | 5 | * @package WordPress |
| | 6 | * @subpackage Multisite |
| | 7 | * @since 4.7.0 |
| | 8 | */ |
| | 9 | |
| | 10 | /** |
| | 11 | * Core class used for handling switched state of the current site and network. |
| | 12 | * |
| | 13 | * @since 4.7.0 |
| | 14 | */ |
| | 15 | class WP_State { |
| | 16 | /** |
| | 17 | * Array of temporary breakpoints. |
| | 18 | * |
| | 19 | * @since 4.7.0 |
| | 20 | * @access private |
| | 21 | * @var array |
| | 22 | */ |
| | 23 | private $breakpoints = array(); |
| | 24 | |
| | 25 | /** |
| | 26 | * Stack of the switched sites. |
| | 27 | * |
| | 28 | * @since 4.7.0 |
| | 29 | * @access private |
| | 30 | * @var array |
| | 31 | */ |
| | 32 | private $switched_stack = array(); |
| | 33 | |
| | 34 | /** |
| | 35 | * Switches the current site. |
| | 36 | * |
| | 37 | * This function is useful if you need to pull posts, or other information, |
| | 38 | * from other sites. You can switch back afterwards using WP_State::restore_current_site(). |
| | 39 | * |
| | 40 | * If the target site is part of a different network, the network is switched as well. |
| | 41 | * |
| | 42 | * Things that aren't switched: |
| | 43 | * - autoloaded options. See #14992 |
| | 44 | * - plugins. See #14941 |
| | 45 | * |
| | 46 | * @see WP_State::restore_current_site() |
| | 47 | * |
| | 48 | * @since 4.7.0 |
| | 49 | * @access public |
| | 50 | * |
| | 51 | * @global WP_Site $current_blog |
| | 52 | * |
| | 53 | * @param int $new_site The id of the site you want to switch to. Default: current site |
| | 54 | * @return true Always returns true. |
| | 55 | */ |
| | 56 | public function switch_to_site( $new_site ) { |
| | 57 | $old_site = $GLOBALS['current_blog']; |
| | 58 | $new_site = get_site( $new_site ); |
| | 59 | |
| | 60 | $this->switched_stack[] = $old_site; |
| | 61 | |
| | 62 | return $this->perform_switch( $new_site, $old_site ); |
| | 63 | } |
| | 64 | |
| | 65 | /** |
| | 66 | * Restores the current site, after calling WP_State::switch_to_site(). |
| | 67 | * |
| | 68 | * If the current site is part of a different network, the network is restored as well. |
| | 69 | * |
| | 70 | * @see WP_State::switch_to_site() |
| | 71 | * |
| | 72 | * @since 4.7.0 |
| | 73 | * @access public |
| | 74 | * |
| | 75 | * @global WP_Site $current_blog |
| | 76 | * |
| | 77 | * @return bool True on success, false if we're already on the current site. |
| | 78 | */ |
| | 79 | public function restore_current_site() { |
| | 80 | if ( empty( $this->switched_stack ) ) { |
| | 81 | return false; |
| | 82 | } |
| | 83 | |
| | 84 | $old_site = $GLOBALS['current_blog']; |
| | 85 | $new_site = array_pop( $this->switched_stack ); |
| | 86 | |
| | 87 | return $this->perform_switch( $new_site, $old_site ); |
| | 88 | } |
| | 89 | |
| | 90 | /** |
| | 91 | * Determines if WP_State::switch_to_site() is in effect |
| | 92 | * |
| | 93 | * @since 4.7.0 |
| | 94 | * @access public |
| | 95 | * |
| | 96 | * @return bool True if switched, false otherwise. |
| | 97 | */ |
| | 98 | public function is_switched() { |
| | 99 | return ! empty( $this->switched_stack ); |
| | 100 | } |
| | 101 | |
| | 102 | /** |
| | 103 | * Sets a state breakpoint which can be restored later. |
| | 104 | * |
| | 105 | * @since 4.7.0 |
| | 106 | * @access public |
| | 107 | * |
| | 108 | * @global WP_Site $current_blog |
| | 109 | * |
| | 110 | * @param string $name Unique name for this breakpoint. |
| | 111 | * @return bool True on success, false on failure. |
| | 112 | */ |
| | 113 | public function set_breakpoint( $name ) { |
| | 114 | if ( isset( $this->breakpoints[ $name ] ) ) { |
| | 115 | return false; |
| | 116 | } |
| | 117 | |
| | 118 | $this->breakpoints[ $name ] = array( |
| | 119 | 'site' => $GLOBALS['current_blog'], |
| | 120 | 'stack' => $this->switched_stack, |
| | 121 | ); |
| | 122 | |
| | 123 | return true; |
| | 124 | } |
| | 125 | |
| | 126 | /** |
| | 127 | * Restores a previously stored state breakpoint and removes it. |
| | 128 | * |
| | 129 | * @since 4.7.0 |
| | 130 | * @access public |
| | 131 | * |
| | 132 | * @global WP_Site $current_blog |
| | 133 | * |
| | 134 | * @param string $name Unique name for this breakpoint. |
| | 135 | * @return bool True on success, false on failure. |
| | 136 | */ |
| | 137 | public function restore_breakpoint( $name ) { |
| | 138 | if ( ! isset( $this->breakpoints[ $name ] ) ) { |
| | 139 | return false; |
| | 140 | } |
| | 141 | |
| | 142 | $old_site = $GLOBALS['current_blog']; |
| | 143 | $new_site = $this->breakpoints[ $name ]['site']; |
| | 144 | |
| | 145 | $this->switched_stack = $this->breakpoints[ $name ]['stack']; |
| | 146 | |
| | 147 | unset( $this->breakpoints[ $name ] ); |
| | 148 | |
| | 149 | return $this->perform_switch( $new_site, $old_site ); |
| | 150 | } |
| | 151 | |
| | 152 | /** |
| | 153 | * Switched the current state from one site to another. |
| | 154 | * |
| | 155 | * @since 4.7.0 |
| | 156 | * @access private |
| | 157 | * |
| | 158 | * @global WP_Site $current_blog |
| | 159 | * @global WP_Network $current_site |
| | 160 | * @global bool $switched |
| | 161 | * |
| | 162 | * @param WP_Site $new_site The site to switch to. |
| | 163 | * @param WP_Site $old_site The site to switch from. |
| | 164 | * @return true Always returns true. |
| | 165 | */ |
| | 166 | private function perform_switch( $new_site, $old_site ) { |
| | 167 | /* |
| | 168 | * If we're switching to the same site that we're on, |
| | 169 | * set the right vars, do the associated actions, but skip |
| | 170 | * the extra unnecessary work. |
| | 171 | */ |
| | 172 | if ( $new_site->id === $old_site->id ) { |
| | 173 | /** |
| | 174 | * Fires when the site is switched. |
| | 175 | * |
| | 176 | * @since MU |
| | 177 | * |
| | 178 | * @param int $new_site_id New site ID. |
| | 179 | * @param int $old_site_id Old site ID. |
| | 180 | */ |
| | 181 | do_action( 'switch_blog', $new_site->id, $new_site->id ); |
| | 182 | $GLOBALS['switched'] = ! empty( $this->switched_stack ); |
| | 183 | |
| | 184 | return true; |
| | 185 | } |
| | 186 | |
| | 187 | $GLOBALS['current_blog'] = $new_site; |
| | 188 | |
| | 189 | if ( $new_site->network_id !== $old_site->network_id ) { |
| | 190 | $GLOBALS['current_site'] = get_network( $new_site->network_id ); |
| | 191 | } |
| | 192 | |
| | 193 | $this->initialize_after_switch(); |
| | 194 | |
| | 195 | /* This filter is documented in wp-includes/class-wp-state.php */ |
| | 196 | do_action( 'switch_blog', $new_site->id, $old_site->id ); |
| | 197 | $GLOBALS['switched'] = ! empty( $this->switched_stack ); |
| | 198 | |
| | 199 | return true; |
| | 200 | } |
| | 201 | |
| | 202 | /** |
| | 203 | * Reinitializes the necessary parts of WordPress after the current site has been switched. |
| | 204 | * |
| | 205 | * @since 4.7.0 |
| | 206 | * @access private |
| | 207 | * |
| | 208 | * @global wpdb $wpdb |
| | 209 | * @global WP_Site $current_blog |
| | 210 | * @global WP_Network $current_site |
| | 211 | * @global int $blog_id |
| | 212 | * @global string $table_prefix |
| | 213 | * @global WP_Object_Cache $wp_object_cache |
| | 214 | */ |
| | 215 | private function initialize_after_switch() { |
| | 216 | global $wpdb, $current_blog, $current_site, $blog_id, $table_prefix; |
| | 217 | |
| | 218 | $wpdb->set_blog_id( $current_blog->id, $current_site->id ); |
| | 219 | $table_prefix = $wpdb->get_blog_prefix(); |
| | 220 | $blog_id = $current_blog->id; |
| | 221 | |
| | 222 | if ( function_exists( 'wp_cache_switch_to_blog' ) ) { |
| | 223 | wp_cache_switch_to_blog( $blog_id ); |
| | 224 | } else { |
| | 225 | global $wp_object_cache; |
| | 226 | |
| | 227 | if ( is_object( $wp_object_cache ) && isset( $wp_object_cache->global_groups ) ) { |
| | 228 | $global_groups = $wp_object_cache->global_groups; |
| | 229 | } else { |
| | 230 | $global_groups = false; |
| | 231 | } |
| | 232 | |
| | 233 | wp_cache_init(); |
| | 234 | |
| | 235 | if ( function_exists( 'wp_cache_add_global_groups' ) ) { |
| | 236 | if ( is_array( $global_groups ) ) { |
| | 237 | wp_cache_add_global_groups( $global_groups ); |
| | 238 | } else { |
| | 239 | wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'useremail', 'userslugs', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache', 'networks', 'sites', 'site-details' ) ); |
| | 240 | } |
| | 241 | wp_cache_add_non_persistent_groups( array( 'counts', 'plugins' ) ); |
| | 242 | } |
| | 243 | } |
| | 244 | |
| | 245 | if ( did_action( 'init' ) ) { |
| | 246 | wp_roles()->reinit(); |
| | 247 | $current_user = wp_get_current_user(); |
| | 248 | $current_user->for_blog( $blog_id ); |
| | 249 | } |
| | 250 | } |
| | 251 | } |