Skip to content

Commit

Permalink
Data: Add persistence via data plugin interface (#8341)
Browse files Browse the repository at this point in the history
* Data: Add persistence via data plugin interface

* Data: Integrate persistence as first-party plugin

* Data: Restore deprecated persistence behaviors

* Data: Return default persisted by caught error

* Data: Initialize persistence by plugin options

* Data: Remove string form variation on use

* Data: Refactor persistence as dispatch enhancer

* Data: Remove middlewares / enhancers support for store

* Data: Remove unused variable

* Data: Improve objectStorage spec compliancy

Should (a) return null if not set, (b) assign value as string

* Data: Fix persistence handling of null value

* Data: Fix deprecation key to persist

1. Wrong property accessed used
2. Reducer is already wrapped at point registerStore is called. Detect from plugin instead.

* Data: Add tests for WPDataRegistry#use

* Data: Remove _ prefix from local variable

Not conventional

* Data: Update plugins documentation to avoid mention of string usage
  • Loading branch information
aduth committed Aug 3, 2018
1 parent b08f9d3 commit c1c4c7e
Show file tree
Hide file tree
Showing 19 changed files with 731 additions and 330 deletions.
9 changes: 1 addition & 8 deletions edit-post/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/
import { registerCoreBlocks } from '@wordpress/core-blocks';
import { render, unmountComponentAtNode } from '@wordpress/element';
import { dispatch, setupPersistence } from '@wordpress/data';
import { dispatch } from '@wordpress/data';
import deprecated from '@wordpress/deprecated';

/**
Expand All @@ -15,11 +15,6 @@ import store from './store';
import { initializeMetaBoxState } from './store/actions';
import Editor from './editor';

/**
* Module Constants
*/
const STORAGE_KEY = `WP_EDIT_POST_DATA_${ window.userSettings.uid }`;

/**
* Reinitializes the editor after the user chooses to reboot the editor after
* an unhandled error occurs, replacing previously mounted editor element using
Expand Down Expand Up @@ -93,5 +88,3 @@ export { default as PluginPostStatusInfo } from './components/sidebar/plugin-pos
export { default as PluginPrePublishPanel } from './components/sidebar/plugin-pre-publish-panel';
export { default as PluginSidebar } from './components/sidebar/plugin-sidebar';
export { default as PluginSidebarMoreMenuItem } from './components/header/plugin-sidebar-more-menu-item';

setupPersistence( STORAGE_KEY );
10 changes: 4 additions & 6 deletions edit-post/store/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
/**
* WordPress Dependencies
*/
import {
registerStore,
restrictPersistence,
} from '@wordpress/data';
import { registerStore } from '@wordpress/data';

/**
* Internal dependencies
Expand All @@ -13,11 +10,12 @@ import reducer from './reducer';
import applyMiddlewares from './middlewares';
import * as actions from './actions';
import * as selectors from './selectors';

const store = registerStore( 'core/edit-post', {
reducer: restrictPersistence( reducer, 'preferences' ),
reducer,
actions,
selectors,
persist: true,
persist: [ 'preferences' ],
} );

applyMiddlewares( store );
Expand Down
16 changes: 16 additions & 0 deletions lib/client-assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,22 @@ function gutenberg_register_scripts_and_styles() {
filemtime( gutenberg_dir_path() . 'build/data/index.js' ),
true
);
wp_add_inline_script(
'wp-data',
implode( "\n", array(
// TODO: Transferring old storage should be removed at v3.7.
'( function() {',
' var userId = window.userSettings.uid;',
' var oldStorageKey = "WP_EDIT_POST_DATA_" + userId;',
' var storageKey = "WP_DATA_USER_" + userId;',
' if ( localStorage[ oldStorageKey ] ) {',
' localStorage[ storageKey ] = localStorage[ oldStorageKey ];',
' delete localStorage[ oldStorageKey ];',
' }',
' wp.data.use( wp.data.plugins.persistence, { storageKey: storageKey } );',
'} )()',
) )
);
wp_register_script(
'wp-core-data',
gutenberg_url( 'build/core-data/index.js' ),
Expand Down
55 changes: 50 additions & 5 deletions packages/data/src/deprecated.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import deprecated from '@wordpress/deprecated';
/**
* Internal dependencies
*/
import { getPersistenceStorage } from './persist';
import * as persistence from './plugins/persistence';

/**
* Adds the rehydration behavior to redux reducers.
Expand Down Expand Up @@ -63,12 +63,14 @@ export function loadAndPersist( store, reducer, reducerKey, storageKey ) {
hint: 'See https://github.com/WordPress/gutenberg/pull/8146 for more details',
} );

const persist = persistence.createPersistenceInterface( { storageKey } );

// Load initially persisted value
const persistedString = getPersistenceStorage().getItem( storageKey );
if ( persistedString ) {
const persisted = persist.get();
if ( persisted ) {
const persistedState = {
...get( reducer( undefined, { type: '@@gutenberg/init' } ), reducerKey ),
...JSON.parse( persistedString ),
...JSON.parse( persisted ),
};

store.dispatch( {
Expand All @@ -85,7 +87,50 @@ export function loadAndPersist( store, reducer, reducerKey, storageKey ) {
if ( newStateValue !== currentStateValue ) {
currentStateValue = newStateValue;
const stateToSave = get( reducer( store.getState(), { type: 'SERIALIZE' } ), reducerKey );
getPersistenceStorage().setItem( storageKey, JSON.stringify( stateToSave ) );
persist.set( stateToSave );
}
} );
}

/**
* Higher-order reducer used to persist just one key from the reducer state.
*
* @param {function} reducer Reducer function.
* @param {string} keyToPersist The reducer key to persist.
*
* @return {function} Updated reducer.
*/
export function restrictPersistence( reducer, keyToPersist ) {
deprecated( 'wp.data.restrictPersistence', {
alternative: 'registerStore persist option with persistence plugin',
version: '3.7',
plugin: 'Gutenberg',
hint: 'See https://github.com/WordPress/gutenberg/pull/8341 for more details',
} );

reducer.__deprecatedKeyToPersist = keyToPersist;

return reducer;
}

/**
* Sets a different persistence storage.
*
* @param {Object} storage Persistence storage.
*/
export function setPersistenceStorage( storage ) {
deprecated( 'wp.data.setPersistenceStorage', {
alternative: 'persistence plugin with storage option',
version: '3.7',
plugin: 'Gutenberg',
hint: 'See https://github.com/WordPress/gutenberg/pull/8341 for more details',
} );

const originalCreatePersistenceInterface = persistence.createPersistenceInterface;
persistence.createPersistenceInterface = ( options ) => {
originalCreatePersistenceInterface( {
storage,
...options,
} );
};
}
12 changes: 10 additions & 2 deletions packages/data/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,19 @@ import { combineReducers } from 'redux';
* Internal dependencies
*/
import defaultRegistry from './default-registry';
export { restrictPersistence, setPersistenceStorage } from './persist';
import * as plugins from './plugins';

export { default as withSelect } from './components/with-select';
export { default as withDispatch } from './components/with-dispatch';
export { default as RegistryProvider } from './components/registry-provider';
export { createRegistry } from './registry';
export { withRehydration, loadAndPersist } from './deprecated';
export {
withRehydration,
loadAndPersist,
restrictPersistence,
setPersistenceStorage,
} from './deprecated';
export { plugins };

/**
* The combineReducers helper function turns an object whose values are different
Expand All @@ -35,3 +42,4 @@ export const registerActions = defaultRegistry.registerActions;
export const registerSelectors = defaultRegistry.registerSelectors;
export const registerResolvers = defaultRegistry.registerResolvers;
export const setupPersistence = defaultRegistry.setupPersistence;
export const use = defaultRegistry.use;
83 changes: 0 additions & 83 deletions packages/data/src/persist.js

This file was deleted.

17 changes: 17 additions & 0 deletions packages/data/src/plugins/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Data Plugins
============

Included here are a set of default plugin integrations for the WordPress data module.

## Usage

For any of the plugins included here as directories, call the `use` method to include its behaviors in the registry.

```js
// npm Usage
import { plugins, use } from '@wordpress/data';
use( plugins.persistence );

// WordPress Globals Usage
wp.data.use( wp.data.plugins.persistence );
```
1 change: 1 addition & 0 deletions packages/data/src/plugins/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as persistence } from './persistence';
36 changes: 36 additions & 0 deletions packages/data/src/plugins/persistence/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
Persistence Plugin
==================

The persistence plugin enhances a registry to enable registered stores to opt in to persistent storage.

By default, persistence occurs by [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). This can be changed using the [`setStorage` function](#api) defined on the plugin. Unless set otherwise, state will be persisted on the `WP_DATA` key in storage.

## Usage

Call the `use` method on the default or your own registry to include the persistence plugin:

```js
wp.data.use( wp.data.plugins.persistence, { storageKey: 'example' } );
```

Then, when registering a store, set a `persist` property as `true` (persist all state) or an array of state keys to persist.

```js
wp.data.registerStore( 'my-plugin', {
// ...

persist: [ 'preferences' ],
} );
```

## Options

### `storage`

Persistent storage implementation. This must at least implement `getItem` and `setItem` of the Web Storage API.

See: https://developer.mozilla.org/en-US/docs/Web/API/Storage

### `storageKey`

The key on which to set in persistent storage.
Loading

0 comments on commit c1c4c7e

Please sign in to comment.