@wordpress/editor 14.4.0 → 14.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/bindings/post-meta.js +12 -0
  3. package/build/bindings/post-meta.js.map +1 -1
  4. package/build/components/blog-title/index.js +1 -1
  5. package/build/components/blog-title/index.js.map +1 -1
  6. package/build/components/commands/index.js +8 -2
  7. package/build/components/commands/index.js.map +1 -1
  8. package/build/components/document-bar/index.js +1 -1
  9. package/build/components/document-bar/index.js.map +1 -1
  10. package/build/components/header/index.js +2 -3
  11. package/build/components/header/index.js.map +1 -1
  12. package/build/components/page-attributes/parent.js +6 -2
  13. package/build/components/page-attributes/parent.js.map +1 -1
  14. package/build/components/post-actions/actions.js +38 -344
  15. package/build/components/post-actions/actions.js.map +1 -1
  16. package/build/components/post-actions/index.js +16 -6
  17. package/build/components/post-actions/index.js.map +1 -1
  18. package/build/components/post-author/hook.js +10 -3
  19. package/build/components/post-author/hook.js.map +1 -1
  20. package/build/components/post-author/panel.js +2 -1
  21. package/build/components/post-author/panel.js.map +1 -1
  22. package/build/components/post-card-panel/index.js +1 -1
  23. package/build/components/post-card-panel/index.js.map +1 -1
  24. package/build/components/post-comments/index.js +6 -20
  25. package/build/components/post-comments/index.js.map +1 -1
  26. package/build/components/post-status/index.js +17 -41
  27. package/build/components/post-status/index.js.map +1 -1
  28. package/build/components/post-template/create-new-template-modal.js +3 -0
  29. package/build/components/post-template/create-new-template-modal.js.map +1 -1
  30. package/build/components/post-url/panel.js +3 -2
  31. package/build/components/post-url/panel.js.map +1 -1
  32. package/build/components/preview-dropdown/index.js +82 -17
  33. package/build/components/preview-dropdown/index.js.map +1 -1
  34. package/build/components/provider/disable-non-page-content-blocks.js +14 -18
  35. package/build/components/provider/disable-non-page-content-blocks.js.map +1 -1
  36. package/build/components/site-discussion/index.js +6 -20
  37. package/build/components/site-discussion/index.js.map +1 -1
  38. package/build/components/template-content-panel/index.js +14 -12
  39. package/build/components/template-content-panel/index.js.map +1 -1
  40. package/build/components/visual-editor/index.js +2 -1
  41. package/build/components/visual-editor/index.js.map +1 -1
  42. package/build/dataviews/actions/export-pattern.native.js +9 -0
  43. package/build/dataviews/actions/export-pattern.native.js.map +1 -0
  44. package/build/dataviews/actions/permanently-delete-post.js +107 -0
  45. package/build/dataviews/actions/permanently-delete-post.js.map +1 -0
  46. package/build/dataviews/actions/restore-post.js +112 -0
  47. package/build/dataviews/actions/restore-post.js.map +1 -0
  48. package/build/dataviews/actions/trash-post.js +142 -0
  49. package/build/dataviews/actions/trash-post.js.map +1 -0
  50. package/build/dataviews/store/private-actions.js +45 -0
  51. package/build/dataviews/store/private-actions.js.map +1 -1
  52. package/build/dataviews/store/private-selectors.js +10 -10
  53. package/build/dataviews/store/private-selectors.js.map +1 -1
  54. package/build/dataviews/store/reducer.js +15 -1
  55. package/build/dataviews/store/reducer.js.map +1 -1
  56. package/build/dataviews/types.js.map +1 -1
  57. package/build/private-apis.js +0 -2
  58. package/build/private-apis.js.map +1 -1
  59. package/build/store/actions.js +16 -2
  60. package/build/store/actions.js.map +1 -1
  61. package/build/store/private-actions.js +8 -1
  62. package/build/store/private-actions.js.map +1 -1
  63. package/build/store/private-selectors.js +33 -2
  64. package/build/store/private-selectors.js.map +1 -1
  65. package/build-module/bindings/post-meta.js +12 -0
  66. package/build-module/bindings/post-meta.js.map +1 -1
  67. package/build-module/components/blog-title/index.js +1 -1
  68. package/build-module/components/blog-title/index.js.map +1 -1
  69. package/build-module/components/commands/index.js +8 -2
  70. package/build-module/components/commands/index.js.map +1 -1
  71. package/build-module/components/document-bar/index.js +1 -1
  72. package/build-module/components/document-bar/index.js.map +1 -1
  73. package/build-module/components/header/index.js +2 -3
  74. package/build-module/components/header/index.js.map +1 -1
  75. package/build-module/components/page-attributes/parent.js +7 -3
  76. package/build-module/components/page-attributes/parent.js.map +1 -1
  77. package/build-module/components/post-actions/actions.js +44 -350
  78. package/build-module/components/post-actions/actions.js.map +1 -1
  79. package/build-module/components/post-actions/index.js +16 -6
  80. package/build-module/components/post-actions/index.js.map +1 -1
  81. package/build-module/components/post-author/hook.js +10 -3
  82. package/build-module/components/post-author/hook.js.map +1 -1
  83. package/build-module/components/post-author/panel.js +2 -1
  84. package/build-module/components/post-author/panel.js.map +1 -1
  85. package/build-module/components/post-card-panel/index.js +1 -1
  86. package/build-module/components/post-card-panel/index.js.map +1 -1
  87. package/build-module/components/post-comments/index.js +7 -23
  88. package/build-module/components/post-comments/index.js.map +1 -1
  89. package/build-module/components/post-status/index.js +19 -43
  90. package/build-module/components/post-status/index.js.map +1 -1
  91. package/build-module/components/post-template/create-new-template-modal.js +3 -0
  92. package/build-module/components/post-template/create-new-template-modal.js.map +1 -1
  93. package/build-module/components/post-url/panel.js +4 -5
  94. package/build-module/components/post-url/panel.js.map +1 -1
  95. package/build-module/components/preview-dropdown/index.js +84 -19
  96. package/build-module/components/preview-dropdown/index.js.map +1 -1
  97. package/build-module/components/provider/disable-non-page-content-blocks.js +15 -19
  98. package/build-module/components/provider/disable-non-page-content-blocks.js.map +1 -1
  99. package/build-module/components/site-discussion/index.js +7 -21
  100. package/build-module/components/site-discussion/index.js.map +1 -1
  101. package/build-module/components/template-content-panel/index.js +15 -13
  102. package/build-module/components/template-content-panel/index.js.map +1 -1
  103. package/build-module/components/visual-editor/index.js +2 -1
  104. package/build-module/components/visual-editor/index.js.map +1 -1
  105. package/build-module/dataviews/actions/export-pattern.native.js +3 -0
  106. package/build-module/dataviews/actions/export-pattern.native.js.map +1 -0
  107. package/build-module/dataviews/actions/permanently-delete-post.js +99 -0
  108. package/build-module/dataviews/actions/permanently-delete-post.js.map +1 -0
  109. package/build-module/dataviews/actions/restore-post.js +104 -0
  110. package/build-module/dataviews/actions/restore-post.js.map +1 -0
  111. package/build-module/dataviews/actions/trash-post.js +135 -0
  112. package/build-module/dataviews/actions/trash-post.js.map +1 -0
  113. package/build-module/dataviews/store/private-actions.js +40 -0
  114. package/build-module/dataviews/store/private-actions.js.map +1 -1
  115. package/build-module/dataviews/store/private-selectors.js +8 -9
  116. package/build-module/dataviews/store/private-selectors.js.map +1 -1
  117. package/build-module/dataviews/store/reducer.js +15 -1
  118. package/build-module/dataviews/store/reducer.js.map +1 -1
  119. package/build-module/dataviews/types.js.map +1 -1
  120. package/build-module/private-apis.js +0 -2
  121. package/build-module/private-apis.js.map +1 -1
  122. package/build-module/store/actions.js +16 -2
  123. package/build-module/store/actions.js.map +1 -1
  124. package/build-module/store/private-actions.js +8 -1
  125. package/build-module/store/private-actions.js.map +1 -1
  126. package/build-module/store/private-selectors.js +32 -2
  127. package/build-module/store/private-selectors.js.map +1 -1
  128. package/build-style/style-rtl.css +19 -3
  129. package/build-style/style.css +19 -3
  130. package/build-types/bindings/post-meta.d.ts +6 -0
  131. package/build-types/bindings/post-meta.d.ts.map +1 -1
  132. package/build-types/components/commands/index.d.ts.map +1 -1
  133. package/build-types/components/header/index.d.ts.map +1 -1
  134. package/build-types/components/page-attributes/parent.d.ts.map +1 -1
  135. package/build-types/components/post-actions/actions.d.ts.map +1 -1
  136. package/build-types/components/post-actions/index.d.ts.map +1 -1
  137. package/build-types/components/post-author/hook.d.ts +1 -1
  138. package/build-types/components/post-author/hook.d.ts.map +1 -1
  139. package/build-types/components/post-author/panel.d.ts.map +1 -1
  140. package/build-types/components/post-comments/index.d.ts.map +1 -1
  141. package/build-types/components/post-status/index.d.ts +2 -1
  142. package/build-types/components/post-status/index.d.ts.map +1 -1
  143. package/build-types/components/post-template/create-new-template-modal.d.ts.map +1 -1
  144. package/build-types/components/post-url/panel.d.ts.map +1 -1
  145. package/build-types/components/preview-dropdown/index.d.ts.map +1 -1
  146. package/build-types/components/provider/disable-non-page-content-blocks.d.ts.map +1 -1
  147. package/build-types/components/site-discussion/index.d.ts.map +1 -1
  148. package/build-types/components/template-content-panel/index.d.ts.map +1 -1
  149. package/build-types/components/visual-editor/index.d.ts.map +1 -1
  150. package/build-types/dataviews/actions/export-pattern.native.d.ts +3 -0
  151. package/build-types/dataviews/actions/export-pattern.native.d.ts.map +1 -0
  152. package/build-types/dataviews/actions/permanently-delete-post.d.ts +5 -0
  153. package/build-types/dataviews/actions/permanently-delete-post.d.ts.map +1 -0
  154. package/build-types/dataviews/actions/restore-post.d.ts +5 -0
  155. package/build-types/dataviews/actions/restore-post.d.ts.map +1 -0
  156. package/build-types/dataviews/actions/trash-post.d.ts +5 -0
  157. package/build-types/dataviews/actions/trash-post.d.ts.map +1 -0
  158. package/build-types/dataviews/store/private-actions.d.ts +8 -3
  159. package/build-types/dataviews/store/private-actions.d.ts.map +1 -1
  160. package/build-types/dataviews/store/private-selectors.d.ts +2 -1
  161. package/build-types/dataviews/store/private-selectors.d.ts.map +1 -1
  162. package/build-types/dataviews/store/reducer.d.ts +4 -1
  163. package/build-types/dataviews/store/reducer.d.ts.map +1 -1
  164. package/build-types/dataviews/types.d.ts +9 -0
  165. package/build-types/dataviews/types.d.ts.map +1 -1
  166. package/build-types/private-apis.d.ts.map +1 -1
  167. package/build-types/store/actions.d.ts.map +1 -1
  168. package/build-types/store/private-actions.d.ts.map +1 -1
  169. package/build-types/store/private-selectors.d.ts +11 -0
  170. package/build-types/store/private-selectors.d.ts.map +1 -1
  171. package/build-types/store/reducer.d.ts +1 -0
  172. package/build-types/store/reducer.d.ts.map +1 -1
  173. package/package.json +36 -36
  174. package/src/bindings/post-meta.js +20 -0
  175. package/src/components/blog-title/index.js +1 -1
  176. package/src/components/commands/index.js +4 -2
  177. package/src/components/document-bar/index.js +1 -1
  178. package/src/components/document-bar/style.scss +1 -1
  179. package/src/components/editor-interface/style.scss +5 -0
  180. package/src/components/header/index.js +1 -2
  181. package/src/components/list-view-sidebar/style.scss +4 -0
  182. package/src/components/page-attributes/parent.js +25 -7
  183. package/src/components/post-actions/actions.js +47 -470
  184. package/src/components/post-actions/index.js +19 -7
  185. package/src/components/post-author/hook.js +11 -3
  186. package/src/components/post-author/panel.js +3 -1
  187. package/src/components/post-card-panel/index.js +1 -1
  188. package/src/components/post-comments/index.js +7 -20
  189. package/src/components/post-publish-panel/test/__snapshots__/index.js.snap +2 -2
  190. package/src/components/post-status/index.js +11 -41
  191. package/src/components/post-template/create-new-template-modal.js +7 -1
  192. package/src/components/post-url/panel.js +8 -2
  193. package/src/components/preview-dropdown/index.js +113 -35
  194. package/src/components/preview-dropdown/style.scss +5 -0
  195. package/src/components/provider/disable-non-page-content-blocks.js +27 -24
  196. package/src/components/site-discussion/index.js +7 -19
  197. package/src/components/template-content-panel/index.js +36 -21
  198. package/src/components/visual-editor/index.js +8 -6
  199. package/src/components/visual-editor/style.scss +1 -3
  200. package/src/dataviews/actions/export-pattern.native.tsx +3 -0
  201. package/src/dataviews/actions/permanently-delete-post.tsx +116 -0
  202. package/src/dataviews/actions/restore-post.tsx +134 -0
  203. package/src/dataviews/actions/trash-post.tsx +196 -0
  204. package/src/dataviews/store/private-actions.ts +68 -0
  205. package/src/dataviews/store/private-selectors.ts +9 -17
  206. package/src/dataviews/store/reducer.ts +20 -1
  207. package/src/dataviews/types.ts +11 -0
  208. package/src/private-apis.js +0 -2
  209. package/src/store/actions.js +36 -13
  210. package/src/store/private-actions.js +8 -4
  211. package/src/store/private-selectors.js +45 -2
  212. package/src/store/test/private-selectors.js +78 -0
  213. package/tsconfig.tsbuildinfo +1 -1
  214. package/build/dataviews/actions/index.js +0 -32
  215. package/build/dataviews/actions/index.js.map +0 -1
  216. package/build-module/dataviews/actions/index.js +0 -24
  217. package/build-module/dataviews/actions/index.js.map +0 -1
  218. package/build-types/dataviews/actions/index.d.ts +0 -2
  219. package/build-types/dataviews/actions/index.d.ts.map +0 -1
  220. package/src/components/document-outline/test/__snapshots__/index.js.snap +0 -111
  221. package/src/components/document-outline/test/index.js +0 -185
  222. package/src/dataviews/actions/index.ts +0 -25
