WP 7.0: Fix Rewrite & Republish race conditions with Real-Time Collaboration#485
Open
enricobattocchi wants to merge 6 commits intotrunkfrom
Open
WP 7.0: Fix Rewrite & Republish race conditions with Real-Time Collaboration#485enricobattocchi wants to merge 6 commits intotrunkfrom
enricobattocchi wants to merge 6 commits intotrunkfrom
Conversation
Register _dp_has_rewrite_republish_copy post meta for the REST API and read it reactively via the core store's getEntityRecord. Since the R&R copy is created via a server-side admin action (not through the editor), the meta change does not enter the RTC CRDT document. Periodic cache invalidation (every 15s) ensures the editor refetches the entity record and picks up the change. A snackbar notification informs the user when another collaborator has created an R&R copy, explaining why the button disappeared. Ref: Yoast/reserved-tasks#1127 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When another user republishes an R&R copy via RTC, the collaborator is left editing a deleted post. The RTC status change does not propagate because the republishing user navigates away before the CRDT update is sent. Detect this by polling the REST API every 2 seconds for the copy's status. When the copy is republished (dp-rewrite-republish), trashed, or deleted (404), show a snackbar notification and redirect the collaborator to the original post's edit screen after 3 seconds. Also adds a dpcollabredirected query param so the original post's edit page shows an info notice explaining what happened. Ref: Yoast/reserved-tasks#1127 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Claim the slot on the original post using add_post_meta() with $unique = true before creating the copy. This returns false if the meta key already exists, preventing duplicate copies when two concurrent requests both pass the permission check before either sets the meta. If wp_insert_post() fails, the claim is rolled back by deleting the meta. Also fixes Block_Editor_Test to mock get_post_type_object() for the restBase addition to the localized JS object. Ref: Yoast/reserved-tasks#1127 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pull Request Test Coverage Report for Build 23667162515Details
💛 - Coveralls |
Contributor
There was a problem hiding this comment.
Pull request overview
Improves Rewrite & Republish (R&R) behavior under WordPress 7.0 Real-Time Collaboration by preventing duplicate copy creation and ensuring collaborators are redirected/notified when a copy is republished/deleted.
Changes:
- Prevents concurrent R&R requests from creating multiple copies by claiming a unique meta “slot” before copy creation.
- Adds block editor UI updates for RTC: hides the R&R button when a copy exists (via REST-exposed meta + periodic cache invalidation) and polls REST to redirect collaborators when the copy is republished/deleted.
- Adds collaborator-redirect notices and makes the new query arg removable; updates unit tests accordingly.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/post-duplicator.php |
Adds a DB-level “claim” via unique post meta to avoid duplicate R&R copies under concurrent requests. |
src/ui/block-editor.php |
Registers REST-exposed meta and localizes restBase to support editor-side polling/invalidation. |
js/src/duplicate-post-edit-script.js |
Adds RTC-aware UI: meta-based button hiding, periodic invalidation, and REST polling/redirect logic. |
src/watchers/republished-post-watcher.php |
Adds collaborator redirect notice + removable query arg handling. |
tests/Unit/UI/Block_Editor_Test.php |
Extends unit tests for the new init hook, meta registration, and localized restBase. |
tests/Unit/Watchers/Republished_Post_Watcher_Test.php |
Updates removable query args test to include the new parameter. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Use per-post auth_callback for register_post_meta (edit_post cap instead of generic edit_posts). - Fall back to post type name when rest_base is empty, matching the pattern used by WP core REST controllers. - Only redirect collaborator on confirmed deletion (404/410/403), not on transient network errors. - Improve register_post_meta unit test to verify config values. - Add WP integration tests for R&R race condition: slot claiming, duplicate blocking, and rollback on failure. Ref: Yoast/reserved-tasks#1127 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
PluginDocumentSettingPanelinstead of metaboxes. This creates several issues with the Rewrite & Republish flow when multiple users are involved.Summary
This PR can be summarized in the following changelog entry:
Relevant technical choices:
add_post_meta()with$unique = trueto claim the slot on the original post before creating the copy. This prevents duplicate copies at the database level. Ifwp_insert_post()fails, the claim is rolled back.dp-rewrite-republishstatus), trashed, or deleted (404). TherestBaseis provided via localized PHP data becauseselect('core').getPostType()is a resolver-backed selector that returnsundefinedat script initialization time._dp_has_rewrite_republish_copywithshow_in_restand reads it viagetEntityRecordfrom thecorestore. Server-side meta changes bypass the RTC CRDT, so periodic cache invalidation viainvalidateResolutionevery 15 seconds ensures the editor picks up the change.invalidateResolutionis safe with unsaved local edits — the store'seditsreducer preserves local changes that differ from the server response.Test instructions
Test instructions for the acceptance test before the PR gets merged
This PR can be acceptance tested by following these steps:
Setup: WordPress 7.0+ with RTC enabled, two browser sessions (different users or normal + incognito).
Item 1 — Race condition:
Item 2 — Collaborator redirect:
Item 3 — Dynamic button:
Backward compatibility:
Relevant test scenarios
Test instructions for QA when the code is in the RC
QA can test this PR by following these steps:
Impact check
This PR affects the following parts of the plugin, which may require extra testing:
src/post-duplicator.php)js/src/duplicate-post-edit-script.js)src/watchers/republished-post-watcher.php)src/ui/block-editor.php)UI changes
Documentation
Quality assurance
Innovation
innovationlabel and noted the work hours.Fixes Yoast/reserved-tasks#1127