WordPress Playground-inspired model¶
What WordPress Playground means here¶
This repository does not embed WordPress itself. Instead, it uses WordPress Playground's @php-wasm/web runtime to run Omeka S entirely in the browser.
That means WordPress Playground matters here in two ways:
- Conceptually: it is the reference architecture for browser-native PHP application bootstrapping.
- Practically: it provides the PHP WASM runtime, and informs how this repository handles runtime setup, ephemeral state, blueprints, and contributor workflows.
If you know WordPress Playground already, the mental model is similar: an application ZIP bundle is extracted into writable MEMFS, bootstrapped from a blueprint, and served through a service worker.
How the project uses the Playground model¶
The runtime flow is:
index.html
-> src/shell/main.js
-> remote.html
-> src/remote/main.js
-> sw.js
-> php-worker.js (bundled via esbuild into dist/)
-> src/runtime/php-loader.js (@php-wasm/web)
-> src/runtime/php-compat.js (API wrapper)
-> src/runtime/bootstrap.js
-> src/runtime/vfs.js (ZIP extraction)
-> src/runtime/crash-recovery.js
The main WordPress Playground-style patterns are:
- Browser PHP runtime using
@php-wasm/weband@php-wasm/universal - Multiple PHP versions (8.1, 8.2, 8.3, 8.4, 8.5) selectable from the UI
- Service-worker routing so same-origin browser requests can be served by the in-browser PHP process
- ZIP bundle extraction into writable MEMFS at boot
- Portable blueprint input to describe initial state declaratively
- Crash recovery that snapshots DB and addons before WASM crashes
Initialization lifecycle¶
On each page load, the runtime:
- downloads and extracts the Omeka ZIP bundle from
assets/omeka/ - writes all files into
/www/omekain MEMFS - prepares writable directories under
/persist - writes database and local configuration
- installs Omeka if needed
- applies the active blueprint
- logs in automatically when
autologinis enabled
All state is ephemeral — closing the tab destroys everything. Each page load boots a fresh instance.
What depends on the Playground model¶
The following areas depend directly on this architecture:
sw.js: maps browser requests into the scoped runtime and rewrites HTML responses for the Pages subpathphp-worker.js: owns the PHP worker lifecycle and crash recoverysrc/runtime/php-loader.js: creates PHP runtime via@php-wasm/websrc/runtime/php-compat.js: wraps the @php-wasm API for Omeka's bootstrapsrc/runtime/bootstrap.js: applies the blueprint and installs Omekasrc/runtime/vfs.js: extracts the ZIP bundle into MEMFSsrc/runtime/crash-recovery.js: WASM crash detection, DB snapshot/restorelib/omeka-loader.js: downloads and caches the ZIP bundlesrc/shared/blueprint.js: normalizes blueprint input before boot
When contributors change any of those areas, they should think in Playground terms: ephemeral MEMFS, ZIP extraction, and idempotent boot steps.
Working locally and in the browser¶
Local development¶
- Use
make serveto start the local server. - Use
make upwhen you need the full dependency, prepare, bundle, and serve flow. - Expect the local dev server to expose the addon proxy endpoint configured by
addonProxyPath.
Browser behavior¶
- All state is ephemeral (MEMFS). Closing the tab destroys everything.
- Importing a blueprint triggers a clean boot.
- The shell UI stores session state such as the active path and runtime selection.
- The settings panel (⚙️) allows switching PHP versions.
- Runtime navigation happens inside the iframe, while Home, Admin, and Docs buttons are in the toolbar.
Constraints and caveats¶
These are the main project-specific constraints contributors should keep in mind:
- The public deployment runs under the GitHub Pages subpath
/omeka-s-playground, not/. - Omeka-generated HTML may contain escaped URLs, so routing and rewriting logic must stay conservative.
- Remote addon ZIP downloads often need the configured proxy because many upstream hosts do not provide CORS headers suitable for browser fetches.
- Browser compatibility is focused on Chromium-class browsers first.
- The
@php-wasm__private__dont__useAPI is used for low-level FS access; pin package versions.
Practical workflows¶
Change demo content¶
Edit assets/blueprints/default.blueprint.json, then reload with a clean scope or reset the current scope.
Debug install-time issues¶
Set debug.enabled to true in the blueprint, reproduce the clean boot, and inspect shell logs plus the PHP Info tab.
Add a module or theme¶
Use the blueprint's modules or themes arrays and prefer stable, clearly named entries. For remote ZIPs, verify the URL will work with the configured proxy rules.
Recommended habits¶
- Keep boot logic declarative through the blueprint whenever possible.
- Prefer small blueprint changes over hidden imperative install logic.
- Validate both first boot and reload behavior after changing runtime or routing code.
- Document any new assumptions in these docs at the same time as the code change.