Announcing a collaborative editing outreach effort for 7.1

A new dedicated outreach effort is underway for WordPress 7.1 to ensure collaborative editing gets the collaborative testing it needs. Please join #collaborative-editing-outreach in WordPress SlackSlack Slack is a Collaborative Group Chat Platform https://slack.com/. The WordPress community has its own Slack Channel at https://make.wordpress.org/chat/ (steps to sign up here) if you:

  • Want to use collaborative editing on a regular basis.
  • Enjoy being an early adopter.
  • Feel comfortable using the latest version of the GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses ‘blocks’ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/ pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party..
  • Have the ability to participate through the 7.1 cycle (at least until 8/18/26).

Thanks in advance for helping shape the future of this feature.

Why now?

Collaborative features require an inherently collaborative way of testing. For the 7.0 cycle, a lot of time and effort was spent with more developer oriented testing, enterprise level testing, and deterministic testing with hosts. While incredibly useful, this effort broadens the scope of testing by bringing in passionate real-world early adopters across a range of hosting environments and backgrounds. For collaborative editing to truly succeed, it’s important to go beyond just getting stability, performance, and reliability right.

In running the FSE Outreach Program, I saw how powerful it was to have a dedicated space for folks to regularly interact with those building the feature for a faster feedback loopLoop The Loop is PHP code used by WordPress to display posts. Using The Loop, WordPress processes each post to be displayed on the current page, and formats it according to how it matches specified criteria within The Loop tags. Any HTML or PHP code in the Loop will be processed on each post. https://codex.wordpress.org/The_Loop in the right direction. After the hard decision was made to remove collaborative editing from WordPress 7.0, the aim is that ahead of 7.1 the outreach program model provides enough structure to create meaningful feedback without being too overbearing or exclusive considering the timeframe. This was first discussed in #feature-realtime-collaboration before being brought to project leadership. 

Who can join?

Anyone is welcome to join #collaborative-editing-outreach! Real Time Collaboration is included in the latest versions of Gutenberg, and can be enabled under `Settings > Writing` in the dashboard when the Gutenberg plugin is active.

It’s critical people from across different hosting environments and use cases are a part of this, from nonprofits to small businesses to newsrooms. If you have a large need for collaborative editing, enjoy sharing feedback, and are comfortable with using the latest Gutenberg plugin, this is an awesome way to contribute to the WordPress project. Test team badges will be given out at the end. 

More about the effort

