Skip to content

Instantly share code, notes, and snippets.

@jsnajdr
Last active May 24, 2018 15:59
Show Gist options
  • Save jsnajdr/040ffaa492d9a83c823ddc7c09cf201b to your computer and use it in GitHub Desktop.
Save jsnajdr/040ffaa492d9a83c823ddc7c09cf201b to your computer and use it in GitHub Desktop.

Post Editor Redux

Post is a bag of attributes like title, content, metadata or terms. Some are primitive values, others are complex objects.

Post reducer data

The copy of the post saved on server is part of the common post state tree at state.posts.queries. In the UI code known as currentPost or savedPost.

Local edits are stored in state.posts.edits. Modified attributes only, diff from the saved post.

getEditedPost( state, siteId, postId ) selector merges them together and returns the post as the editor displays it. In the UI code known as post.

When saving, the server returns the full post object as it knows it. Locally, we update the savedPost and merge the changes from server into the local edits. On most saves, that makes edits empty and the post no longer dirty.

Post actions

START_EDITING_NEW, START_EDITING_EXISTING

Set up the post editor to edit a post. New post is initialized with default attribute values and doesn't have an ID until its first save.

Editing existing post usually needs to wait until the post is fetched from the server.

RECEIVE_POST_TO_EDIT

Existing post arrived from the server, initialize the editor with its attributes

SAVE_POST

Save the modifications to server. Sends the modified attributes.

RECEIVE_POST_BEING_EDITED

Save requests return the full copy of the post as the server knows it. This actions updates the local savedPost and updates the edits.

AUTOSAVE_POST

There are two types of autosave. Autosaving drafts is just a synonym to a regular save. Autosaving published posts doesn't update the publicly visible post, but saves into a "hidden" location. Jetpack/WP.com feature, not available in core.

STOP_EDITING

Set everything to null

Merging edits

Merging edits sometimes requires some sophistication:

In a post from server, featured_image is either null, or it's an URL. The image's ID is in post_thumbnail.ID. When sending a modify request, featured_image attribute in edits contains the ID.

When publishing or scheduling a post, we send status of publish and a date property. The server can however return publish, future or pending. We need to accept a different status like this as a performed edit, otherwise the post remains dirty.

Similar troubles are with categories etc.

Metadata

Array of key, value pairs:

[
  { key: 'geo_public', value: '1' }
]

To modify, we send "update" and "delete" operations as edits:

[
  { key: 'geo_public', operation: 'delete' }
]

Copying a post

We can choose to edit a new post as a duplicate of another. Needs care about what attributes we copy. If we copied everything, then publicize would break, for example.

Post Preview

We (auto)save the post before showing a preview. Subtle async logic that's easy to break.

Save blockers

Sometimes the post is in such a state that it cannot be saved. For example, while an image is being uploaded. Then the post body contains a shortcode with a temporary ID or featured image has a temporary ID.

In such case, actions to block and unblock save are dispatched and save action looks at the block status.

Syncing content between Redux/Flux and TinyMCE

Redux state has a content attribute. TinyMCE contains some content. We don't sync them on every keystroke for performance reasons. editor.getContent() is slow and does some postprocessing on the HTML markup. We only update the Redux content immediately before save or when switching editor mode.

To show correct isDirty status, we maintain a rawContent property that uses a more efficent editor.getContent() implementation and is debounced/throttled.

We sync the content the other way (from Redux to TinyMCE) in a few cases:

  • new post started being edited (empty)
  • post to edit loaded
  • started to edit a post copy
  • revision from history was loaded

Tricky and hard to understand in React: detect the exact event in lifecycle method

Trouble with common post store in state.posts.queries

The REST endpoint to retrieve a post has a context param that can be edit, display etc. There is some title, content and excerpt processing for the edit context.

Now, in state.posts.queries, we have mixed post data from display and edit contexts. Causes some content corruption: escaping entities, newlines etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment