Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Entities: Add config to read and write transient edits from edited post #57500

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/reference-guides/data/data-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ _Parameters_

_Returns_

- `any`: Entity config
- `EntityConfig | undefined`: Entity config

### getEntityRecord

Expand Down
2 changes: 1 addition & 1 deletion packages/core-data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ _Parameters_

_Returns_

- `any`: Entity config
- `EntityConfig | undefined`: Entity config

### getEntityRecord

Expand Down
16 changes: 13 additions & 3 deletions packages/core-data/src/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { capitalCase, pascalCase } from 'change-case';
import apiFetch from '@wordpress/api-fetch';
import { __ } from '@wordpress/i18n';
import { RichTextData } from '@wordpress/rich-text';
import { __unstableSerializeAndClean, parse } from '@wordpress/blocks';

/**
* Internal dependencies
Expand All @@ -19,6 +20,13 @@ import { getSyncProvider } from './sync';
export const DEFAULT_ENTITY_KEY = 'id';

const POST_RAW_ATTRIBUTES = [ 'title', 'excerpt', 'content' ];
const blocksTransientEntity = {
read: ( record ) => parse( record.content ),
write: ( record ) => ( {
...record,
content: __unstableSerializeAndClean( record.content ),
} ),
};

export const rootEntitiesConfig = [
{
Expand Down Expand Up @@ -138,7 +146,9 @@ export const rootEntitiesConfig = [
baseURL: '/wp/v2/sidebars',
baseURLParams: { context: 'edit' },
plural: 'sidebars',
transientEdits: { blocks: true },
transientEdits: {
blocks: blocksTransientEntity,
},
label: __( 'Widget areas' ),
},
{
Expand All @@ -147,7 +157,7 @@ export const rootEntitiesConfig = [
baseURL: '/wp/v2/widgets',
baseURLParams: { context: 'edit' },
plural: 'widgets',
transientEdits: { blocks: true },
transientEdits: { blocks: blocksTransientEntity },
label: __( 'Widgets' ),
},
{
Expand Down Expand Up @@ -320,7 +330,7 @@ async function loadPostTypeEntities() {
name,
label: postType.name,
transientEdits: {
blocks: true,
blocks: blocksTransientEntity,
selection: true,
},
mergedEdits: { meta: true },
Expand Down
11 changes: 4 additions & 7 deletions packages/core-data/src/entity-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
useMemo,
} from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
import { parse, __unstableSerializeAndClean } from '@wordpress/blocks';
import { __unstableSerializeAndClean } from '@wordpress/blocks';

/**
* Internal dependencies
Expand Down Expand Up @@ -153,7 +153,7 @@ export function useEntityProp( kind, name, prop, _id ) {
export function useEntityBlockEditor( kind, name, { id: _id } = {} ) {
const providerId = useEntityId( kind, name );
const id = _id ?? providerId;
const { content, editedBlocks, meta } = useSelect(
const { editedBlocks, meta } = useSelect(
( select ) => {
if ( ! id ) {
return {};
Expand All @@ -162,7 +162,6 @@ export function useEntityBlockEditor( kind, name, { id: _id } = {} ) {
const editedRecord = getEditedEntityRecord( kind, name, id );
return {
editedBlocks: editedRecord.blocks,
content: editedRecord.content,
meta: editedRecord.meta,
};
},
Expand All @@ -180,10 +179,8 @@ export function useEntityBlockEditor( kind, name, { id: _id } = {} ) {
return editedBlocks;
}

return content && typeof content !== 'function'
? parse( content )
: EMPTY_ARRAY;
}, [ id, editedBlocks, content ] );
return EMPTY_ARRAY;
}, [ id, editedBlocks ] );

const updateFootnotes = useCallback(
( _blocks ) => updateFootnotesFromMeta( _blocks, meta ),
Expand Down
78 changes: 63 additions & 15 deletions packages/core-data/src/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,15 @@ interface EntityState< EntityRecord extends ET.EntityRecord > {
revisions?: RevisionsQueriedData;
}

interface EntityConfig {
type TransientPropertyConfig = boolean | { read: Function; write: Function };
type EntityConfig = {
name: string;
kind: string;
}
key?: string;
__unstable_rest_base?: string;
getTitle?: ( entity: any ) => string;
transientEdits?: Record< string, TransientPropertyConfig >;
};

interface UserState {
queries: Record< string, EntityRecordKey[] >;
Expand Down Expand Up @@ -265,7 +270,7 @@ export function getEntityConfig(
state: State,
kind: string,
name: string
): any {
): EntityConfig | undefined {
return state.entities.config?.find(
( config ) => config.kind === kind && config.name === name
);
Expand Down Expand Up @@ -670,7 +675,7 @@ export const __experimentalGetDirtyEntityRecords = createSelector(
// when it's used as an object key.
key: entityRecord
? entityRecord[
entityConfig.key || DEFAULT_ENTITY_KEY
entityConfig?.key || DEFAULT_ENTITY_KEY
]
: undefined,
title:
Expand Down Expand Up @@ -723,7 +728,7 @@ export const __experimentalGetEntitiesBeingSaved = createSelector(
// when it's used as an object key.
key: entityRecord
? entityRecord[
entityConfig.key || DEFAULT_ENTITY_KEY
entityConfig?.key || DEFAULT_ENTITY_KEY
]
: undefined,
title:
Expand All @@ -750,16 +755,56 @@ export const __experimentalGetEntitiesBeingSaved = createSelector(
*
* @return The entity record's edits.
*/
export function getEntityRecordEdits(
state: State,
kind: string,
name: string,
recordId: EntityRecordKey
): Optional< any > {
return state.entities.records?.[ kind ]?.[ name ]?.edits?.[
recordId as string | number
];
}
export const getEntityRecordEdits = createSelector(
(
state: State,
kind: string,
name: string,
recordId: EntityRecordKey
): Optional< any > => {
const { transientEdits } = getEntityConfig( state, kind, name ) ?? {};
const regularEdits =
state.entities.records?.[ kind ]?.[ name ]?.edits?.[
recordId as string | number
];
let result = regularEdits;
const rawRecord = getRawEntityRecord( state, kind, name, recordId );
const recordWithEdits = rawRecord
? {
...rawRecord,
...regularEdits,
}
: undefined;
Object.entries( transientEdits ?? {} ).forEach(
( [ key, transientEditConfig ] ) => {
if (
recordWithEdits &&
regularEdits?.[ key ] === undefined &&
typeof transientEditConfig === 'object'
) {
result = {
...result,
[ key ]: transientEditConfig.read( recordWithEdits ),
};
}
}
);

return result;
},
( state: State, kind: string, name: string, recordId: EntityRecordKey ) => {
const context = 'default';
return [
state.entities.config,
state.entities.records?.[ kind ]?.[ name ]?.edits?.[ recordId ],
state.entities.records?.[ kind ]?.[ name ]?.queriedData?.items[
context
]?.[ recordId ],
state.entities.records?.[ kind ]?.[ name ]?.queriedData
?.itemIsComplete[ context ]?.[ recordId ],
];
}
);