@@ -1,24 +1,22 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { external, trash, backup } from '@wordpress/icons';
4
+ import { external } from '@wordpress/icons';
5
5
  import { addQueryArgs } from '@wordpress/url';
6
- import { useDispatch, useSelect, useRegistry } from '@wordpress/data';
6
+ import { useDispatch, useSelect } from '@wordpress/data';
7
7
  import { decodeEntities } from '@wordpress/html-entities';
8
8
  import { store as coreStore } from '@wordpress/core-data';
9
- import { __, _n, sprintf, _x } from '@wordpress/i18n';
9
+ import { __, sprintf, _x } from '@wordpress/i18n';
10
10
  import { store as noticesStore } from '@wordpress/notices';
11
- import { useMemo, useState } from '@wordpress/element';
11
+ import { useMemo, useState, useEffect } from '@wordpress/element';
12
12
  import { privateApis as patternsPrivateApis } from '@wordpress/patterns';
13
13
  import { parse } from '@wordpress/blocks';
14
- import { DataForm } from '@wordpress/dataviews';
14
+ import { DataForm, isItemValid } from '@wordpress/dataviews';
15
15
  import {
16
16
  Button,
17
17
  TextControl,
18
- __experimentalText as Text,
19
18
  __experimentalHStack as HStack,
20
19
  __experimentalVStack as VStack,
21
- __experimentalNumberControl as NumberControl,
22
20
  } from '@wordpress/components';
