An exploratory WordPress plugin for trying out server-aware real-time collaboration in Gutenberg. It provides three candidate sync engines (how the server merges edits from several people) and several transports (how updates move between the editor and WordPress). Each can be selected from a settings screen, so they can be compared on the same site under the same conditions.
This plugin is a decision tool, not a solution. Real-time collaboration was removed from WordPress 7.0, and the concerns behind that decision call for a change in direction: collaboration should run through WordPress, with Core in control. The reasoning is explored in Moving to a server-aware approach for collaboration.
This repository is where candidates are built, measured, and compared so that one can be chosen. The eventual goal is to package the preferred engine as a feature plugin for wider testing.
WordPress 7.0 and the Presence API plugin, which must be active before this plugin can be activated. The wp-env environments and both Playground blueprints install it.
- Install and activate the Presence API.
- Install the latest release zip and activate it. Activation creates the storage tables and turns the Gutenberg "Real-time collaboration" experiment on.
- Open the same post in two browsers as two users and type. Changes appear in the other window within seconds, each window shows the other person's avatar, and when both change the same paragraph at once a review panel offers to restore or dismiss the change that was set aside.
The defaults (the intent-log engine, polling with a WebRTC advisory channel) need nothing from the host. Every option is explained on the settings screen itself. Deactivating the plugin turns collaboration off and keeps the storage tables; deleting it drops them.
The editor sends short descriptions of what changed, such as "move this block". The server keeps an ordered log of these and works out how to combine edits that overlap. Genuine conflicts are set aside for someone to review, so no work is silently lost.
intent-log-data-flow.mov
When two people edit at the same time, the server adjusts the later edit around the earlier one before adding it to the log, so both are adjusted for what each person meant:
intent-log-data-flow-ot.mov
A PHP implementation of Yjs. The server holds a shared document for each post in a format built to merge automatically (a CRDT), merges every update into it, keeps it small by itself, and can produce the post content from it.
yjs-data-flow.mov
Distributed Editing: the server compares three versions of the post, the latest saved version, the editor's proposed version, and the version the editor started from, and combines the changes (a three-way merge). Sync happens on save or autosave, not on every change. Genuine conflicts are flagged for someone to review instead of silently merging.
de-rtc-data-flow.mov
To choose one, and see what each gives up, read docs/engine-comparison.md.
- http-polling: the editor asks the server for updates on a short timer. Every host can run it (default). Beside it, an advisory channel links the browser tabs on one post. It tells each tab who else is here and when to fetch new changes, and it never carries content, so a tab polls only when there is something to fetch. It runs over WebRTC between browsers or over a WebSocket.
- sse: one long-lived response per tab that the server writes each change to (server-sent events), woken by Redis when a Redis address is configured and by half-second storage checks otherwise. Needs a proxy that passes streams through unbuffered.
- sse-daemon: the same stream, written by the sync daemon that the websocket transport runs, on the same port. It holds no PHP worker per tab, and it works where a proxy blocks the WebSocket upgrade.
- websocket: the server pushes updates over a persistent connection
served by a bundled PHP daemon (
wp collaboration sync-server).
docs/transports.md compares them and says what each needs from a host.
Each post's shared editing session (a room) lives in two plugin-owned tables instead of post meta, so no collaboration write touches post caches. Who is present lives in the Presence API's table. Deactivating the plugin keeps the tables and every session; deleting it drops them. See docs/storage.md.
The plugin registers engines and transports with the collaboration
framework in Gutenberg (the @wordpress/sync package and the
lib/experimental/collaboration/ server) through the wp_sync_engines
and wp_sync_transports PHP filters and the registerSyncEngine and
registerSyncTransport JavaScript functions. The server says which
engine and transport to use, and the browser checks that it has them.
If they do not match, the editor uses the classic post lock instead, so
nothing is corrupted. The framework ships no engines and no transports
of its own; without this plugin, collaboration is off.
How an edit travels is in docs/data-flow.md. How to
add an engine or a transport is in docs/protocol.md.
The framework's own design notes are at
gutenberg/prototypes/sync/ARCHITECTURE.md inside this repository's
bundled Gutenberg. Every page is indexed in
docs/README.md.
Moving merge work to the server has a cost, and the point of this
repository is to measure it. npm run bench reports what the plugin
adds to a server on your own hardware, and
npm run bench -- --suite=engines prints the engine comparison. The
benchmarks, the fuzzer, and the debugging tools are described in
tests/benchmarks/README.md,
tests/fuzzer/README.md, and
tests/debugging/README.md.
The framework is maintained in a separate Gutenberg branch and copied
into gutenberg/ as a squashed Git subtree. Each plugin commit pins one
exact framework commit, and the plugin loads this bundled copy when no
standalone Gutenberg plugin is active.
composer install # PHP tooling
npm install # Plugin dependencies
cd gutenberg && npm ci --ignore-scripts && npm run build && cd ..
npm run build # Plugin client bundle
npm run env start # Start WordPress at http://localhost:8888
npm run env:stop # Stop it (and the Redis container)
npm run test:js # Jest
npm run test:php # PHPUnit in the wp-env tests container
npm run test:e2e # Playwright, two-browser collaborationnpm run playground serves the built checkout on a local WordPress
Playground instead. AGENTS.md is the full guide to working in the
repo: environments, the test ladder, diagnostics, and the traps.
To type in a second window by yourself, see
tests/tools/README.md.
This plugin is maintained by the WordPress Core team, with contributions from the community. The maintainers are:
- Chris Zarate (@chriszarate)
- Alec Geatches (@alecgeatches)
- Joe Fusco (@josephfusco)
Open GitHub issues or discuss in #feature-realtime-collaboration channel in
WordPress Slack. To contribute, see
CONTRIBUTING.md.