/**
* Returns the specified entity record's non transient edits.
Expand Down Expand Up @@ -1152,6 +1197,9 @@ export function canUserEditEntityRecord(
return false;
}
const resource = entityConfig.__unstable_rest_base;
if ( resource === undefined ) {
return false;
}

return canUser( state, 'update', resource, recordId );
}
Expand Down
16 changes: 3 additions & 13 deletions packages/editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
getFreeformContentHandlerName,
getDefaultBlockName,
__unstableSerializeAndClean,
parse,
} from '@wordpress/blocks';
import { isInTheFuture, getDate } from '@wordpress/date';
import { addQueryArgs, cleanForSlug } from '@wordpress/url';
Expand Down Expand Up @@ -1112,18 +1111,9 @@ export const isPublishSidebarEnabled = createRegistrySelector(
* @param {Object} state
* @return {Array} Block list.
*/
export const getEditorBlocks = createSelector(
( state ) => {
return (
getEditedPostAttribute( state, 'blocks' ) ||
parse( getEditedPostContent( state ) )
);
},
( state ) => [
getEditedPostAttribute( state, 'blocks' ),
getEditedPostContent( state ),
]
);
export function getEditorBlocks( state ) {
return getEditedPostAttribute( state, 'blocks' );
}

/**
* Returns true if the given panel was programmatically removed, or false otherwise.
Expand Down
Loading