23
21
 
24
22
  /**
@@ -39,19 +37,29 @@ import { getItemTitle } from '../../dataviews/actions/utils';
39
37
  const { PATTERN_TYPES, CreatePatternModalContents, useDuplicatePatternProps } =
40
38
  unlock( patternsPrivateApis );
41
39
 
42
- // TODO: this should be shared with other components (page-pages).
40
+ // TODO: this should be shared with other components (see post-fields in edit-site).
43
41
  const fields = [
44
42
  {
45
43
  type: 'text',
46
- header: __( 'Title' ),
47
44
  id: 'title',
45
+ label: __( 'Title' ),
48
46
  placeholder: __( 'No title' ),
49
47
  getValue: ( { item } ) => item.title,
50
48
  },
49
+ {
50
+ type: 'integer',
51
+ id: 'menu_order',
52
+ label: __( 'Order' ),
53
+ description: __( 'Determines the order of pages.' ),
54
+ },
51
55
  ];
52
56
 
53
- const form = {
54
- visibleFields: [ 'title' ],
57
+ const formDuplicateAction = {
58
+ fields: [ 'title' ],
59
+ };
60
+
61
+ const formOrderAction = {
62
+ fields: [ 'menu_order' ],
55
63
  };
56
64
 
57
65
  /**
@@ -73,406 +81,6 @@ function isTemplateRemovable( template ) {
73
81
  );
74
82
  }
75
83
 
76
- const trashPostAction = {
77
- id: 'move-to-trash',
78
- label: __( 'Move to Trash' ),
79
- isPrimary: true,
80
- icon: trash,
81
- isEligible( item ) {
82
- return ! [ 'auto-draft', 'trash' ].includes( item.status );
83
- },
84
- supportsBulk: true,
85
- hideModalHeader: true,
86
- RenderModal: ( { items, closeModal, onActionPerformed } ) => {
87
- const [ isBusy, setIsBusy ] = useState( false );
88
- const { createSuccessNotice, createErrorNotice } =
89
- useDispatch( noticesStore );
90
- const { deleteEntityRecord } = useDispatch( coreStore );
91
- return (
92
- <VStack spacing="5">
93
- <Text>
94
- { items.length === 1
95
- ? sprintf(
96
- // translators: %s: The item's title.
97
- __(
98
- 'Are you sure you want to move to trash "%s"?'
99
- ),
100
- getItemTitle( items[ 0 ] )
101
- )
102
- : sprintf(
103
- // translators: %d: The number of items (2 or more).
104
- _n(
105
- 'Are you sure you want to move to trash %d item?',
106
- 'Are you sure you want to move to trash %d items?',
107
- items.length
108
- ),
109
- items.length
110
- ) }
111
- </Text>
112
- <HStack justify="right">
113
- <Button
114
- variant="tertiary"
115
- onClick={ closeModal }
116
- disabled={ isBusy }
117
- accessibleWhenDisabled
118
- >
119
- { __( 'Cancel' ) }
120
- </Button>
121
- <Button
122
- variant="primary"
123
- onClick={ async () => {
124
- setIsBusy( true );
125
- const promiseResult = await Promise.allSettled(
126
- items.map( ( item ) =>
127
- deleteEntityRecord(
128
- 'postType',
129
- item.type,
130
- item.id,
131
- {},
132
- { throwOnError: true }
133
- )
134
- )
135
- );
136
- // If all the promises were fulfilled with success.
137
- if (
138
- promiseResult.every(
139
- ( { status } ) => status === 'fulfilled'
140
- )
141
- ) {
142
- let successMessage;
143
- if ( promiseResult.length === 1 ) {
144
- successMessage = sprintf(
145
- /* translators: The item's title. */
146
- __( '"%s" moved to trash.' ),
147
- getItemTitle( items[ 0 ] )
148
- );
149
- } else {
150
- successMessage = sprintf(
151
- /* translators: The number of items. */
152
- _n(
153
- '%s item moved to trash.',
154
- '%s items moved to trash.',
155
- items.length
156
- ),
157
- items.length
158
- );
159
- }
160
- createSuccessNotice( successMessage, {
161
- type: 'snackbar',
162
- id: 'move-to-trash-action',
163
- } );
164
- } else {
165
- // If there was at least one failure.
166
- let errorMessage;
167
- // If we were trying to delete a single item.
168
- if ( promiseResult.length === 1 ) {
169
- if ( promiseResult[ 0 ].reason?.message ) {
170
- errorMessage =
171
- promiseResult[ 0 ].reason.message;
172
- } else {
173
- errorMessage = __(
174
- 'An error occurred while moving to trash the item.'
175
- );
176
- }
177
- // If we were trying to delete multiple items.
178
- } else {
179
- const errorMessages = new Set();
180
- const failedPromises = promiseResult.filter(
181
- ( { status } ) => status === 'rejected'
182
- );
183
- for ( const failedPromise of failedPromises ) {
184
- if ( failedPromise.reason?.message ) {
185
- errorMessages.add(
186
- failedPromise.reason.message
187
- );
188
- }
189
- }
190
- if ( errorMessages.size === 0 ) {
191
- errorMessage = __(
192
- 'An error occurred while moving to trash the items.'
193
- );
194
- } else if ( errorMessages.size === 1 ) {
195
- errorMessage = sprintf(
196
- /* translators: %s: an error message */
197
- __(
198
- 'An error occurred while moving to trash the item: %s'
199
- ),
200
- [ ...errorMessages ][ 0 ]
201
- );
202
- } else {
203
- errorMessage = sprintf(
204
- /* translators: %s: a list of comma separated error messages */
205
- __(
206
- 'Some errors occurred while moving to trash the items: %s'
207
- ),
208
- [ ...errorMessages ].join( ',' )
209
- );
210
- }
211
- }
212
- createErrorNotice( errorMessage, {
213
- type: 'snackbar',
214
- } );
215
- }
216
- if ( onActionPerformed ) {
217
- onActionPerformed( items );
218
- }
219
- setIsBusy( false );
220
- closeModal();
221
- } }
222
- isBusy={ isBusy }
223
- disabled={ isBusy }
224
- accessibleWhenDisabled
225
- >
226
- { __( 'Trash' ) }
227
- </Button>
228
- </HStack>
229
- </VStack>
230
- );
231
- },
232
- };
233
-
234
- function useCanUserEligibilityCheckPostType( capability, postType, action ) {
235
- const registry = useRegistry();
236
- return useMemo(
237
- () => ( {
238
- ...action,
239
- isEligible( item ) {
240
- return (
241
- action.isEligible( item ) &&
242
- registry.select( coreStore ).canUser( capability, {
243
- kind: 'postType',
244
- name: postType,
245
- id: item.id,
246
- } )
247
- );
248
- },
249
- } ),
250
- [ action, registry, capability, postType ]
251
- );
252
- }
253
-
254
- function useTrashPostAction( postType ) {
255
- return useCanUserEligibilityCheckPostType(
256
- 'delete',
257
- postType,
258
- trashPostAction
259
- );
260
- }
261
-
262
- const permanentlyDeletePostAction = {
263
- id: 'permanently-delete',
264
- label: __( 'Permanently delete' ),
265
- supportsBulk: true,
266
- isEligible( { status } ) {
267
- return status === 'trash';
268
- },
269
- async callback( posts, { registry, onActionPerformed } ) {
270
- const { createSuccessNotice, createErrorNotice } =
271
- registry.dispatch( noticesStore );
272
- const { deleteEntityRecord } = registry.dispatch( coreStore );
273
- const promiseResult = await Promise.allSettled(
274
- posts.map( ( post ) => {
275
- return deleteEntityRecord(
276
- 'postType',
277
- post.type,
278
- post.id,
279
- { force: true },
280
- { throwOnError: true }
281
- );
282
- } )
283
- );
284
- // If all the promises were fulfilled with success.
285
- if ( promiseResult.every( ( { status } ) => status === 'fulfilled' ) ) {
286
- let successMessage;
287
- if ( promiseResult.length === 1 ) {
288
- successMessage = sprintf(
289
- /* translators: The posts's title. */
290
- __( '"%s" permanently deleted.' ),
291
- getItemTitle( posts[ 0 ] )
292
- );
293
- } else {
294
- successMessage = __( 'The posts were permanently deleted.' );
295
- }
296
- createSuccessNotice( successMessage, {
297
- type: 'snackbar',
298
- id: 'permanently-delete-post-action',
299
- } );
300
- onActionPerformed?.( posts );
301
- } else {
302
- // If there was at lease one failure.
303
- let errorMessage;
304
- // If we were trying to permanently delete a single post.
305
- if ( promiseResult.length === 1 ) {
306
- if ( promiseResult[ 0 ].reason?.message ) {
307
- errorMessage = promiseResult[ 0 ].reason.message;
308
- } else {
309
- errorMessage = __(
310
- 'An error occurred while permanently deleting the post.'
311
- );
312
- }
313
- // If we were trying to permanently delete multiple posts
314
- } else {
315
- const errorMessages = new Set();
316
- const failedPromises = promiseResult.filter(
317
- ( { status } ) => status === 'rejected'
318
- );
319
- for ( const failedPromise of failedPromises ) {
320
- if ( failedPromise.reason?.message ) {
321
- errorMessages.add( failedPromise.reason.message );
322
- }
323
- }
324
- if ( errorMessages.size === 0 ) {
325
- errorMessage = __(
326
- 'An error occurred while permanently deleting the posts.'
327
- );
328
- } else if ( errorMessages.size === 1 ) {
329
- errorMessage = sprintf(
330
- /* translators: %s: an error message */
331
- __(
332
- 'An error occurred while permanently deleting the posts: %s'
333
- ),
334
- [ ...errorMessages ][ 0 ]
335
- );
336
- } else {
337
- errorMessage = sprintf(
338
- /* translators: %s: a list of comma separated error messages */
339
- __(
340
- 'Some errors occurred while permanently deleting the posts: %s'
341
- ),
342
- [ ...errorMessages ].join( ',' )
343
- );
344
- }
345
- }
346
- createErrorNotice( errorMessage, {
347
- type: 'snackbar',
348
- } );
349
- }
350
- },
351
- };
352
-
353
- function usePermanentlyDeletePostAction( postType ) {
354
- return useCanUserEligibilityCheckPostType(
355
- 'delete',
356
- postType,
357
- permanentlyDeletePostAction
358
- );
359
- }
360
-
361
- const restorePostAction = {
362
- id: 'restore',
363
- label: __( 'Restore' ),
364
- isPrimary: true,
365
- icon: backup,
366
- supportsBulk: true,
367
- isEligible( { status } ) {
368
- return status === 'trash';
369
- },
370
- async callback( posts, { registry, onActionPerformed } ) {
371
- const { createSuccessNotice, createErrorNotice } =
372
- registry.dispatch( noticesStore );
373
- const { editEntityRecord, saveEditedEntityRecord } =
374
- registry.dispatch( coreStore );
375
- await Promise.allSettled(
376
- posts.map( ( post ) => {
377
- return editEntityRecord( 'postType', post.type, post.id, {
378
- status: 'draft',
379
- } );
380
- } )
381
- );
382
- const promiseResult = await Promise.allSettled(
383
- posts.map( ( post ) => {
384
- return saveEditedEntityRecord( 'postType', post.type, post.id, {
385
- throwOnError: true,
386
- } );
387
- } )
388
- );
389
-
390
- if ( promiseResult.every( ( { status } ) => status === 'fulfilled' ) ) {
391
- let successMessage;
392
- if ( posts.length === 1 ) {
393
- successMessage = sprintf(
394
- /* translators: The number of posts. */
395
- __( '"%s" has been restored.' ),
396
- getItemTitle( posts[ 0 ] )
397
- );
398
- } else if ( posts[ 0 ].type === 'page' ) {
399
- successMessage = sprintf(
400
- /* translators: The number of posts. */
401
- __( '%d pages have been restored.' ),
402
- posts.length
403
- );
404
- } else {
405
- successMessage = sprintf(
406
- /* translators: The number of posts. */
407
- __( '%d posts have been restored.' ),
408
- posts.length
409
- );
410
- }
411
- createSuccessNotice( successMessage, {
412
- type: 'snackbar',
413
- id: 'restore-post-action',
414
- } );
415
- if ( onActionPerformed ) {
416
- onActionPerformed( posts );
417
- }
418
- } else {
419
- // If there was at lease one failure.
420
- let errorMessage;
421
- // If we were trying to move a single post to the trash.
422
- if ( promiseResult.length === 1 ) {
423
- if ( promiseResult[ 0 ].reason?.message ) {
424
- errorMessage = promiseResult[ 0 ].reason.message;
425
- } else {
426
- errorMessage = __(
427
- 'An error occurred while restoring the post.'
428
- );
429
- }
430
- // If we were trying to move multiple posts to the trash
431
- } else {
432
- const errorMessages = new Set();
433
- const failedPromises = promiseResult.filter(
434
- ( { status } ) => status === 'rejected'
435
- );
436
- for ( const failedPromise of failedPromises ) {
437
- if ( failedPromise.reason?.message ) {
438
- errorMessages.add( failedPromise.reason.message );
439
- }
440
- }
441
- if ( errorMessages.size === 0 ) {
442
- errorMessage = __(
443
- 'An error occurred while restoring the posts.'
444
- );
445
- } else if ( errorMessages.size === 1 ) {
446
- errorMessage = sprintf(
447
- /* translators: %s: an error message */
448
- __( 'An error occurred while restoring the posts: %s' ),
449
- [ ...errorMessages ][ 0 ]
450
- );
451
- } else {
452
- errorMessage = sprintf(
453
- /* translators: %s: a list of comma separated error messages */
454
- __(
455
- 'Some errors occurred while restoring the posts: %s'
456
- ),
457
- [ ...errorMessages ].join( ',' )
458
- );
459
- }
460
- }
461
- createErrorNotice( errorMessage, {
462
- type: 'snackbar',
463
- } );
464
- }
465
- },
466
- };
467
-
468
- function useRestorePostAction( postType ) {
469
- return useCanUserEligibilityCheckPostType(
470
- 'update',
471
- postType,
472
- restorePostAction
473
- );
474
- }
475
-
476
84
  const viewPostAction = {
477
85
  id: 'view-post',
478
86
  label: __( 'View' ),
@@ -539,11 +147,15 @@ const renamePostAction = {
539
147
  ...Object.values( PATTERN_TYPES ),
540
148
  ].includes( post.type )
541
149
  ) {
542
- return true;
150
+ return post.permissions?.update;
543
151
  }