The aim is to engage passionate real-world early adopters across a spread of hosting environments in a dedicated slack channel throughout the release process to ensure a tight feedback loop for both bugs and feature requests. This will take a simple form: a dedicated slack channel (#collaborative-editing-outreach) where folks can get set up with collaborative editing, share ongoing feedback, and those working on the feature can open bugs/make fixes/share improvements/etc. Compared to the FSE Outreach Program, there won’t be ongoing themed calls for testing since they would end up being very repetitive. Instead, key updates will be shared in the slack channel to help inform folks as new fixes or features are added to give feedback on them. The latest updates for collaborative editing will be delivered through the Gutenberg plugin which is why using the latest version is a requirement for this channel. As discussed here, a featured plugin isn’t currently feasible. 

Tied to this, outreach will be done to hosting companies to attempt to recruit participants for this outreach program. This is being done to help get as many different environments as possible represented. 

Currently, @amykamala, @greenshady, and I will be acting as the small crew driving this forward in the slack channel, alongside the developers and designers working on this feature. 

Questions? Comments? Concerns?

Please leave them below. Thanks for engaging.

Thank you to @amykamala @greenshady @maxschmeling for reviewing this post. 

#7-1, #collaboration, #feature-real-time-collaboration, #gutenberg, #phase-3

Results: Real Time Collaboration performance testing analysis

Following the decision to remove real-time collaboration from WordPress 7.0, this post summarizes what the latest hosting test data showed and outlines the recommended storage strategy for future iteration. A huge thank you to every web host that submitted results in response to last week’s call for testing. Submissions came in from eight hosting environments between April 29 and May 4, and analysis of the aggregated, anonymized data is now complete. Based on the results, the recommendation is to use custom-table-with-transients as the default RTC storage strategy for continued testing and future iteration.

As a reminder, four candidate storage strategies for the Real Time Collaboration (“RTC”) feature were tested under load:

  • post-meta — the RC2 baseline.
  • custom-table — a dedicated table for all RTC data.
  • post-meta-transients — post metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress. for storage with transients for client awareness.
  • custom-table-with-transients — a dedicated table with an object cache-backed awareness (Note: while contributors have been referring to this as a transient approach, it is a convenient short hand rather than a technical description)

The test runner captured per-request REST dispatch time and database query counts during sustained 30-second polling windows. Eight complete captures from a mix of shared, shared-with-Redis, managed-cloud, and no-object-cache environments form the basis of the analysis below.

What the data showed

Across the cohort, custom-table-with-transients was first or tied-first on six of seven complete environments, and was never slower than the RC2 baseline (post-meta approach). On average, the custom-table-with-transients approach was ~52% faster and the purely custom-table approach was ~37% faster than the current implementation. On hosts without a persistent object cache, it landed within 0.05–0.17 ms of plain custom-table—close enough that the two are effectively tied where caching is absent.

Two clean signals showed up in the database query counts during dispatch:

  1. With a persistent object cache present, both transient-based strategies dropped to a single database query per dispatch.
  2. Independent of caching, the custom-table schema cut the query count roughly in half compared to the post-meta strategies.

custom-table-with-transients wins because it gets the schema reduction when caching is absent, and the cache reduction when it’s present. post-meta-transients, by contrast, is not recommended even as a fallback. It nearly doubles in latency without a persistent cache, and on one no-cache shared environment it exhibited a pathological transient code path that pushed dispatch latency past 26 ms — several times worse than any other strategy on that host.

Recommendation for the future

The recommended storage strategy custom-table-with-transients is considered the best case among the candidates. It wins decisively on environments with a persistent object cache, remains comfortably ahead of the baseline on environments without one, and degrades gracefully across the full spread of hosting tiers represented in the data.

Read the full analysis

The full anonymized analysis—including per-environment dispatch tables, query counts, cross-cuts comparing cache effects, and bootstrap floors—is available here. All submissions remain anonymized in line with the commitment made in the original call for testing.

Summary

The data from this testing window was sufficient to make the call confidently: custom-table-with-transients is the best option forward as the default for real time collaboration. When work resumes after clean up from 7.0, this is the approach best positioned to explore more deeply next.

Thank you again to every host that participated. Your contributions provided the data needed to make this storage recommendation and will help set real-time collaboration up for success across the wide range of environments where WordPress runs. Props to Ionos, BlueHost, Kinsta, XServer, and WordPress.comWordPress.com An online implementation of WordPress code that lets you immediately access a new WordPress environment to publish your content. WordPress.com is a private company owned by Automattic that hosts the largest multisite in the world. This is arguably the best place to start blogging if you have never touched WordPress before. https://wordpress.com/ for their contributions here.

Props to @griffbrad for drafting this post. Props to @dd32 @desrosj @jmdodd @peterwilsoncc @jorbin @4thhubbard for testing, analysis, and review. If I missed your name, please tell me as it’s a mistake and there have been a lot of moving pieces.

#feature-real-time-collaboration

Real-time collaboration will not ship in WordPress 7.0

Today, @matt made the decision to remove real-time collaboration from WordPress 7.0 and shared that he is not confident the current approach is robust enough to include in CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. at this time, citing concerns around surface area, race conditions, server load, memory efficiency, and recurring bugs found through fuzz testing.

This is a difficult decision, especially given the amount of work that has gone into the feature, but it is being made in service of shipping a stable and reliable WordPress 7.0 release for our users. Work to remove the feature from the release is being organized in #65205 and in the #feature-realtime-collaboration. At this time, the release schedule remains as is and further updates will be provided if the schedule needs to change to unwind this feature.

Real-time collaboration remains an important and exciting feature for WordPress. Once the immediate release work is complete, a plan will be shared for broader testing and continued iteration to help prepare the feature for a future release. Thank you to everyone who has contributed to this work so far from so many angles.

#7-0, #feature-real-time-collaboration

Building a custom sync provider for real-time collaboration

Real Time Collaboration was removed from the scope of WordPress 7.0 before RC3.

WordPress 7.0 will introduce real-time collaboration in the blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. editor. Out of the box, the editor syncs changes between peers using an HTTPHTTP HTTP is an acronym for Hyper Text Transfer Protocol. HTTP is the underlying protocol used by the World Wide Web and this protocol defines how messages are formatted and transmitted, and what actions Web servers and browsers should take in response to various commands. polling provider. However, an HTTP polling transport isn’t the only option and it may not be the best fit for your infrastructure, especially if you are a WordPress hosting provider.

The sync.providers client-side filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. proposed for WordPress 7.0 lets you replace the default transport with your own. This post walks through why you’d want to use one, what a provider does, and how to build one.

Why build a custom provider?

The default HTTP polling provider is designed to work on any WordPress installation. It batches document and awareness updates into periodic HTTP requests: every four seconds when editing alone, every second when collaborators are present. (These values are filterable.)

It works reliably, but there can be good reasons to swap it out:

  • Lower latency. Transports such as WebSockets deliver updates as they happen, not on a polling interval. For sites doing heavy collaborative editing, the difference can be noticeable.
  • Reduced server load. Polling generates requests even when nothing has changed. A push-based transport only sends data when needed.
  • Infrastructure alignment. If you already run WebSocket servers or other real-time transport, you can benefit from using familiar infrastructure with WordPress.

These benefits come with a substantial overhead. Building a custom provider is not trivial. It will require custom code. Most likely, it will also involve deployingDeploy Launching code from a local development environment to the production web server, so that it's available to visitors. and maintaining server resources.

What a sync provider does

Real-time collaboration in WordPress is powered by Yjs, a Conflictconflict A conflict occurs when a patch changes code that was modified after the patch was created. These patches are considered stale, and will require a refresh of the changes before it can be applied, or the conflicts will need to be resolved.-free Replicated Data Type (CRDT) library. WordPress content is represented by Yjs documents; syncing happens by exchanging updates to those documents.

The sync provider is the transport layer. It facilitates the exchange of Yjs document updates between peers.

Concretely, a provider needs to:

  1. Receive local Yjs document updates and send them to remote peers.
  2. Receive remote updates and apply them to the local Yjs document.
  3. Report connection status so the editor UIUI User interface can show whether the user is connected.

GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses ‘blocks’ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/’s sync manager orchestrates the syncing process. It creates a sync provider for each Yjs document that will be synced. Therefore, supplying a custom sync provider means supplying a provider creator function. A provider creator is an async function following this example:

async function myProviderCreator( options ) {
    const objectType = options.objectType; // e.g., "postType/post"
    const objectId   = options.objectId;   // e.g., "123"
    const ydoc       = options.ydoc;       // Yjs document
    const awareness  = options.awareness;  // Yjs awareness

    // Create provider.
    const room     = `${ objectType }:${ objectId }`;
    const provider = new MyYjsProvider( ydoc, awareness, room );

    // Connect.
    provider.connect();

    return {
        destroy: () => provider.destroy(),
        on: ( event, callback ) => provider.on( event, callback ),
     };
}

Note that the returned object has two function properties that the provider must implement:

  • destroy(): The sync manager will call this function when it is time to close connections, remove listeners, and free resources.
  • on(): This function allows the sync manager to subscribe to connection state changes. Emit { status: 'connecting' }, { status: 'connected' }, or { status: 'disconnected', error?: ConnectionError } as appropriate.
    • A disconnected event can be accompanied by an error. Using specific error codes allows the editor to give specific feedback to the user. See the list of error codes and resulting messaging.

Existing Yjs providers

You don’t have to build a sync provider from scratch. Yjs has a provider ecosystem and several existing libraries can handle the heavy lifting. 

y-websocket is the most widely used Yjs provider and has been deployedDeploy Launching code from a local development environment to the production web server, so that it's available to visitors. by WordPress VIP and other WordPress hosts. It includes both a client and a simple Node.js server.

Note: y-webrtc is nominally a peer-to-peer provider that syncs via WebRTC, but in practice it requires centralized servers to reliably connect peers with each other. It is not recommended unless you are willing to invest in those servers. 

Minimal client example with y-websocket

Wrapping a Yjs provider in a ProviderCreator function is straightforward, as seen in the following example. However, note that this example is missing essential authorization checks (discussed in the next section):

import { addFilter } from '@wordpress/hooks';
import { WebsocketProvider } from 'y-websocket';

addFilter( 'sync.providers', 'my-plugin/websocket', () => {
    return [
        async ( { objectType, objectId, ydoc, awareness } ) => {
            const roomName = `${ objectType }-${ objectId ?? 'collection' }`;
            const provider = new WebsocketProvider(
                'wss://my-sync-server.example.com',
                roomName,
                ydoc,
                { awareness }
            );

            return {
                destroy: () => provider.destroy(),
                on: ( event, callback ) => provider.on( event, callback ),
            };
        },
    ];
} );

This code replaces the default HTTP polling provider entirely. The filter callback ignores the incoming providerCreators array and returns a new array containing a single WebSocket-based provider creator.

The WebSocket server (wss://my-sync-server.example.com in the example above) must be configured and deployed separately. The y-websocket-server library is the server companion to y-websocket.

Authorization and security

A custom sync provider connects to infrastructure that you own and operate, e.g., a WebSocket server. Because that infrastructure lives outside of WordPress, WordPress can’t authorize requests to it on your behalf.

Securing the connection between the editor and your sync server is your responsibility—a critical one. Without authorization checks, any user could connect to your WebSocket server and participate in a collaborative session with your WordPress users. 

Token-based auth

A common pattern is to issue short-lived tokens via a WordPress REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/ endpoint, then pass the token when opening the WebSocket connection. The tokens assert that the user has permission to collaborate on a specific entity.

Here’s a simplified example of how the WPVIP Real-Time Collaboration plugin handles it:

// Fetch a short-lived token from a WordPress REST endpoint.
// This endpoint is provided by your plugin. Tokens encode the
// type and ID of the entity being edited, as well as the current
// WordPress user ID.
const data = await apiFetch( {
    path: '/my-plugin/v1/sync/auth',
    method: 'GET',
    data: { objectType, objectId },
} );

// Pass the token as a query parameter when connecting.
provider.params = { auth: data.token };
provider.connect();

Key considerations

  • Validate on the server. Never trust the client. The sync server should verify the token on every connection request. The token should encode information about the user, the entity being edited, and which actions are authorized. The sync server should validate each assertion and reject unauthorized connections before applying any document updates.
  • Authorize per-document. It’s worth restating: Don’t just authenticate the user, additionally verify they have permission to edit the specific post or entity being synced. Your WebSocket server should validate this on every connection.
  • Rotate tokens. WebSocket connections are long-lived. Use short-lived tokens and re-authenticate on reconnect so that revoked permissions take effect promptly.
  • Handle disconnects gracefully. When authorization fails or a token is invalidinvalid A resolution on the bug tracker (and generally common in software development, sometimes also notabug) that indicates the ticket is not a bug, is a support request, or is generally invalid., emit a { status: 'disconnected', error } event so the editor can inform the user. The WPVIP pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party. maps WebSocket close codes to specific error types to give users actionable feedback.

The WPVIP Real-Time Collaboration plugin is a functional and secure example using WebSockets. It’s open sourceOpen Source Open Source denotes software for which the original source code is made freely available and may be redistributed and modified. Open Source **must be** delivered via a licensing model, see GPL. and contributions are welcome.

Feedback

If you have questions or feedback about building a custom sync provider, please share them in a comment on this post or in the #hosting channel of Make WordPress Slack.

Props to @jorbin and @westonruter for feedback and contributions.

#7-0, #dev-notes, #dev-notes-7-0, #feature-real-time-collaboration