diff --git a/packages/core-data/src/footnotes/get-rich-text-values-cached.js b/packages/core-data/src/footnotes/get-rich-text-values-cached.js index 06a01c5ef63fd..a5c2d25810861 100644 --- a/packages/core-data/src/footnotes/get-rich-text-values-cached.js +++ b/packages/core-data/src/footnotes/get-rich-text-values-cached.js @@ -6,7 +6,7 @@ import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; /** * Internal dependencies */ -import { unlock } from '../private-apis'; +import { unlock } from '../lock-unlock'; // TODO: The following line should have been: // diff --git a/packages/core-data/src/hooks/use-entity-records.ts b/packages/core-data/src/hooks/use-entity-records.ts index 5d643ab889692..e2659b88bc019 100644 --- a/packages/core-data/src/hooks/use-entity-records.ts +++ b/packages/core-data/src/hooks/use-entity-records.ts @@ -4,6 +4,7 @@ import { addQueryArgs } from '@wordpress/url'; import deprecated from '@wordpress/deprecated'; import { useSelect } from '@wordpress/data'; +import { useMemo } from '@wordpress/element'; /** * Internal dependencies @@ -12,6 +13,7 @@ import useQuerySelect from './use-query-select'; import { store as coreStore } from '../'; import type { Options } from './use-entity-record'; import type { Status } from './constants'; +import { unlock } from '../lock-unlock'; interface EntityRecordsResolution< RecordType > { /** The requested entity record */ @@ -152,3 +154,51 @@ export function __experimentalUseEntityRecords( } ); return useEntityRecords( kind, name, queryArgs, options ); } + +export function useEntityRecordsWithPermissions< RecordType >( + kind: string, + name: string, + queryArgs: Record< string, unknown > = {}, + options: Options = { enabled: true } +): EntityRecordsResolution< RecordType > { + const entityConfig = useSelect( + ( select ) => select( coreStore ).getEntityConfig( kind, name ), + [ kind, name ] + ); + const { records: data, ...ret } = useEntityRecords( + kind, + name, + queryArgs, + options + ); + const ids = useMemo( + () => + data?.map( + // @ts-ignore + ( record: RecordType ) => record[ entityConfig?.key ?? 'id' ] + ) ?? [], + [ data, entityConfig?.key ] + ); + + const permissions = useSelect( + ( select ) => { + const { getEntityRecordsPermissions } = unlock( + select( coreStore ) + ); + return getEntityRecordsPermissions( kind, name, ids ); + }, + [ ids, kind, name ] + ); + + const dataWithPermissions = useMemo( + () => + data?.map( ( record, index ) => ( { + // @ts-ignore + ...record, + permissions: permissions[ index ], + } ) ) ?? [], + [ data, permissions ] + ); + + return { records: dataWithPermissions, ...ret }; +} diff --git a/packages/core-data/src/index.js b/packages/core-data/src/index.js index bd25fa8de9902..ad6adec0203c5 100644 --- a/packages/core-data/src/index.js +++ b/packages/core-data/src/index.js @@ -18,7 +18,7 @@ import { getMethodName, } from './entities'; import { STORE_NAME } from './name'; -import { unlock } from './private-apis'; +import { unlock } from './lock-unlock'; // The entity selectors/resolvers and actions are shortcuts to their generic equivalents // (getEntityRecord, getEntityRecords, updateEntityRecord, updateEntityRecords) @@ -86,3 +86,4 @@ export * from './entity-provider'; export * from './entity-types'; export * from './fetch'; export * from './hooks'; +export * from './private-apis'; diff --git a/packages/core-data/src/lock-unlock.js b/packages/core-data/src/lock-unlock.js new file mode 100644 index 0000000000000..91bf30792c970 --- /dev/null +++ b/packages/core-data/src/lock-unlock.js @@ -0,0 +1,10 @@ +/** + * WordPress dependencies + */ +import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/private-apis'; + +export const { lock, unlock } = + __dangerousOptInToUnstableAPIsOnlyForCoreModules( + 'I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.', + '@wordpress/core-data' + ); diff --git a/packages/core-data/src/private-apis.js b/packages/core-data/src/private-apis.js index 91bf30792c970..443db97957285 100644 --- a/packages/core-data/src/private-apis.js +++ b/packages/core-data/src/private-apis.js @@ -1,10 +1,10 @@ /** - * WordPress dependencies + * Internal dependencies */ -import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/private-apis'; +import { useEntityRecordsWithPermissions } from './hooks/use-entity-records'; +import { lock } from './lock-unlock'; -export const { lock, unlock } = - __dangerousOptInToUnstableAPIsOnlyForCoreModules( - 'I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.', - '@wordpress/core-data' - ); +export const privateApis = {}; +lock( privateApis, { + useEntityRecordsWithPermissions, +} ); diff --git a/packages/core-data/src/private-selectors.ts b/packages/core-data/src/private-selectors.ts index 6280bb9631963..9a9b2ef510078 100644 --- a/packages/core-data/src/private-selectors.ts +++ b/packages/core-data/src/private-selectors.ts @@ -50,3 +50,26 @@ export const getBlockPatternsForPostType = createRegistrySelector( () => [ select( STORE_NAME ).getBlockPatterns() ] ) ); + +/** + * Returns the entity records permissions for the given entity record ids. + */ +export const getEntityRecordsPermissions = createRegistrySelector( ( select ) => + createSelector( + ( state: State, kind: string, name: string, ids: string[] ) => { + return ids.map( ( id ) => ( { + delete: select( STORE_NAME ).canUser( 'delete', { + kind, + name, + id, + } ), + update: select( STORE_NAME ).canUser( 'update', { + kind, + name, + id, + } ), + } ) ); + }, + ( state ) => [ state.userPermissions ] + ) +); diff --git a/packages/edit-site/src/components/post-list/index.js b/packages/edit-site/src/components/post-list/index.js index ff25fbcd1962f..68b8461929eb1 100644 --- a/packages/edit-site/src/components/post-list/index.js +++ b/packages/edit-site/src/components/post-list/index.js @@ -2,7 +2,10 @@ * WordPress dependencies */ import { Button } from '@wordpress/components'; -import { useEntityRecords, store as coreStore } from '@wordpress/core-data'; +import { + store as coreStore, + privateApis as coreDataPrivateApis, +} from '@wordpress/core-data'; import { useState, useMemo, useCallback, useEffect } from '@wordpress/element'; import { privateApis as routerPrivateApis } from '@wordpress/router'; import { useSelect, useDispatch } from '@wordpress/data'; @@ -33,6 +36,7 @@ import usePostFields from '../post-fields'; const { usePostActions } = unlock( editorPrivateApis ); const { useLocation, useHistory } = unlock( routerPrivateApis ); +const { useEntityRecordsWithPermissions } = unlock( coreDataPrivateApis ); const EMPTY_ARRAY = []; function useView( postType ) { @@ -199,7 +203,7 @@ export default function PostList( { postType } ) { isResolving: isLoadingMainEntities, totalItems, totalPages, - } = useEntityRecords( 'postType', postType, queryArgs ); + } = useEntityRecordsWithPermissions( 'postType', postType, queryArgs ); const ids = records?.map( ( record ) => getItemId( record ) ) ?? []; const prevIds = usePrevious( ids ) ?? [];