[Website] Accept ZIP drops across the page - #4121
Merged
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR updates Playground ZIP export/import to round-trip complete site state (including user-owned wp-content and wp-config.php) while preserving runtime-managed files, and improves the website ZIP import UX with drag-and-drop plus progress reporting.
Changes:
- Export now produces a “formatVersion: 2” ZIP containing full
wp-content,wp-config.php, and a manifest; import treats that content as authoritative while retaining Playground runtime files and restoring omitted stock files for legacy exports. - Website import flow now imports into first-boot MEMFS before the initial OPFS copy, supports click/drop, and reports phase + real persistence progress inline.
- Replaces the public
wpContentFilesExcludedFromExportexport withplaygroundRuntimeWpContentPathsand updates call sites/tests accordingly.
Reviewed changes
Copilot reviewed 22 out of 27 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/playground/website/src/lib/state/redux/site-management-api-middleware.ts | Adds ZIP-to-new-site creation, first-boot initialization integration, and OPFS sync progress reporting. |
| packages/playground/website/src/lib/state/redux/site-first-boot-initializer.ts | Introduces a registry to run initialization work before the first OPFS copy. |
| packages/playground/website/src/lib/state/redux/boot-site-client.ts | Runs first-boot initializers during client boot and reports OPFS sync error on initializer failure. |
| packages/playground/website/src/lib/state/redux/boot-site-client.spec.ts | Adds coverage ensuring the initializer runs before the initial OPFS copy. |
| packages/playground/website/src/github/import-from-github.ts | Switches to new runtime-path list and changes restore semantics for runtime-managed files. |
| packages/playground/website/src/github/github-export-form/form.tsx | Updates export exclusion list to the new runtime-paths constant. |
| packages/playground/website/src/github/github-export-form/form.spec.tsx | Updates mocks to new export symbol name. |
| packages/playground/website/src/components/toolbar-buttons/download-as-zip.tsx | Updates ZIP download to use the new complete export behavior. |
| packages/playground/website/src/components/saved-playgrounds-panel/style.module.css | Adds styles for drag-and-drop ZIP import UI and inline progress/error state. |
| packages/playground/website/src/components/saved-playgrounds-panel/index.tsx | Reworks ZIP import UX: dropzone, inline progress/errors, and new-site-from-ZIP import path. |
| packages/playground/website/playwright/e2e/opfs.spec.ts | Updates e2e flows for new import UI and verifies persistence of customized theme files after reboot. |
| packages/playground/remote-access/src/remote-access-direct-tunnel.ts | Updates remote tunnel ZIP export to use the new complete export behavior. |
| packages/playground/personal-wp/src/lib/hooks/use-backup.ts | Updates personal-wp backup ZIP export to use the new complete export behavior. |
| packages/playground/blueprints/src/tests/steps/import-wordpress-files.spec.ts | Adds tests for complete exports, runtime file retention, and legacy export restoration behavior. |
| packages/playground/blueprints/src/lib/utils/wp-content-paths.ts | Defines runtime-managed wp-content paths and legacy omitted user paths. |
| packages/playground/blueprints/src/lib/utils/wp-content-files-excluded-from-exports.ts | Removes the old excluded-paths list. |
| packages/playground/blueprints/src/lib/steps/zip-wp-content.ts | Makes ZIP export “complete” by default, adds manifest formatVersion: 2, includes wp-config.php. |
| packages/playground/blueprints/src/lib/steps/index.ts | Re-exports the new runtime-paths constant instead of the old excluded list. |
| packages/playground/blueprints/src/lib/steps/import-wordpress-files.ts | Adds format-version handling, runtime-file retention, legacy restoration, and progress tracker captions/percentages. |
| packages/playground/blueprints/src/index.ts | Re-exports the new runtime-paths constant publicly. |
| packages/playground/blueprints/public/blueprint-v2-schema-validator.js | Updates generated schema refs (validator artifact). |
| packages/playground/blueprints/public/blueprint-schema.json | Updates generated schema refs (schema artifact). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
adamziel
force-pushed
the
adamziel/improve-zip-import-ux
branch
2 times, most recently
from
July 20, 2026 19:26
0c06b2c to
e3addef
Compare
adamziel
force-pushed
the
adamziel/improve-zip-import-ux
branch
7 times, most recently
from
July 21, 2026 00:41
9e03807 to
d3313f1
Compare
adamziel
force-pushed
the
adamziel/improve-zip-import-ux
branch
from
July 21, 2026 01:35
d3313f1 to
2b41603
Compare
adamziel
force-pushed
the
adamziel/improve-zip-import-ux
branch
from
July 21, 2026 10:33
2b41603 to
8dc1886
Compare
adamziel
force-pushed
the
adamziel/zip-import-progress
branch
2 times, most recently
from
July 21, 2026 10:51
4df3e25 to
a27aaa9
Compare
adamziel
force-pushed
the
adamziel/improve-zip-import-ux
branch
from
July 21, 2026 10:51
8dc1886 to
206c30c
Compare
adamziel
force-pushed
the
adamziel/improve-zip-import-ux
branch
from
July 21, 2026 11:13
206c30c to
6c27c56
Compare
adamziel
force-pushed
the
adamziel/zip-import-progress
branch
from
July 21, 2026 11:16
32ef0d7 to
ab958d7
Compare
adamziel
force-pushed
the
adamziel/improve-zip-import-ux
branch
from
July 21, 2026 11:16
6c27c56 to
639dc00
Compare
adamziel
force-pushed
the
adamziel/zip-import-progress
branch
from
July 21, 2026 12:20
ab958d7 to
9d68a74
Compare
adamziel
force-pushed
the
adamziel/improve-zip-import-ux
branch
2 times, most recently
from
July 21, 2026 12:28
bc593a8 to
ccd8a87
Compare
adamziel
force-pushed
the
adamziel/zip-import-progress
branch
from
July 21, 2026 12:28
9d68a74 to
c864646
Compare
adamziel
force-pushed
the
adamziel/improve-zip-import-ux
branch
from
July 21, 2026 12:40
ccd8a87 to
7337ca0
Compare
adamziel
force-pushed
the
adamziel/zip-import-progress
branch
2 times, most recently
from
July 21, 2026 12:50
63a41a9 to
2b0a33c
Compare
adamziel
force-pushed
the
adamziel/improve-zip-import-ux
branch
from
July 21, 2026 12:50
7337ca0 to
24a9426
Compare
adamziel
added a commit
that referenced
this pull request
Jul 21, 2026
… defaults (#4130) A version-2 Playground ZIP now defines user-owned `wp-content`: archived files replace the boot defaults, and a missing user file means it was deleted. Legacy runtime artifacts remain owned by the importing Playground through #4141. Pre-versioned exports remain partial. When one omits a stock plugin, theme, or database directory, import retains the fresh installation's copy. An archived copy still wins when present. This preserves customized default themes such as BrewCommerce's purple Twenty Twenty-Five background through export, import, and reload without treating stock themes as runtime files. ## Testing Browser coverage imports a pre-versioned partial export, then separately customizes Twenty Twenty-Five, exports it, imports it into a new Playground, reloads, and checks both the theme file and rendered background. The full stack passes 488 Blueprint tests, 347 website tests, both packages' lint and typecheck, and 10 Chromium ZIP-import scenarios. ## Stack 1. [#4139 — Export complete versioned Playground ZIP snapshots](#4139) 2. [#4141 — Exclude legacy runtime artifacts from site snapshots](#4141) 3. [#4130 — Import versioned ZIP user content while retaining legacy defaults](#4130) 4. [#4131 — Import ZIP contents before initial browser persistence](#4131) 5. [#4132 — Keep ZIP preparation visible until the imported site is ready](#4132) 6. [#4121 — Accept ZIP drops across the page](#4121)
adamziel
force-pushed
the
adamziel/zip-import-progress
branch
from
July 21, 2026 13:45
2b0a33c to
2bba7ff
Compare
adamziel
force-pushed
the
adamziel/improve-zip-import-ux
branch
from
July 21, 2026 13:46
24a9426 to
7c67c5d
Compare
adamziel
added a commit
that referenced
this pull request
Jul 21, 2026
… defaults (#4130) A version-2 Playground ZIP now defines user-owned `wp-content`: archived files replace the boot defaults, and a missing user file means it was deleted. Legacy runtime artifacts remain owned by the importing Playground through #4141. Pre-versioned exports remain partial. When one omits a stock plugin, theme, or database directory, import retains the fresh installation's copy. An archived copy still wins when present. This preserves customized default themes such as BrewCommerce's purple Twenty Twenty-Five background through export, import, and reload without treating stock themes as runtime files. ## Testing Browser coverage imports a pre-versioned partial export, then separately customizes Twenty Twenty-Five, exports it, imports it into a new Playground, reloads, and checks both the theme file and rendered background. The full stack passes 488 Blueprint tests, 347 website tests, both packages' lint and typecheck, and 10 Chromium ZIP-import scenarios. ## Stack 1. [#4139 — Export complete versioned Playground ZIP snapshots](#4139) 2. [#4141 — Exclude legacy runtime artifacts from site snapshots](#4141) 3. [#4130 — Import versioned ZIP user content while retaining legacy defaults](#4130) 4. [#4131 — Import ZIP contents before initial browser persistence](#4131) 5. [#4132 — Keep ZIP preparation visible until the imported site is ready](#4132) 6. [#4121 — Accept ZIP drops across the page](#4121)
adamziel
added a commit
that referenced
this pull request
Jul 21, 2026
…me files (#4141) Make new ZIP exports preserve the site’s plugins, themes, uploads, and database exactly. Make imports remove any pre-bundled Playground's runtime files (such as `0-playground.php` mu-plugin) and lean on their latest versions shipped in the `/internal` directory. ## Backwards compatibility Playground's ZIP export format evolved over time. Here's how each version is handled after this PR: | ZIP | Site files in `wp-content` | Playground runtime artifacts | If a theme or plugin is missing | | --- | --- | --- | --- | | Before this PR | Custom plugins, themes, and uploads. Default `themes/twenty*` directories were included only by the self-contained export. `database/` may be absent. | Some January–May 2024 ZIPs contain the old SQLite MU plugin. | Backfill well-known paths from the site loaded right before the import: Akismet, Hello Dolly, WordPress Importer, default themes, and `database/`. This is a best-effort heuristic. We can't distinguish a deleted theme from a missing theme. | | `formatVersion: 2` after this PR | Every site path then on disk: plugins, themes, uploads, `database/`, and a custom `db.php` if the user specifically created one. | None. | Leave it missing. | On every import, archived Playground files are removed. The new Playground supplies them. ## Playground runtime files These four old paths are always treated as Playground-provided runtime files: - `mu-plugins/sqlite-database-integration` - `mu-plugins/playground-includes` - `mu-plugins/0-playground.php` - `mu-plugins/0-sqlite.php` From January 29 through May 8, 2024, the self-contained exporter included `mu-plugins/sqlite-database-integration`. It also included `mu-plugins/0-sqlite.php` when present. It already omitted `mu-plugins/0-playground.php` and `mu-plugins/playground-includes`; those entries handle stale sites, GitHub trees, and hand-built ZIPs. `db.php` needs a separate rule because it can be a custom WordPress drop-in. During legacy WordPress boot, `writeLegacyDbPhp()` creates Playground's copy through `generateDbPhpContent()`. That function writes `@playground-managed` into the file header. Only a `db.php` with that marker is treated as a Playground file. An unmarked `db.php` stays with the site. Before January 29, 2024, SQLite used `plugins/sqlite-database-integration`. This PR leaves that path as site content because it is also a valid user-installed plugin path. **Breaking change:** `wpContentFilesExcludedFromExport` is no longer public. `getLegacyPlaygroundRuntimeWpContentPaths()` exposes the smaller runtime rule. ## Testing Tests cover a modified Twenty Twenty-Five theme, a deleted v2 theme, a theme omitted by a pre-v2 ZIP, archived runtime files, marked and custom `db.php` files, failed runtime staging, and archives without `wp-content`. The full stack passes 488 Blueprint tests, 347 website tests, package lint and typecheck, and 10 Chromium ZIP-import scenarios. ## Stack 1. [#4139 — Export complete versioned Playground ZIP snapshots](#4139) — merged 2. [#4141 — Exclude legacy runtime artifacts from site snapshots](#4141) — includes #4130 3. [#4131 — Import ZIP contents before initial browser persistence](#4131) 4. [#4132 — Keep ZIP preparation visible until the imported site is ready](#4132) 5. [#4121 — Accept ZIP drops across the page](#4121)
adamziel
added a commit
that referenced
this pull request
Jul 21, 2026
ZIP imports used to persist a fresh WordPress installation before applying the archive. The archive then rewrote that stored filesystem: 1. Boot fresh WordPress in MEMFS. 2. Copy the fresh site to browser storage. 3. Apply the ZIP to the running site. 4. Flush the rewritten site to browser storage again. This PR applies the ZIP during the new site's first boot, before its initial browser-storage copy: 1. Boot fresh WordPress in MEMFS. 2. Apply the ZIP in MEMFS. 3. Copy the finished filesystem to browser storage once. `createNewSiteFromZip()` registers the import as first-boot work. The boot path runs that work before the initial MEMFS-to-OPFS copy, and the call reports success only after that copy finishes. If ZIP initialization or the first OPFS copy fails, the newly created stored site is removed and the previously active Playground is selected again. When OPFS is unavailable, the import uses a fresh temporary Playground. Its new slug forces React to boot a new iframe instead of reusing the previous runtime. The ZIP picker now delegates this lifecycle to `createNewSiteFromZip()` instead of coordinating site creation, client boot, import, and persistence through component effects. This PR does not change which files a ZIP contains or how versioned and legacy ZIP contents are interpreted. Those rules are handled by #4141 and #4130. This PR changes when the imported filesystem is written to browser storage. ## Testing 1. Import a ZIP from both temporary and saved Playgrounds and confirm the new site persists after reload. 2. Import a malformed ZIP and confirm no incomplete stored site remains. 3. Confirm the previously active Playground remains selected after a failed stored-site import. Unit coverage checks that ZIP initialization runs before the initial OPFS copy and that failed-import cleanup selects the requested previous site once. Browser coverage checks that a failed import leaves the stored-site list unchanged, including after reload. ## Stack 1. [#4139 — Export complete versioned Playground ZIP snapshots](#4139) — merged 2. [#4141 — Export and import all site files except Playground runtime files](#4141) — merged 3. [#4130 — Import versioned ZIP user content while retaining legacy defaults](#4130) — merged 4. [#4131 — Import ZIP contents before initial browser persistence](#4131) 5. [#4132 — Keep ZIP preparation visible until the imported site is ready](#4132) 6. [#4121 — Accept ZIP drops across the page](#4121)
adamziel
force-pushed
the
adamziel/zip-import-progress
branch
from
July 21, 2026 20:37
9c56cbf to
fe7b422
Compare
adamziel
force-pushed
the
adamziel/improve-zip-import-ux
branch
4 times, most recently
from
July 21, 2026 22:43
6bbde70 to
2c2fa98
Compare
adamziel
force-pushed
the
adamziel/zip-import-progress
branch
2 times, most recently
from
July 24, 2026 17:14
01522ad to
24e6693
Compare
adamziel
force-pushed
the
adamziel/improve-zip-import-ux
branch
from
July 24, 2026 22:09
2c2fa98 to
4193c51
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The ZIP import tab now has a large click target. While that tab is open, dragging a file anywhere over the page shows a stable full-page drop overlay without changing a word in the panel. A non-ZIP drop stays in the panel and reports the problem inline.
The small-breakpoint screenshots document the responsive layout; touch users keep the click-to-choose path.
Screenshots
Desktop drag target
Small-breakpoint layout
Testing