WP 7.0: Fix Rewrite & Republish race conditions with Real-Time Collaboration#485
WP 7.0: Fix Rewrite & Republish race conditions with Real-Time Collaboration#485enricobattocchi 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 |
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>
There was a problem hiding this comment.
I have successfully verified the original issues, tested all the steps with the PR on WP 7.0 & 6.9, and the code looks good to me 👍
One thing I noticed: in Item 2 step 3, User A also gets the snackbar “Another user has republished this post. Redirecting to the original…”, sometimes even a few of them at once, even though it's User A who did the republishing, and not another user 🙂
Otherwise, this seems good to go.
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