WordPress 7.0 is finally bringing real-time collaboration to the block editor, and while the default HTTP polling transport is a safe bet for most, it’s going to be a bottleneck for high-traffic environments. Consequently, if you are a WordPress hosting provider or managing a site with heavy editorial workflows, you will eventually need to build a custom sync provider to maintain performance.
The standard implementation uses periodic HTTP requests to sync document state. However, polling generates unnecessary server load and introduces noticeable latency. In contrast, a WebSocket-based approach provides the “Google Docs-like” experience clients actually expect. I’ve seen enough “race condition” tickets to know that when four editors jump into a post simultaneously, those 1-second polling intervals start to feel like an eternity.
Why You Need a Custom Sync Provider
The default provider is built for compatibility, not speed. It batches updates every four seconds (or every second if others are present). Therefore, it works on the cheapest shared hosting, but it fails the “real-time” smell test. By building a custom sync provider, you can leverage WebSockets for instant updates and reduced overhead. Specifically, you only send data when a change occurs, rather than asking the server “any news?” every thousand milliseconds.
Before you dive in, you should check out the WordPress 7.0 stability testing notes to see how the core team is handling these document states. Furthermore, be aware that broken meta boxes can often disrupt the sync flow entirely if not handled correctly.
The Mechanics: Yjs and the Sync Manager
Real-time collaboration in WordPress is powered by Yjs, a high-performance CRDT library. The sync provider acts as the transport layer for these document updates. To swap the default transport, we use the sync.providers client-side filter. This filter expects a “provider creator” function—an async function that initializes your connection and returns a cleanup method.
import { addFilter } from '@wordpress/hooks';
import { WebsocketProvider } from 'y-websocket';
addFilter( 'sync.providers', 'bbioon/websocket-sync', () => {
return [
async ( { objectType, objectId, ydoc, awareness } ) => {
// Define a unique room for the post/entity
const roomName = `${ objectType }-${ objectId ?? 'collection' }`;
// Initialize the WebSocket provider
const provider = new WebsocketProvider(
'wss://sync.example.com',
roomName,
ydoc,
{ awareness }
);
return {
destroy: () => provider.destroy(),
on: ( event, callback ) => provider.on( event, callback ),
};
},
];
} );
Security: Don’t Ship Naked Connections
The code above is a “happy path” example. In the real world, connecting a client directly to a WebSocket server without authorization is a disaster waiting to happen. Since your sync server lives outside the standard WordPress PHP lifecycle, it doesn’t know who the user is. Therefore, you must implement token-based authentication.
A common architectural pattern is to fetch a short-lived JWT via the WordPress REST API and pass it as a query parameter during the WebSocket handshake. If the token is invalid or expired, the server should immediately drop the connection. For a production-grade example, look at how the WPVIP Real-Time Collaboration plugin handles its auth lifecycle.
Server-Side Validation Checklist
- Validate per-document: Don’t just check if the user is “logged in.” Verify they have the
edit_postcapability for that specific ID. - Rotate tokens: Keep TTLs short. Re-authenticate on every reconnect.
- Sanitize updates: While Yjs is robust, never trust raw data from the client without basic integrity checks.
Look, if this custom sync provider stuff is eating up your dev hours, let me handle it. I’ve been wrestling with WordPress since the 4.x days, and I’ve seen exactly how these real-time systems break under pressure.
Final Takeaway
Building a custom sync provider in WordPress 7.0 isn’t just about reducing latency; it’s about making the editor feel professional. While the sync.providers filter makes the implementation straightforward, the real work lies in your server infrastructure and security model. If you’re using y-websocket, ensure your Node.js backend is horizontally scalable, or you’ll just trade HTTP bottlenecks for WebSocket ones.