Conversation
…getPostChangesFromCRDTDoc()
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
Size Change: +72 B (0%) Total Size: 8.75 MB
ℹ️ View Unchanged
|
| isRichTextAttribute( blockName, key ) && | ||
| typeof value === 'string' | ||
| ) { | ||
| newAttributes[ key ] = RichTextData.fromHTMLString( value ); |
There was a problem hiding this comment.
Following this call stack, we eventually land here:
Is this cheap enough (given the Document re-use) that we don't need to cache this operation?
|
|
||
| for ( const [ key, value ] of Object.entries( attributes ) ) { | ||
| if ( | ||
| isRichTextAttribute( blockName, key ) && |
There was a problem hiding this comment.
The serialize function relies on the value being an instant of RichTextData while the deserialize relies on the attribute for the value mentioning that its rich-text. Would a block author always mention that schema type, or could they skip it and then this path wouldn't be triggered? Should we account for the less than ideal path?
There was a problem hiding this comment.
Would a block author always mention that schema type
We have been assuming this contract will be upheld in general. We definitely should not go down the path of trying to predict the attribute type based on its value.
There was a problem hiding this comment.
Totally, we should follow the path of assuming that the contract will be upheld but I wanted to point it out 🙏🏾
| for ( const [ key, value ] of Object.entries( attributes ) ) { | ||
| if ( | ||
| isRichTextAttribute( blockName, key ) && | ||
| typeof value === 'string' |
There was a problem hiding this comment.
The deserialize function, if I'm reading it right, doesn't account for arrays the way the serialize function does (tables for instance). Wouldn't the new rich-text conversion not apply if this kind of text existed in a table?
|
Flaky tests detected in af680cd. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/23220669791
|
What?
Fixes an issue we've observed with the
jetpack-mu-wpcomcode block override that causes code content to be cleared out when another user loads the editor:code-block-reproduction.mov
This in particular resulted from the custom code block accessing a
RichTextattribute value viaattributes.content?.text. Intrunk, our CRDT code caused theattributes.contentvalue to be astringinstead ofRichTextDataso the.textproperty failed to exist.Why?
The Jetpack enhanced code block (and any block whose edit component accesses
content.textand expects a rich text object) breaks when a second user joins a collaborative session. The CRDT serialization path correctly convertsRichTextDatato strings when writing to the Y.Doc (serializeAttributeValue), but the deserialization path has no corresponding conversion back.This meant blocks received from CRDT had
contentas a raw string, socontent.text(aRichTextDatagetter) wasundefined. The edit component then initialized with empty content and wrote that back, wiping the block's content entirely.How?
Added
deserializeBlockAttributesas the inverse of the existing serialization path. WhengetPostChangesFromCRDTDocextracts blocks from the CRDT document, it now converts any rich-text string attributes back toRichTextDataviaRichTextData.fromHTMLString(). This ensures block edit components receive the same attribute types regardless of whether blocks were created locally or arrived via CRDT sync.Testing Instructions
Unit test
You can see the test failing before the fix here: https://github.com/WordPress/gutenberg/actions/runs/23220557291/job/67491959921?pr=76607.
Manual testing
Manual testing with
jetpack-mu-wpcom-specific blocks is difficult locally, so I've included test files that can be used locally to reproduce the same issue. Here's what the reproduction looks like using the "RTC Test Code Block":local-block-reproduction.mov
Test code block with fix disabled to show local reproduction
Here's how to run this locally to reproduce the bug against
trunk:Enable RTC via Settings -> Writing -> "Enable real-time collaboration" checkbox.
Create a
rtc-test-code-block/folder at the root of yourgutenbergrepository. Add these two files:rtc-test-code-block.phprtc-test-code-block.jsThese implement a block that reads from content via
attributes.content?.textand writes it back to the block attributes, replicating the same bug.Add the "plugin" to your
.wp-env.json:{ "$schema": "./schemas/json/wp-env.json", "testsEnvironment": false, "core": "WordPress/WordPress", - "plugins": [ "." ], + "plugins": [ ".", "./rtc-test-code-block" ], /* ... */ }Activate the plugin and open a draft post. Insert a "RTC Test Code Block", a heading block, and another "RTC Test Code Block", each with content.
Open the same post in a second browser.
After the collaborator list appears, the second user should see the code block contents cleared out.
Try again on this branch (
fix/rich-text-deserialization) and the content should stay.Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Used for: Diagnosing the CRDT serialization problem and implementing the fix.