| @@ -151,8 +151,136 @@ | ||
| 151 | 151 | return $names; |
| 152 | 152 | } |
| 153 | 153 | |
| 154 | 154 | /** |
| 155 | + * Whether OpenStation runs on a site of this network. | |
| 156 | + * | |
| 157 | + * @param int $blog_id The site. | |
| 158 | + * @return bool | |
| 159 | + */ | |
| 160 | +function openstation_multisite_active_on( $blog_id ) { | |
| 161 | + $plugin = plugin_basename( OPENSTATION_FILE ); | |
| 162 | + if ( isset( get_site_option( 'active_sitewide_plugins', array() )[ $plugin ] ) ) { | |
| 163 | + return true; | |
| 164 | + } | |
| 165 | + // Running here without being in this site's list means the plugin is | |
| 166 | + // loaded some other way (an mu-plugin loader), which reaches every site. | |
| 167 | + if ( ! in_array( $plugin, (array) get_option( 'active_plugins', array() ), true ) ) { | |
| 168 | + return true; | |
| 169 | + } | |
| 170 | + return in_array( $plugin, (array) get_blog_option( $blog_id, 'active_plugins', array() ), true ); | |
| 171 | +} | |
| 172 | + | |
| 173 | +/** | |
| 174 | + * My Sites inside a window: its row links follow the shell instead of | |
| 175 | + * opening as tabs of the Dashboard window. Visit opens a browser tab; | |
| 176 | + * this site's Dashboard goes back to Home; another site's hops to its | |
| 177 | + * shell when OpenStation is active there, or opens its wp-admin in a | |
| 178 | + * browser tab. The bridge leaves `_blank` and `_top` links to the | |
| 179 | + * browser, and a top-level navigation is the same hop the shell takes. | |
| 180 | + * | |
| 181 | + * @return void | |
| 182 | + */ | |
| 183 | +function openstation_multisite_my_sites_load() { | |
| 184 | + if ( ! is_multisite() || ! openstation_is_chromeless_request() ) { | |
| 185 | + return; | |
| 186 | + } | |
| 187 | + // Decided up front: Core runs the filter while switched to each | |
| 188 | + // site, where `openstation_multisite_active_on()` would read that | |
| 189 | + // site's plugin list as this one's. | |
| 190 | + $current = get_current_blog_id(); | |
| 191 | + $active = array(); | |
| 192 | + foreach ( get_blogs_of_user( get_current_user_id() ) as $blog ) { | |
| 193 | + $active[ (int) $blog->userblog_id ] = openstation_multisite_active_on( (int) $blog->userblog_id ); | |
| 194 | + } | |
| 195 | + add_filter( | |
| 196 | + 'myblogs_blog_actions', | |
| 197 | + static function ( $actions, $user_blog ) use ( $current, $active ) { | |
| 198 | + $blog_id = (int) $user_blog->userblog_id; | |
| 199 | + return openstation_multisite_my_sites_actions( $actions, $blog_id, $current, ! empty( $active[ $blog_id ] ) ); | |
| 200 | + }, | |
| 201 | + 10, | |
| 202 | + 2 | |
| 203 | + ); | |
| 204 | +} | |
| 205 | +add_action( 'load-my-sites.php', 'openstation_multisite_my_sites_load' ); | |
| 206 | + | |
| 207 | +/** | |
| 208 | + * One My Sites row's links, rewritten for the shell. Runs switched to | |
| 209 | + * that site, as Core's `myblogs_blog_actions` does, and leaves markup | |
| 210 | + * it does not recognise alone. | |
| 211 | + * | |
| 212 | + * @param string $actions The row's links. | |
| 213 | + * @param int $blog_id The row's site. | |
| 214 | + * @param int $current_blog_id The site whose shell the window is in. | |
| 215 | + * @param bool $active Whether OpenStation runs on the row's site. | |
| 216 | + * @return string | |
| 217 | + */ | |
| 218 | +function openstation_multisite_my_sites_actions( $actions, $blog_id, $current_blog_id, $active ) { | |
| 219 | + $home = esc_url( home_url() ); | |
| 220 | + $admin = esc_url( admin_url() ); | |
| 221 | + | |
| 222 | + if ( $blog_id === $current_blog_id ) { | |
| 223 | + $dashboard = "<a href='" . esc_url( admin_url( 'index.php' ) ) . "'>"; | |
| 224 | + } elseif ( $active ) { | |
| 225 | + $dashboard = "<a href='" . $admin . "' target='_top'>"; | |
| 226 | + } else { | |
| 227 | + $dashboard = "<a href='" . $admin . "' target='_blank' rel='noopener'>"; | |
| 228 | + } | |
| 229 | + | |
| 230 | + return str_replace( | |
| 231 | + array( "<a href='" . $home . "'>", "<a href='" . $admin . "'>" ), | |
| 232 | + array( "<a href='" . $home . "' target='_blank' rel='noopener'>", $dashboard ), | |
| 233 | + (string) $actions | |
| 234 | + ); | |
| 235 | +} | |
| 236 | + | |
| 237 | +/** | |
| 238 | + * The network Sites list inside a window: the same rules as My Sites, | |
| 239 | + * minus a current site, since the network admin is its own instance. | |
| 240 | + * Visit opens a browser tab, and Dashboard hops to the site's shell | |
| 241 | + * when OpenStation is active there, or opens its wp-admin in a tab. | |
| 242 | + * | |
| 243 | + * @return void | |
| 244 | + */ | |
| 245 | +function openstation_multisite_sites_list_load() { | |
| 246 | + if ( ! is_network_admin() || ! openstation_is_chromeless_request() ) { | |
| 247 | + return; | |
| 248 | + } | |
| 249 | + add_filter( | |
| 250 | + 'manage_sites_action_links', | |
| 251 | + static function ( $actions, $blog_id ) { | |
| 252 | + return openstation_multisite_sites_row_actions( (array) $actions, openstation_multisite_active_on( (int) $blog_id ) ); | |
| 253 | + }, | |
| 254 | + 10, | |
| 255 | + 2 | |
| 256 | + ); | |
| 257 | +} | |
| 258 | +add_action( 'load-sites.php', 'openstation_multisite_sites_list_load' ); | |
| 259 | + | |
| 260 | +/** | |
| 261 | + * One network Sites row's actions, with a browsing context on the two | |
| 262 | + * links that leave the network admin. A link that already names one | |
| 263 | + * is left alone. | |
| 264 | + * | |
| 265 | + * @param array<string,string> $actions The row's actions, keyed as Core keys them. | |
| 266 | + * @param bool $active Whether OpenStation runs on the row's site. | |
| 267 | + * @return array<string,string> | |
| 268 | + */ | |
| 269 | +function openstation_multisite_sites_row_actions( array $actions, $active ) { | |
| 270 | + $targets = array( | |
| 271 | + 'visit' => '_blank', | |
| 272 | + 'backend' => $active ? '_top' : '_blank', | |
| 273 | + ); | |
| 274 | + foreach ( $targets as $key => $target ) { | |
| 275 | + if ( isset( $actions[ $key ] ) && is_string( $actions[ $key ] ) && false === strpos( $actions[ $key ], 'target=' ) ) { | |
| 276 | + $actions[ $key ] = (string) preg_replace( '/^<a /', '<a target="' . $target . '" ', $actions[ $key ], 1 ); | |
| 277 | + } | |
| 278 | + } | |
| 279 | + return $actions; | |
| 280 | +} | |
| 281 | + | |
| 282 | +/** | |
| 155 | 283 | * The sites the user may switch to, each with its own shell screen. |
| 156 | 284 | * |
| 157 | 285 | * The user's own sites first — `get_blogs_of_user()`, the list behind |
| 158 | 286 | * the admin bar's My Sites, minus the archived, spam and deleted, in |
| @@ -181,8 +309,10 @@ | ||
| 181 | 309 | $sites[] = array( |
| 182 | 310 | 'id' => (string) $blog_id, |
| 183 | 311 | 'name' => $name, |
| 184 | 312 | 'shellUrl' => esc_url_raw( get_admin_url( $blog_id, 'admin.php?page=' . OPENSTATION_SHELL_PAGE_SLUG ) ), |
| 313 | + 'adminUrl' => esc_url_raw( get_admin_url( $blog_id ) ), | |
| 314 | + 'active' => openstation_multisite_active_on( $blog_id ), | |
| 185 | 315 | 'kind' => 'local', |
| 186 | 316 | 'foreign' => false, |
| 187 | 317 | ); |
| 188 | 318 | } |
| @@ -203,9 +333,11 @@ | ||
| 203 | 333 | * a different set. A site dropped here is not offered, though the |
| 204 | 334 | * admin bar still reaches it. |
| 205 | 335 | * |
| 206 | 336 | * @param array[] $sites Each `id` (blog id as a string, or `member:<id>`), `name`, `shellUrl`, |
| 207 | - * `kind` (`local` for a site of this network, `member` for an install | |
| 337 | + * `adminUrl` and `active` (whether OpenStation runs there; the switcher | |
| 338 | + * opens a site without it at `adminUrl` in a browser tab) on a site of | |
| 339 | + * this network, `kind` (`local` for a site of this network, `member` for an install | |
| 208 | 340 | * that joined from elsewhere, which the switcher marks as external), |
| 209 | 341 | * `foreign` (whether the entry is another install, which a switch to |
| 210 | 342 | * it needs a login token for). |
| 211 | 343 | */ |