Building a Custom Sync Provider in WordPress 7.0

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_post capability 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.

author avatar
Ahmad Wael
I'm a WordPress and WooCommerce developer with 15+ years of experience building custom e-commerce solutions and plugins. I specialize in PHP development, following WordPress coding standards to deliver clean, maintainable code. Currently, I'm exploring AI and e-commerce by building multi-agent systems and SaaS products that integrate technologies like Google Gemini API with WordPress platforms, approaching every project with a commitment to performance, security, and exceptional user experience.

Leave a Comment