# Multisite

Multisite is a first-class surface in Divine, not a special case bolted onto a single-site product. On a single-site install Divine lives in the normal admin and treats the one active theme as the workspace. On a multisite network it moves to network admin and treats every network site as its own app, keyed by `blog_id`. The model is the same in both places: an app is a theme you build inside. Multisite only changes how many apps there are and which capability gates them.

## Single Site Versus Multisite

Divine detects the install type with `is_multisite()` and registers exactly one admin surface for it. The detection is automatic; you do not configure a mode.

On a single-site install, Divine registers under the normal admin menu, gates on `manage_options`, and hides the multi-app sidebar because there is only one app to build. The active theme is that single app.

On a multisite network, Divine registers under the network admin menu, gates on `manage_network`, and shows the multi-app sidebar listing the network's sites. Divine deliberately registers on only one of the two surfaces: on multisite it bails out of the normal per-site admin so the workspace lives in network admin alone, where managing themes across the network belongs.

| Aspect | Single site | Multisite |
| --- | --- | --- |
| Admin location | Normal wp-admin | Network admin |
| Management capability | `manage_options` | `manage_network` |
| Multi-app sidebar | Hidden | Visible |
| Apps | The one active theme | One per network site |
| Create-app action | Hidden | Links to native site creation |

Because the capability differs, an account that can open Divine on a single-site install will not necessarily see it on a network. Reaching the network admin workspace requires `manage_network`, which is the super admin capability, so the people who manage themes across the whole network are the ones who reach Divine there.

## One Site Is One App

On a network, each site is one Divine app, and that app is the site's active theme. Divine builds the app list from `get_sites()`, so the sidebar reflects the real network rather than a separate Divine-owned list of workspaces. Adding a site to the network adds an app; the list stays in step with WordPress.

Each app has a stable slug derived from the site's `blog_id`:

```text
site-{blog_id}
```

So `blog_id` 1 is the app `site-1`, `blog_id` 5 is `site-5`, and so on. The app carries the site's active stylesheet, its template, a label drawn from the site's name (falling back to the theme name), and the site's domain and path. The label and domain are presentation; the `blog_id` is identity. Two sites running the same theme are still two distinct apps because they have different blog IDs.

## blog_id Is Part Of Every Operation

On multisite, `blog_id` is woven through the workspace, not just the app list. It is part of the workspace identity, the preview session, the signed preview token, and the deploy target. Every Divine action that touches a theme on a network resolves which site it is acting on first, then operates inside that site's context.

This matters most for deploy. Deploy promotes accepted worktree files into an app theme, and on multisite it targets the selected site's active theme only. It never fans out across the network and never touches another site's theme, even when several sites share the same stylesheet name. Deploy remains files-only here as everywhere in Divine: it mirrors theme files and never copies posts, options, uploads, or any database state between sites.

Previews are scoped the same way. A signed preview renders a theme for one request against one site's data, and the token is bound to that site. A preview issued for one network site does not render against another site's content.

Per-site behavior like this lives in Divine's own app and runtime plumbing rather than in the shared preview service-worker kit, so that adding a site or switching the targeted blog stays a Divine concern and does not push network-specific logic into shared code.

## Divine Does Not Create Sites

Divine links to WordPress's own site creation; it is not a hosting product or a custom site provisioner. On a network the create-app action opens the native network admin Add New Site screen rather than running a Divine-specific provisioning flow. You create and configure network sites through WordPress, assign each one a theme, and Divine then surfaces each site as an app you can build. Divine owns the theme workspace, and WordPress owns the network.

## Resolving A Site From The CLI

The `dv show` command builds capturable render URLs, and on a network it has to know which site it is rendering against. It resolves the target subsite in one of three ways.

When exactly one network site runs the theme you are working in, `dv show` resolves that site automatically from the theme path. You do not have to name a site when the mapping is unambiguous.

When the theme is ambiguous, or you want a specific site, name it explicitly. Pass `--site` with a slug or numeric blog ID, or pass `--url` with the site's URL. The two are mutually exclusive; use one or the other.

```bash
dv show page home --site 5
dv show page home --site site-5
dv show page home --url https://network.example/team-blog/
```

If the named site is not part of the network, `dv show` reports that the network site was not found rather than rendering against the wrong place. Passing `--site` on a single-site install is rejected, because there is no network to select from. When you do not name a site and the theme maps cleanly to one, automatic resolution handles it; when it does not, naming the site keeps the render unambiguous.

For the broader set of `dv show` resolution problems, including running outside a WordPress context and the database-connection failures common to local stacks, see [Operations and Troubleshooting](operations-and-troubleshooting).
