Skip to content

Multisite: every site is its own OpenStation, with a site switcher in overview - #741

Merged
epeicher merged 4 commits into
trunkfrom
multisite-site-instances
Sep 4, 2026
Merged

Multisite: every site is its own OpenStation, with a site switcher in overview#741
epeicher merged 4 commits into
trunkfrom
multisite-site-instances

Conversation

@epeicher

@epeicher epeicher commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

What it does

On a network, every site is its own OpenStation, and so is the network admin. Overview's top bar gains a row above the desktop tiles: an <os-segmented> naming Network Admin (with manage_network) and every site, with the current instance lit. Picking another one navigates to that site's shell screen with the cross-document slide the shell already opts into, and lands in that site's overview, so the panel reads as one surface whose tiles changed. Cmd/ctrl/shift or middle click opens the site in a browser tab instead. Every cross-admin click (the Network Admin tile and its rows, a Sites-list "Dashboard" link inside a window) takes the same hop.

Site Spaces (#736) are replaced: no scoped desktops, no per-Space dock, no payload quarantine, no session scope exception. A session saved with Space desktops is healed on read, so those desks disappear rather than lingering as empty ones.

Rationale

A Space could only ever show another admin's pages as iframe windows and borrow its dock. That admin's native windows, widgets, settings and plugins stayed out of reach (the quarantine existed precisely to keep a foreign payload from registering), and it only worked where framing does, so subdomain and mapped-domain networks fell back to a tab. A site's own shell is the real instance, works on every network shape, and the per-admin sessions from #728 already keep each one's desktops. Switching costs a page load; the view transition covers it.

Considered generalising Spaces into per-site desktop groups inside one shell instead. It stays instant, but it can never be more than iframes plus a dock, and it is same-origin only.

Implementation

  • The switcher is buildSiteSwitcher() in src/multisite/site-switcher.ts, built from wp.os.config.multisite (MultisiteConfig gained current, sites[] and networkAdmin.shellUrl). Overview offers one seam for a row above its tiles, installOverviewHeader( build ) in src/window-manager/overview.ts; the shell installs the switcher there, and overviewTopBarReserve() adds the row's height to the grid reserve so thumbnails never sit under it. A lone instance gets no row.

  • Landing in overview is a one-shot boot arg, openstation_overview=1: read once server-side (openstation_shell_lands_in_overview()) into config.landInOverview, stripped from the address bar with target and intent (SHELL_BOOT_ARGS), and honoured after session restore and the entry window so the grid has every window it will show:

    if ( config.landInOverview && ! soloWindowId ) {
        void bootWindowsSettled.then( () => {
            manager.enterOverview();
            revealInstance();
        } );
    }
  • The hop animates on both sides of the page swap. The cross-document view transition can only crossfade the root, and the new page paints its bare desk long before overview opens, so on its own a switch read as a hard cut. The switcher now slides the desk out towards the site it picked (os-shell--hop-out-next / -prev on the shell root, for the beat before it navigates) and leaves the direction as a one-shot sessionStorage hint (openstation-hop-direction); a shell asked to boot into overview is stamped os-shell--arriving server-side, so its first paint is the wallpaper alone, and once overview is up revealInstance() slides the desk in from the same side. No hint (a cross-origin site) fades instead. A desk never stays hidden: a keyframe fallback in the stylesheet and a boot timer both let it in within seconds, and reduced motion skips every slide. src/multisite/instance-transition.ts drives it.

  • The site list is openstation_multisite_sites(): the user's own sites (get_blogs_of_user(), minus archived, spam and deleted) and, for a super admin, the network's sites by path up to the first 20, through the new openstation_multisite_sites filter. The multisite block is no longer gated on manage_network; only its networkAdmin part is.

  • The hop is hopToAdmin() from src/multisite/hop.ts: navigate this tab to the raw admin URL and let the admin_init redirect route it to the matching shell screen with the URL as the boot target. The Network Admin tile and the bridge's os-iframe-other-admin-link router both use it.

  • Removed: src/multisite/spaces.ts, src/multisite/space-dock.ts, src/admin-scope.ts and its PHP twin, Desktop.scope, the scoped branch of closeDesktop(), frameSourceIsOtherAdmin() and openstation_session_desktop_scope(). The bridge keeps its inline adminScope() rule, the one copy still needed. openstation_get_session() drops desktops carrying a scope and moves the active desktop off them.

  • Kept from Multisite: Site Spaces — another admin opens on its own desktop #736: the probe's admin-context fix (openstation_menu_refresh_probe_screen_id()), because a live refresh on the network shell still needs it.

Testing instructions

npm run test:js            # site-switcher, overview-header, multisite-dock-tiles
npm run test:php:multisite # payload per role, the overview flag, scoped-desktop cleanup

On a subdirectory multisite (plugin network-activated), as a super admin:

  1. On any site, open Overview: a row above the desktop tiles lists Network Admin and every site, this one lit.
  2. Click Network Admin: the network shell slides in, already in overview, with the network dock and its own desktops; the address bar reads network/admin.php?page=openstation, no flag.
  3. Click a subsite you are not a member of: it lands in its own overview, with its own dock and a fresh Desktop 1 holding its dashboard.
  4. Cmd/ctrl-click a site in the row: a browser tab, and the row keeps the current site lit.
  5. In the network shell, open Sites and click a site's Dashboard link: that site's shell opens with the dashboard as a window, no Space.
  6. As a site admin who belongs to one site only: no row in overview.
  7. Watch a switch: the desk slides out towards the site you picked and the new site's desk slides in from the same side over the wallpaper, which never moves. With reduced motion on, it swaps instantly.
Open WordPress Playground Preview

… overview

On a network each site's shell is a whole instance: its own plugins,
native windows, widgets, dock, desktops and session. Switching site is
a navigation to that site's shell screen, animated by the
cross-document view transition the shell already opts into.

The overview top bar gains a row above the desktop tiles, an
os-segmented naming the network admin (with manage_network) and every
site the user belongs to; a super admin also gets the network's sites,
up to the first 20 by path, and the openstation_multisite_sites filter
picks a different set. Picking one lands in that site's overview
through a one-shot openstation_overview boot arg, read once
server-side and stripped from the address bar like target and intent.
A modifier or middle click opens the site in a browser tab.

Every cross-admin click takes the same hop, so Site Spaces go away:
the scoped desktop, the per-Space dock, the payload quarantine and the
session's scope exception. Desktops persisted with a scope are dropped
on read. The probe's admin-context fix stays, since a live refresh on
the network shell needs it.
The cross-document view transition can only crossfade the root, and
the new page paints its bare desk long before its session restores
and overview opens, so a switch read as a hard cut with the strip and
tiles popping in after the load.

Now the switcher slides the desk out towards the site it picked
(os-shell--hop-out-next / -prev on the shell root, for the beat before
it navigates) and leaves the direction as a one-shot sessionStorage
hint; a shell asked to boot into overview is stamped os-shell--arriving
server-side, so its first paint is the wallpaper alone, and once
overview is up the desk slides in from the same side. No hint (a
cross-origin site) fades instead. The wallpaper never moves.

A desk never stays hidden: a keyframe fallback in the stylesheet and a
boot timer both let it in within seconds if nothing else does, and
reduced motion skips every slide and the wait before navigating.
…nces

# Conflicts:
#	docs/javascript-reference.md
@epeicher
epeicher merged commit a601d7b into trunk Sep 4, 2026
5 checks passed
@epeicher
epeicher deleted the multisite-site-instances branch September 4, 2026 15:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant