#60761 closed defect (bug) (fixed)
Interactivity API: Empty state objects are not correctly sent to the client
Reported by: | jonsurrell | Owned by: | swissspidy |
---|---|---|---|
Milestone: | 6.5 | Priority: | normal |
Severity: | normal | Version: | 6.5 |
Component: | Interactivity API | Keywords: | has-patch has-unit-tests commit dev-reviewed fixed-major |
Focuses: | Cc: |
Description
If an Interactivity API store is created on the server with an empty array:
wp_interactivity_state( 'myPlugin', array() );
It is serialized and sent to the client as a JavaScript array: []
. However, state is expected to be an object {}
. This creates problems on the client when server and client states are merged. For example, it breaks state getters defined on the client like this:
store( "myplugin/demo", { state: { get aValue() { return 'This will break.'; }, } } );
Change History (15)
This ticket was mentioned in PR #6261 on WordPress/wordpress-develop by @jonsurrell.
10 months ago
#1
- Keywords has-patch has-unit-tests added
@jonsurrell commented on PR #6261:
10 months ago
#2
👋 @c4rl0sbr4v0 @DAreRodz for review.
#3
@
10 months ago
- Component changed from General to Editor
- Milestone changed from Awaiting Review to 6.5
- Version set to trunk
@jonsurrell commented on PR #6261:
10 months ago
#4
This pairs nicely with https://github.com/WordPress/gutenberg/pull/59842 which will ensure stores are initialized on the client before they're needed.
#5
follow-up:
↓ 6
@
10 months ago
What's the implication of serving an empty array []
from the server instead of an object {}
? Will it break something on the client if the client-side patch lands? I'm thinking about how severe the problem is to make a good decision whether to include in 6.5.0.
#6
in reply to:
↑ 5
@
10 months ago
Replying to gziolo:
What's the implication of serving an empty array
[]
from the server instead of an object{}
? Will it break something on the client if the client-side patch lands? I'm thinking about how severe the problem is to make a good decision whether to include in 6.5.0.
In my opinion this fix is important and should be landed for 6.5. I'd like https://github.com/WordPress/gutenberg/pull/59842 to also be backported to 6.5. I think those two changes together are sufficient to address the related problems I observed.
The client expects state
to be a JavaScript object. I explained some of this on the PR in this comment, but I'll summarize here.
The client expects state to be a JavaScript object ({}
) and does not currently do any validation on the initial state provided by the server, or any state the first time a store is created for a given namespace. Checks should be added to the client, but that may be a bigger change. Both the client and the server should be fixed to prevent non-objects from being stored in state.
I've observed this problem of an array entering state breaking plugin code on the client. Looking at the code, it seems like the problem is the following:
- State data sent from the server is injected into the store namespaces. State values are not checked for whether they're objects.
- Initially this data is stored.
- Subsequent calls to
store
are prevented from updatingstate
because they would be merged, but the merge function bails if either argument is not an object.
I'm happy to also fix non-objects being stored in state on the first store call, that would be another client side PR. If that is fixed on the client, this change would become more of an optimization than a bugfix. It would still be incorrect to send []
state to the client, but it wouldn't be harmful.
#7
@
10 months ago
Here's a PR for the client-side fix to prevent non-objects from being stored as interactivity store state: https://github.com/WordPress/gutenberg/pull/59886
#8
@
10 months ago
- Keywords dev-feedback added
@swissspidy, it would be important to land this bug fix in 6.5.0 to avoid unexpected issues with custom blocks that set the initial state to values that are incorrectly serialized.
#9
@
10 months ago
- Keywords commit added
- Owner changed from jonsurrell to swissspidy
- Status changed from assigned to reviewing
@swissspidy commented on PR #6261:
10 months ago
#11
Committed in https://core.trac.wordpress.org/changeset/57841
Prevent an empty Interactivity store from being serialized as
[]
. Stores are expected to be JSON objects ({}
), but PHP willjson_encode
empty arrays as[]
. An option would be to force PHP to use empty objects withJSON_FORCE_OBJECT
, but that is deep, so if we wanted e.g.array( 'myStore' => array( 'ids' => array() ) )
the innerarray()
would also become{}
, which we probably don't want.Trac ticket: https://core.trac.wordpress.org/ticket/60761