544
152
  // In the case of templates, we can only rename custom templates.
545
153
  if ( post.type === TEMPLATE_POST_TYPE ) {
546
- return isTemplateRemovable( post ) && post.is_custom;
154
+ return (
155
+ isTemplateRemovable( post ) &&
156
+ post.is_custom &&
157
+ post.permissions?.update
158
+ );
547
159
  }
548
160
  // Make necessary checks for template parts and patterns.
549
161
  const isTemplatePart = post.type === TEMPLATE_PART_POST_TYPE;
@@ -555,7 +167,7 @@ const renamePostAction = {
555
167
  isUserPattern ||
556
168
  ( isTemplatePart && post.source === TEMPLATE_ORIGINS.custom );
557
169
  const hasThemeFile = post?.has_theme_file;
558
- return isCustomPattern && ! hasThemeFile;
170
+ return isCustomPattern && ! hasThemeFile && post.permissions?.update;
559
171
  },
560
172
  RenderModal: ( { items, closeModal, onActionPerformed } ) => {
561
173
  const [ item ] = items;
@@ -626,30 +238,21 @@ const renamePostAction = {
626
238
  },
627
239
  };
628
240
 
629
- function useRenamePostAction( postType ) {
630
- return useCanUserEligibilityCheckPostType(
631
- 'update',
632
- postType,
633
- renamePostAction
634
- );
635
- }
636
-
637
241
  function ReorderModal( { items, closeModal, onActionPerformed } ) {
638
- const [ item ] = items;
242
+ const [ item, setItem ] = useState( items[ 0 ] );
243
+ const orderInput = item.menu_order;
639
244
  const { editEntityRecord, saveEditedEntityRecord } =
640
245
  useDispatch( coreStore );
641
246
  const { createSuccessNotice, createErrorNotice } =
642
247
  useDispatch( noticesStore );
643
- const [ orderInput, setOrderInput ] = useState( item.menu_order );
644
248
 
645
249
  async function onOrder( event ) {
646
250
  event.preventDefault();
647
- if (
648
- ! Number.isInteger( Number( orderInput ) ) ||
649
- orderInput?.trim?.() === ''
650
- ) {
251
+
252
+ if ( ! isItemValid( item, fields, formOrderAction ) ) {
651
253
  return;
652
254
  }
255
+
653
256
  try {
654
257
  await editEntityRecord( 'postType', item.type, item.id, {
655
258
  menu_order: orderInput,
@@ -673,9 +276,7 @@ function ReorderModal( { items, closeModal, onActionPerformed } ) {
673
276
  } );
674
277
  }
675
278
  }
676
- const saveIsDisabled =
677
- ! Number.isInteger( Number( orderInput ) ) ||
678
- orderInput?.trim?.() === '';
279
+ const isSaveDisabled = ! isItemValid( item, fields, formOrderAction );
679
280
  return (
680
281
  <form onSubmit={ onOrder }>
681
282
  <VStack spacing="5">
@@ -684,12 +285,11 @@ function ReorderModal( { items, closeModal, onActionPerformed } ) {
684
285
  'Determines the order of pages. Pages with the same order value are sorted alphabetically. Negative order values are supported.'
685
286
  ) }
686
287
  </div>
687
- <NumberControl
688
- __next40pxDefaultSize
689
- label={ __( 'Order' ) }
690
- help={ __( 'Set the page order.' ) }
691
- value={ orderInput }
692
- onChange={ setOrderInput }
288
+ <DataForm
289
+ data={ item }
290
+ fields={ fields }
291
+ form={ formOrderAction }
292
+ onChange={ setItem }
693
293
  />
694
294
  <HStack justify="right">
695
295
  <Button
@@ -706,7 +306,7 @@ function ReorderModal( { items, closeModal, onActionPerformed } ) {
706
306
  variant="primary"
707
307
  type="submit"
708
308
  accessibleWhenDisabled
709
- disabled={ saveIsDisabled }
309
+ disabled={ isSaveDisabled }
710
310
  __experimentalIsFocusable
711
311
  >
712
312
  { __( 'Save' ) }
@@ -873,7 +473,7 @@ const useDuplicatePostAction = ( postType ) => {
873
473
  <DataForm
874
474
  data={ item }
875
475
  fields={ fields }
876
- form={ form }
476
+ form={ formDuplicateAction }
877
477
  onChange={ setItem }
878
478
  />
879
479
  <HStack spacing={ 2 } justify="end">
@@ -974,36 +574,27 @@ export const duplicateTemplatePartAction = {
974
574
  };
975
575
 
976
576
  export function usePostActions( { postType, onActionPerformed, context } ) {
977
- const {
978
- defaultActions,
979
- postTypeObject,
980
- userCanCreatePostType,
981
- cachedCanUserResolvers,
982
- } = useSelect(
577
+ const { defaultActions, postTypeObject, userCanCreatePostType } = useSelect(
983
578
  ( select ) => {
984
- const { getPostType, canUser, getCachedResolvers } =
985
- select( coreStore );
579
+ const { getPostType, canUser } = select( coreStore );
986
580
  const { getEntityActions } = unlock( select( editorStore ) );
987
- const _postTypeObject = getPostType( postType );
988
581
  return {
989
- postTypeObject: _postTypeObject,
582
+ postTypeObject: getPostType( postType ),
990
583
  defaultActions: getEntityActions( 'postType', postType ),
991
584
  userCanCreatePostType: canUser( 'create', {
992
585
  kind: 'postType',
993
586
  name: postType,
994
587
  } ),
995
- cachedCanUserResolvers: getCachedResolvers()?.canUser,
996
588
  };
997
589
  },
998
590
  [ postType ]
999
591
  );
592
+ const { registerPostTypeActions } = unlock( useDispatch( editorStore ) );
593
+ useEffect( () => {
594
+ registerPostTypeActions( postType );
595
+ }, [ registerPostTypeActions, postType ] );
1000
596
 
1001
597
  const duplicatePostAction = useDuplicatePostAction( postType );
1002
- const trashPostActionForPostType = useTrashPostAction( postType );
1003
- const permanentlyDeletePostActionForPostType =
1004
- usePermanentlyDeletePostAction( postType );
1005
- const renamePostActionForPostType = useRenamePostAction( postType );
1006
- const restorePostActionForPostType = useRestorePostAction( postType );
1007
598
  const reorderPagesAction = useReorderPagesAction( postType );
1008
599
  const isTemplateOrTemplatePart = [
1009
600
  TEMPLATE_POST_TYPE,
@@ -1030,14 +621,8 @@ export function usePostActions( { postType, onActionPerformed, context } ) {
1030
621
  userCanCreatePostType &&
1031
622
  duplicateTemplatePartAction,
1032
623
  isPattern && userCanCreatePostType && duplicatePatternAction,
1033
- supportsTitle && renamePostActionForPostType,
624
+ supportsTitle && renamePostAction,
1034
625
  reorderPagesAction,
1035
- ! isTemplateOrTemplatePart && restorePostActionForPostType,
1036
- ! isTemplateOrTemplatePart &&
1037
- ! isPattern &&
1038
- trashPostActionForPostType,
1039
- ! isTemplateOrTemplatePart &&
1040
- permanentlyDeletePostActionForPostType,
1041
626
  ...defaultActions,
1042
627
  ].filter( Boolean );
1043
628
  // Filter actions based on provided context. If not provided
@@ -1101,9 +686,6 @@ export function usePostActions( { postType, onActionPerformed, context } ) {
1101
686
  }
1102
687
 
1103
688
  return actions;
1104
- // We are making this use memo depend on cachedCanUserResolvers as a way to make the component using this hook re-render
1105
- // when user capabilities are resolved. This makes sure the isEligible functions of actions dependent on capabilities are re-evaluated.
1106
- // eslint-disable-next-line react-hooks/exhaustive-deps
1107
689
  }, [
1108
690
  defaultActions,
1109
691
  userCanCreatePostType,
@@ -1112,15 +694,10 @@ export function usePostActions( { postType, onActionPerformed, context } ) {
1112
694
  postTypeObject?.viewable,
1113
695
  duplicatePostAction,
1114
696
  reorderPagesAction,
1115
- trashPostActionForPostType,
1116
- restorePostActionForPostType,
1117
- renamePostActionForPostType,
1118
- permanentlyDeletePostActionForPostType,
1119
697
  onActionPerformed,
1120
698
  isLoaded,
1121
699
  supportsRevisions,
1122
700
  supportsTitle,
1123
701
  context,
1124
- cachedCanUserResolvers,
1125
702
  ] );
1126
703
  }
@@ -29,26 +29,38 @@ const {
29
29
 
30
30
  export default function PostActions( { onActionPerformed, buttonProps } ) {
31
31
  const [ isActionsMenuOpen, setIsActionsMenuOpen ] = useState( false );
32
- const { item, postType } = useSelect( ( select ) => {
32
+ const { item, permissions, postType } = useSelect( ( select ) => {
33
33
  const { getCurrentPostType, getCurrentPostId } = select( editorStore );
34
- const { getEditedEntityRecord } = select( coreStore );
34
+ const { getEditedEntityRecord, getEntityRecordPermissions } = unlock(
35
+ select( coreStore )
36
+ );
35
37
  const _postType = getCurrentPostType();
38
+ const _id = getCurrentPostId();
36
39
  return {
37
- item: getEditedEntityRecord(
40
+ item: getEditedEntityRecord( 'postType', _postType, _id ),
41
+ permissions: getEntityRecordPermissions(
38
42
  'postType',
39
43
  _postType,
40
- getCurrentPostId()
44
+ _id
41
45
  ),
42
46
  postType: _postType,
43
47
  };
44
48
  }, [] );
49
+ const itemWithPermissions = useMemo( () => {
50
+ return {
51
+ ...item,
52
+ permissions,
53
+ };
54
+ }, [ item, permissions ] );
45
55
  const allActions = usePostActions( { postType, onActionPerformed } );
46
56
 
47
57
  const actions = useMemo( () => {
48
58
  return allActions.filter( ( action ) => {
49
- return ! action.isEligible || action.isEligible( item );
59
+ return (
60
+ ! action.isEligible || action.isEligible( itemWithPermissions )
61
+ );
50
62
  } );
51
- }, [ allActions, item ] );
63
+ }, [ allActions, itemWithPermissions ] );
52
64
 
53
65
  return (
54
66
  <DropdownMenu
@@ -72,7 +84,7 @@ export default function PostActions( { onActionPerformed, buttonProps } ) {
72
84
  >
73
85
  <ActionsDropdownMenuGroup
74
86
  actions={ actions }
75
- item={ item }
87
+ item={ itemWithPermissions }
76
88
  onClose={ () => {
77
89
  setIsActionsMenuOpen( false );
78
90
  } }