@wordpress/editor 14.5.0 → 14.6.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 (216) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/bindings/post-meta.js +2 -2
  3. package/build/bindings/post-meta.js.map +1 -1
  4. package/build/components/create-template-part-modal/index.js +1 -0
  5. package/build/components/create-template-part-modal/index.js.map +1 -1
  6. package/build/components/global-styles-provider/index.js +17 -4
  7. package/build/components/global-styles-provider/index.js.map +1 -1
  8. package/build/components/inserter-sidebar/index.js +5 -2
  9. package/build/components/inserter-sidebar/index.js.map +1 -1
  10. package/build/components/page-attributes/parent.js +6 -5
  11. package/build/components/page-attributes/parent.js.map +1 -1
  12. package/build/components/post-actions/actions.js +4 -499
  13. package/build/components/post-actions/actions.js.map +1 -1
  14. package/build/components/post-actions/index.js +8 -17
  15. package/build/components/post-actions/index.js.map +1 -1
  16. package/build/components/post-card-panel/index.js +20 -20
  17. package/build/components/post-card-panel/index.js.map +1 -1
  18. package/build/components/post-featured-image/index.js +2 -0
  19. package/build/components/post-featured-image/index.js.map +1 -1
  20. package/build/components/post-publish-panel/postpublish.js +4 -0
  21. package/build/components/post-publish-panel/postpublish.js.map +1 -1
  22. package/build/components/post-slug/index.js +1 -0
  23. package/build/components/post-slug/index.js.map +1 -1
  24. package/build/components/post-taxonomies/hierarchical-term-selector.js +2 -1
  25. package/build/components/post-taxonomies/hierarchical-term-selector.js.map +1 -1
  26. package/build/components/post-url/index.js +6 -5
  27. package/build/components/post-url/index.js.map +1 -1
  28. package/build/components/sidebar/post-summary.js +10 -7
  29. package/build/components/sidebar/post-summary.js.map +1 -1
  30. package/build/components/template-content-panel/index.js +1 -1
  31. package/build/components/template-content-panel/index.js.map +1 -1
  32. package/build/dataviews/actions/duplicate-pattern.js +48 -0
  33. package/build/dataviews/actions/duplicate-pattern.js.map +1 -0
  34. package/build/dataviews/actions/duplicate-post.js +146 -0
  35. package/build/dataviews/actions/duplicate-post.js.map +1 -0
  36. package/build/dataviews/actions/duplicate-post.native.js +9 -0
  37. package/build/dataviews/actions/duplicate-post.native.js.map +1 -0
  38. package/build/dataviews/actions/duplicate-template-part.js +67 -0
  39. package/build/dataviews/actions/duplicate-template-part.js.map +1 -0
  40. package/build/dataviews/actions/rename-post.js +125 -0
  41. package/build/dataviews/actions/rename-post.js.map +1 -0
  42. package/build/dataviews/actions/reorder-page.js +116 -0
  43. package/build/dataviews/actions/reorder-page.js.map +1 -0
  44. package/build/dataviews/actions/reorder-page.native.js +9 -0
  45. package/build/dataviews/actions/reorder-page.native.js.map +1 -0
  46. package/build/dataviews/actions/reset-post.js +1 -1
  47. package/build/dataviews/actions/reset-post.js.map +1 -1
  48. package/build/dataviews/actions/utils.js +9 -1
  49. package/build/dataviews/actions/utils.js.map +1 -1
  50. package/build/dataviews/actions/view-post-revisions.js +49 -0
  51. package/build/dataviews/actions/view-post-revisions.js.map +1 -0
  52. package/build/dataviews/actions/view-post.js +36 -0
  53. package/build/dataviews/actions/view-post.js.map +1 -0
  54. package/build/dataviews/fields/index.js +32 -0
  55. package/build/dataviews/fields/index.js.map +1 -0
  56. package/build/dataviews/store/private-actions.js +16 -2
  57. package/build/dataviews/store/private-actions.js.map +1 -1
  58. package/build/dataviews/types.js.map +1 -1
  59. package/build/private-apis.js +2 -0
  60. package/build/private-apis.js.map +1 -1
  61. package/build/store/private-actions.js +1 -1
  62. package/build/store/private-actions.js.map +1 -1
  63. package/build/store/utils/is-template-revertable.js +1 -1
  64. package/build/store/utils/is-template-revertable.js.map +1 -1
  65. package/build-module/bindings/post-meta.js +2 -2
  66. package/build-module/bindings/post-meta.js.map +1 -1
  67. package/build-module/components/create-template-part-modal/index.js +1 -0
  68. package/build-module/components/create-template-part-modal/index.js.map +1 -1
  69. package/build-module/components/global-styles-provider/index.js +17 -4
  70. package/build-module/components/global-styles-provider/index.js.map +1 -1
  71. package/build-module/components/inserter-sidebar/index.js +5 -2
  72. package/build-module/components/inserter-sidebar/index.js.map +1 -1
  73. package/build-module/components/page-attributes/parent.js +6 -5
  74. package/build-module/components/page-attributes/parent.js.map +1 -1
  75. package/build-module/components/post-actions/actions.js +5 -501
  76. package/build-module/components/post-actions/actions.js.map +1 -1
  77. package/build-module/components/post-actions/index.js +8 -17
  78. package/build-module/components/post-actions/index.js.map +1 -1
  79. package/build-module/components/post-card-panel/index.js +20 -20
  80. package/build-module/components/post-card-panel/index.js.map +1 -1
  81. package/build-module/components/post-featured-image/index.js +2 -0
  82. package/build-module/components/post-featured-image/index.js.map +1 -1
  83. package/build-module/components/post-publish-panel/postpublish.js +4 -0
  84. package/build-module/components/post-publish-panel/postpublish.js.map +1 -1
  85. package/build-module/components/post-slug/index.js +1 -0
  86. package/build-module/components/post-slug/index.js.map +1 -1
  87. package/build-module/components/post-taxonomies/hierarchical-term-selector.js +3 -2
  88. package/build-module/components/post-taxonomies/hierarchical-term-selector.js.map +1 -1
  89. package/build-module/components/post-url/index.js +7 -6
  90. package/build-module/components/post-url/index.js.map +1 -1
  91. package/build-module/components/sidebar/post-summary.js +10 -7
  92. package/build-module/components/sidebar/post-summary.js.map +1 -1
  93. package/build-module/components/template-content-panel/index.js +1 -1
  94. package/build-module/components/template-content-panel/index.js.map +1 -1
  95. package/build-module/dataviews/actions/duplicate-pattern.js +39 -0
  96. package/build-module/dataviews/actions/duplicate-pattern.js.map +1 -0
  97. package/build-module/dataviews/actions/duplicate-post.js +139 -0
  98. package/build-module/dataviews/actions/duplicate-post.js.map +1 -0
  99. package/build-module/dataviews/actions/duplicate-post.native.js +3 -0
  100. package/build-module/dataviews/actions/duplicate-post.native.js.map +1 -0
  101. package/build-module/dataviews/actions/duplicate-template-part.js +58 -0
  102. package/build-module/dataviews/actions/duplicate-template-part.js.map +1 -0
  103. package/build-module/dataviews/actions/rename-post.js +118 -0
  104. package/build-module/dataviews/actions/rename-post.js.map +1 -0
  105. package/build-module/dataviews/actions/reorder-page.js +111 -0
  106. package/build-module/dataviews/actions/reorder-page.js.map +1 -0
  107. package/build-module/dataviews/actions/reorder-page.native.js +3 -0
  108. package/build-module/dataviews/actions/reorder-page.native.js.map +1 -0
  109. package/build-module/dataviews/actions/reset-post.js +1 -1
  110. package/build-module/dataviews/actions/reset-post.js.map +1 -1
  111. package/build-module/dataviews/actions/utils.js +7 -1
  112. package/build-module/dataviews/actions/utils.js.map +1 -1
  113. package/build-module/dataviews/actions/view-post-revisions.js +43 -0
  114. package/build-module/dataviews/actions/view-post-revisions.js.map +1 -0
  115. package/build-module/dataviews/actions/view-post.js +30 -0
  116. package/build-module/dataviews/actions/view-post.js.map +1 -0
  117. package/build-module/dataviews/fields/index.js +26 -0
  118. package/build-module/dataviews/fields/index.js.map +1 -0
  119. package/build-module/dataviews/store/private-actions.js +16 -2
  120. package/build-module/dataviews/store/private-actions.js.map +1 -1
  121. package/build-module/dataviews/types.js.map +1 -1
  122. package/build-module/private-apis.js +2 -0
  123. package/build-module/private-apis.js.map +1 -1
  124. package/build-module/store/private-actions.js +1 -1
  125. package/build-module/store/private-actions.js.map +1 -1
  126. package/build-module/store/utils/is-template-revertable.js +1 -1
  127. package/build-module/store/utils/is-template-revertable.js.map +1 -1
  128. package/build-style/style-rtl.css +2 -31
  129. package/build-style/style.css +2 -31
  130. package/build-types/components/create-template-part-modal/index.d.ts.map +1 -1
  131. package/build-types/components/global-styles-provider/index.d.ts.map +1 -1
  132. package/build-types/components/inserter-sidebar/index.d.ts.map +1 -1
  133. package/build-types/components/page-attributes/parent.d.ts.map +1 -1
  134. package/build-types/components/post-actions/actions.d.ts +1 -26
  135. package/build-types/components/post-actions/actions.d.ts.map +1 -1
  136. package/build-types/components/post-actions/index.d.ts +3 -2
  137. package/build-types/components/post-actions/index.d.ts.map +1 -1
  138. package/build-types/components/post-card-panel/index.d.ts +4 -2
  139. package/build-types/components/post-card-panel/index.d.ts.map +1 -1
  140. package/build-types/components/post-slug/index.d.ts.map +1 -1
  141. package/build-types/components/post-taxonomies/hierarchical-term-selector.d.ts +1 -17
  142. package/build-types/components/post-taxonomies/hierarchical-term-selector.d.ts.map +1 -1
  143. package/build-types/components/post-url/index.d.ts.map +1 -1
  144. package/build-types/components/sidebar/post-summary.d.ts.map +1 -1
  145. package/build-types/components/template-content-panel/index.d.ts.map +1 -1
  146. package/build-types/dataviews/actions/duplicate-pattern.d.ts +5 -0
  147. package/build-types/dataviews/actions/duplicate-pattern.d.ts.map +1 -0
  148. package/build-types/dataviews/actions/duplicate-post.d.ts +5 -0
  149. package/build-types/dataviews/actions/duplicate-post.d.ts.map +1 -0
  150. package/build-types/dataviews/actions/duplicate-post.native.d.ts +3 -0
  151. package/build-types/dataviews/actions/duplicate-post.native.d.ts.map +1 -0
  152. package/build-types/dataviews/actions/duplicate-template-part.d.ts +5 -0
  153. package/build-types/dataviews/actions/duplicate-template-part.d.ts.map +1 -0
  154. package/build-types/dataviews/actions/rename-post.d.ts +5 -0
  155. package/build-types/dataviews/actions/rename-post.d.ts.map +1 -0
  156. package/build-types/dataviews/actions/reorder-page.d.ts +8 -0
  157. package/build-types/dataviews/actions/reorder-page.d.ts.map +1 -0
  158. package/build-types/dataviews/actions/reorder-page.native.d.ts +3 -0
  159. package/build-types/dataviews/actions/reorder-page.native.d.ts.map +1 -0
  160. package/build-types/dataviews/actions/reset-post.d.ts.map +1 -1
  161. package/build-types/dataviews/actions/utils.d.ts +5 -3
  162. package/build-types/dataviews/actions/utils.d.ts.map +1 -1
  163. package/build-types/dataviews/actions/view-post-revisions.d.ts +8 -0
  164. package/build-types/dataviews/actions/view-post-revisions.d.ts.map +1 -0
  165. package/build-types/dataviews/actions/view-post.d.ts +8 -0
  166. package/build-types/dataviews/actions/view-post.d.ts.map +1 -0
  167. package/build-types/dataviews/fields/index.d.ts +8 -0
  168. package/build-types/dataviews/fields/index.d.ts.map +1 -0
  169. package/build-types/dataviews/store/private-actions.d.ts.map +1 -1
  170. package/build-types/dataviews/types.d.ts +57 -8
  171. package/build-types/dataviews/types.d.ts.map +1 -1
  172. package/build-types/private-apis.d.ts.map +1 -1
  173. package/build-types/store/utils/is-template-revertable.d.ts.map +1 -1
  174. package/package.json +36 -36
  175. package/src/bindings/post-meta.js +2 -2
  176. package/src/components/block-manager/style.scss +2 -2
  177. package/src/components/create-template-part-modal/index.js +1 -0
  178. package/src/components/error-boundary/style.native.scss +1 -1
  179. package/src/components/error-boundary/style.scss +1 -1
  180. package/src/components/global-styles-provider/index.js +16 -3
  181. package/src/components/inserter-sidebar/index.js +10 -4
  182. package/src/components/page-attributes/parent.js +13 -9
  183. package/src/components/post-actions/actions.js +5 -616
  184. package/src/components/post-actions/index.js +16 -20
  185. package/src/components/post-card-panel/index.js +28 -27
  186. package/src/components/post-discussion/style.scss +0 -9
  187. package/src/components/post-featured-image/index.js +2 -0
  188. package/src/components/post-format/style.scss +0 -6
  189. package/src/components/post-publish-panel/postpublish.js +8 -2
  190. package/src/components/post-publish-panel/test/__snapshots__/index.js.snap +8 -8
  191. package/src/components/post-slug/index.js +1 -0
  192. package/src/components/post-status/style.scss +0 -19
  193. package/src/components/post-taxonomies/hierarchical-term-selector.js +3 -1
  194. package/src/components/post-url/index.js +15 -9
  195. package/src/components/save-publish-panels/style.scss +3 -3
  196. package/src/components/sidebar/post-summary.js +20 -16
  197. package/src/components/site-discussion/style.scss +0 -14
  198. package/src/components/template-content-panel/index.js +4 -1
  199. package/src/dataviews/actions/duplicate-pattern.tsx +40 -0
  200. package/src/dataviews/actions/duplicate-post.native.tsx +3 -0
  201. package/src/dataviews/actions/duplicate-post.tsx +174 -0
  202. package/src/dataviews/actions/duplicate-template-part.tsx +70 -0
  203. package/src/dataviews/actions/rename-post.tsx +146 -0
  204. package/src/dataviews/actions/reorder-page.native.tsx +3 -0
  205. package/src/dataviews/actions/reorder-page.tsx +125 -0
  206. package/src/dataviews/actions/reset-post.tsx +2 -1
  207. package/src/dataviews/actions/utils.ts +14 -4
  208. package/src/dataviews/actions/view-post-revisions.tsx +47 -0
  209. package/src/dataviews/actions/view-post.tsx +30 -0
  210. package/src/dataviews/fields/index.ts +26 -0
  211. package/src/dataviews/store/private-actions.ts +42 -1
  212. package/src/dataviews/types.ts +47 -6
  213. package/src/private-apis.js +2 -0
  214. package/src/store/private-actions.js +1 -1
  215. package/src/store/utils/is-template-revertable.js +2 -1
  216. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,70 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useDispatch } from '@wordpress/data';
5
+ import { __, sprintf, _x } from '@wordpress/i18n';
6
+ import { store as noticesStore } from '@wordpress/notices';
7
+ import { useMemo } from '@wordpress/element';
8
+ // @ts-ignore
9
+ import { parse } from '@wordpress/blocks';
10
+ import type { Action } from '@wordpress/dataviews';
11
+
12
+ /**
13
+ * Internal dependencies
14
+ */
15
+ import { TEMPLATE_PART_POST_TYPE } from '../../store/constants';
16
+ import { CreateTemplatePartModalContents } from '../../components/create-template-part-modal';
17
+ import { getItemTitle } from './utils';
18
+ import type { TemplatePart } from '../types';
19
+
20
+ const duplicateTemplatePart: Action< TemplatePart > = {
21
+ id: 'duplicate-template-part',
22
+ label: _x( 'Duplicate', 'action label' ),
23
+ isEligible: ( item ) => item.type === TEMPLATE_PART_POST_TYPE,
24
+ modalHeader: _x( 'Duplicate template part', 'action label' ),
25
+ RenderModal: ( { items, closeModal } ) => {
26
+ const [ item ] = items;
27
+ const blocks = useMemo( () => {
28
+ return (
29
+ item.blocks ??
30
+ parse(
31
+ typeof item.content === 'string'
32
+ ? item.content
33
+ : item.content.raw,
34
+ {
35
+ __unstableSkipMigrationLogs: true,
36
+ }
37
+ )
38
+ );
39
+ }, [ item.content, item.blocks ] );
40
+ const { createSuccessNotice } = useDispatch( noticesStore );
41
+ function onTemplatePartSuccess() {
42
+ createSuccessNotice(
43
+ sprintf(
44
+ // translators: %s: The new template part's title e.g. 'Call to action (copy)'.
45
+ __( '"%s" duplicated.' ),
46
+ getItemTitle( item )
47
+ ),
48
+ { type: 'snackbar', id: 'edit-site-patterns-success' }
49
+ );
50
+ closeModal?.();
51
+ }
52
+ return (
53
+ <CreateTemplatePartModalContents
54
+ blocks={ blocks }
55
+ defaultArea={ item.area }
56
+ defaultTitle={ sprintf(
57
+ /* translators: %s: Existing template part title */
58
+ __( '%s (Copy)' ),
59
+ getItemTitle( item )
60
+ ) }
61
+ onCreate={ onTemplatePartSuccess }
62
+ onError={ closeModal }
63
+ confirmLabel={ _x( 'Duplicate', 'action label' ) }
64
+ closeModal={ closeModal }
65
+ />
66
+ );
67
+ },
68
+ };
69
+
70
+ export default duplicateTemplatePart;
@@ -0,0 +1,146 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useDispatch } from '@wordpress/data';
5
+ import { store as coreStore } from '@wordpress/core-data';
6
+ import { __ } from '@wordpress/i18n';
7
+ import { useState } from '@wordpress/element';
8
+ // @ts-ignore
9
+ import { privateApis as patternsPrivateApis } from '@wordpress/patterns';
10
+ import {
11
+ Button,
12
+ TextControl,
13
+ __experimentalHStack as HStack,
14
+ __experimentalVStack as VStack,
15
+ } from '@wordpress/components';
16
+ import type { Action } from '@wordpress/dataviews';
17
+ import { store as noticesStore } from '@wordpress/notices';
18
+
19
+ /**
20
+ * Internal dependencies
21
+ */
22
+ import {
23
+ TEMPLATE_ORIGINS,
24
+ TEMPLATE_PART_POST_TYPE,
25
+ TEMPLATE_POST_TYPE,
26
+ } from '../../store/constants';
27
+ import { unlock } from '../../lock-unlock';
28
+ import {
29
+ getItemTitle,
30
+ isTemplateRemovable,
31
+ isTemplate,
32
+ isTemplatePart,
33
+ } from './utils';
34
+ import type { CoreDataError, PostWithPermissions } from '../types';
35
+
36
+ // Patterns.
37
+ const { PATTERN_TYPES } = unlock( patternsPrivateApis );
38
+
39
+ const renamePost: Action< PostWithPermissions > = {
40
+ id: 'rename-post',
41
+ label: __( 'Rename' ),
42
+ isEligible( post ) {
43
+ if ( post.status === 'trash' ) {
44
+ return false;
45
+ }
46
+ // Templates, template parts and patterns have special checks for renaming.
47
+ if (
48
+ ! [
49
+ TEMPLATE_POST_TYPE,
50
+ TEMPLATE_PART_POST_TYPE,
51
+ ...Object.values( PATTERN_TYPES ),
52
+ ].includes( post.type )
53
+ ) {
54
+ return post.permissions?.update;
55
+ }
56
+
57
+ // In the case of templates, we can only rename custom templates.
58
+ if ( isTemplate( post ) ) {
59
+ return (
60
+ isTemplateRemovable( post ) &&
61
+ post.is_custom &&
62
+ post.permissions?.update
63
+ );
64
+ }
65
+
66
+ if ( isTemplatePart( post ) ) {
67
+ return (
68
+ post.source === TEMPLATE_ORIGINS.custom &&
69
+ ! post?.has_theme_file &&
70
+ post.permissions?.update
71
+ );
72
+ }
73
+
74
+ return post.type === PATTERN_TYPES.user && post.permissions?.update;
75
+ },
76
+ RenderModal: ( { items, closeModal, onActionPerformed } ) => {
77
+ const [ item ] = items;
78
+ const [ title, setTitle ] = useState( () => getItemTitle( item ) );
79
+ const { editEntityRecord, saveEditedEntityRecord } =
80
+ useDispatch( coreStore );
81
+ const { createSuccessNotice, createErrorNotice } =
82
+ useDispatch( noticesStore );
83
+
84
+ async function onRename( event: React.FormEvent ) {
85
+ event.preventDefault();
86
+ try {
87
+ await editEntityRecord( 'postType', item.type, item.id, {
88
+ title,
89
+ } );
90
+ // Update state before saving rerenders the list.
91
+ setTitle( '' );
92
+ closeModal?.();
93
+ // Persist edited entity.
94
+ await saveEditedEntityRecord( 'postType', item.type, item.id, {
95
+ throwOnError: true,
96
+ } );
97
+ createSuccessNotice( __( 'Name updated' ), {
98
+ type: 'snackbar',
99
+ } );
100
+ onActionPerformed?.( items );
101
+ } catch ( error ) {
102
+ const typedError = error as CoreDataError;
103
+ const errorMessage =
104
+ typedError.message && typedError.code !== 'unknown_error'
105
+ ? typedError.message
106
+ : __( 'An error occurred while updating the name' );
107
+ createErrorNotice( errorMessage, { type: 'snackbar' } );
108
+ }
109
+ }
110
+
111
+ return (
112
+ <form onSubmit={ onRename }>
113
+ <VStack spacing="5">
114
+ <TextControl
115
+ __nextHasNoMarginBottom
116
+ __next40pxDefaultSize
117
+ label={ __( 'Name' ) }
118
+ value={ title }
119
+ onChange={ setTitle }
120
+ required
121
+ />
122
+ <HStack justify="right">
123
+ <Button
124
+ __next40pxDefaultSize
125
+ variant="tertiary"
126
+ onClick={ () => {
127
+ closeModal?.();
128
+ } }
129
+ >
130
+ { __( 'Cancel' ) }
131
+ </Button>
132
+ <Button
133
+ __next40pxDefaultSize
134
+ variant="primary"
135
+ type="submit"
136
+ >
137
+ { __( 'Save' ) }
138
+ </Button>
139
+ </HStack>
140
+ </VStack>
141
+ </form>
142
+ );
143
+ },
144
+ };
145
+
146
+ export default renamePost;
@@ -0,0 +1,3 @@
1
+ const reorderPage = undefined;
2
+
3
+ export default reorderPage;
@@ -0,0 +1,125 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useDispatch } from '@wordpress/data';
5
+ import { store as coreStore } from '@wordpress/core-data';
6
+ import { __ } from '@wordpress/i18n';
7
+ import { store as noticesStore } from '@wordpress/notices';
8
+ import { useState } from '@wordpress/element';
9
+ import { DataForm, isItemValid } from '@wordpress/dataviews';
10
+ import {
11
+ Button,
12
+ __experimentalHStack as HStack,
13
+ __experimentalVStack as VStack,
14
+ } from '@wordpress/components';
15
+ import type { Action, RenderModalProps } from '@wordpress/dataviews';
16
+
17
+ /**
18
+ * Internal dependencies
19
+ */
20
+ import type { CoreDataError, BasePost } from '../types';
21
+ import { orderField } from '../fields';
22
+
23
+ const fields = [ orderField ];
24
+ const formOrderAction = {
25
+ fields: [ 'menu_order' ],
26
+ };
27
+
28
+ function ReorderModal( {
29
+ items,
30
+ closeModal,
31
+ onActionPerformed,
32
+ }: RenderModalProps< BasePost > ) {
33
+ const [ item, setItem ] = useState( items[ 0 ] );
34
+ const orderInput = item.menu_order;
35
+ const { editEntityRecord, saveEditedEntityRecord } =
36
+ useDispatch( coreStore );
37
+ const { createSuccessNotice, createErrorNotice } =
38
+ useDispatch( noticesStore );
39
+
40
+ async function onOrder( event: React.FormEvent ) {
41
+ event.preventDefault();
42
+
43
+ if ( ! isItemValid( item, fields, formOrderAction ) ) {
44
+ return;
45
+ }
46
+
47
+ try {
48
+ await editEntityRecord( 'postType', item.type, item.id, {
49
+ menu_order: orderInput,
50
+ } );
51
+ closeModal?.();
52
+ // Persist edited entity.
53
+ await saveEditedEntityRecord( 'postType', item.type, item.id, {
54
+ throwOnError: true,
55
+ } );
56
+ createSuccessNotice( __( 'Order updated.' ), {
57
+ type: 'snackbar',
58
+ } );
59
+ onActionPerformed?.( items );
60
+ } catch ( error ) {
61
+ const typedError = error as CoreDataError;
62
+ const errorMessage =
63
+ typedError.message && typedError.code !== 'unknown_error'
64
+ ? typedError.message
65
+ : __( 'An error occurred while updating the order' );
66
+ createErrorNotice( errorMessage, {
67
+ type: 'snackbar',
68
+ } );
69
+ }
70
+ }
71
+ const isSaveDisabled = ! isItemValid( item, fields, formOrderAction );
72
+ return (
73
+ <form onSubmit={ onOrder }>
74
+ <VStack spacing="5">
75
+ <div>
76
+ { __(
77
+ 'Determines the order of pages. Pages with the same order value are sorted alphabetically. Negative order values are supported.'
78
+ ) }
79
+ </div>
80
+ <DataForm
81
+ data={ item }
82
+ fields={ fields }
83
+ form={ formOrderAction }
84
+ onChange={ ( changes ) =>
85
+ setItem( {
86
+ ...item,
87
+ ...changes,
88
+ } )
89
+ }
90
+ />
91
+ <HStack justify="right">
92
+ <Button
93
+ __next40pxDefaultSize
94
+ variant="tertiary"
95
+ onClick={ () => {
96
+ closeModal?.();
97
+ } }
98
+ >
99
+ { __( 'Cancel' ) }
100
+ </Button>
101
+ <Button
102
+ __next40pxDefaultSize
103
+ variant="primary"
104
+ type="submit"
105
+ accessibleWhenDisabled
106
+ disabled={ isSaveDisabled }
107
+ >
108
+ { __( 'Save' ) }
109
+ </Button>
110
+ </HStack>
111
+ </VStack>
112
+ </form>
113
+ );
114
+ }
115
+
116
+ const reorderPage: Action< BasePost > = {
117
+ id: 'order-pages',
118
+ label: __( 'Order' ),
119
+ isEligible( { status } ) {
120
+ return status !== 'trash';
121
+ },
122
+ RenderModal: ReorderModal,
123
+ };
124
+
125
+ export default reorderPage;
@@ -32,7 +32,8 @@ const resetPost: Action< Post > = {
32
32
  return (
33
33
  isTemplateOrTemplatePart( item ) &&
34
34
  item?.source === TEMPLATE_ORIGINS.custom &&
35
- item?.has_theme_file
35
+ ( Boolean( item.type === 'wp_template' && item?.plugin ) ||
36
+ item?.has_theme_file )
36
37
  );
37
38
  },
38
39
  icon: backup,
@@ -12,11 +12,19 @@ import {
12
12
  TEMPLATE_POST_TYPE,
13
13
  } from '../../store/constants';
14
14
 
15
- import type { Post, TemplateOrTemplatePart } from '../types';
15
+ import type { Post, TemplatePart, Template } from '../types';
16
+
17
+ export function isTemplate( post: Post ): post is Template {
18
+ return post.type === TEMPLATE_POST_TYPE;
19
+ }
20
+
21
+ export function isTemplatePart( post: Post ): post is TemplatePart {
22
+ return post.type === TEMPLATE_PART_POST_TYPE;
23
+ }
16
24
 
17
25
  export function isTemplateOrTemplatePart(
18
26
  p: Post
19
- ): p is TemplateOrTemplatePart {
27
+ ): p is Template | TemplatePart {
20
28
  return p.type === TEMPLATE_POST_TYPE || p.type === TEMPLATE_PART_POST_TYPE;
21
29
  }
22
30
 
@@ -39,7 +47,7 @@ export function getItemTitle( item: Post ) {
39
47
  * @param template The template entity to check.
40
48
  * @return Whether the template is removable.
41
49
  */
42
- export function isTemplateRemovable( template: TemplateOrTemplatePart ) {
50
+ export function isTemplateRemovable( template: Template | TemplatePart ) {
43
51
  if ( ! template ) {
44
52
  return false;
45
53
  }
@@ -49,6 +57,8 @@ export function isTemplateRemovable( template: TemplateOrTemplatePart ) {
49
57
  return (
50
58
  [ template.source, template.source ].includes(
51
59
  TEMPLATE_ORIGINS.custom
52
- ) && ! template.has_theme_file
60
+ ) &&
61
+ ! Boolean( template.type === 'wp_template' && template?.plugin ) &&
62
+ ! template.has_theme_file
53
63
  );
54
64
  }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { addQueryArgs } from '@wordpress/url';
5
+ import { __, sprintf } from '@wordpress/i18n';
6
+ import type { Action } from '@wordpress/dataviews';
7
+
8
+ /**
9
+ * Internal dependencies
10
+ */
11
+ import type { Post } from '../types';
12
+
13
+ const viewPostRevisions: Action< Post > = {
14
+ id: 'view-post-revisions',
15
+ context: 'list',
16
+ label( items ) {
17
+ const revisionsCount =
18
+ items[ 0 ]._links?.[ 'version-history' ]?.[ 0 ]?.count ?? 0;
19
+ return sprintf(
20
+ /* translators: %s: number of revisions */
21
+ __( 'View revisions (%s)' ),
22
+ revisionsCount
23
+ );
24
+ },
25
+ isEligible( post ) {
26
+ if ( post.status === 'trash' ) {
27
+ return false;
28
+ }
29
+ const lastRevisionId =
30
+ post?._links?.[ 'predecessor-version' ]?.[ 0 ]?.id ?? null;
31
+ const revisionsCount =
32
+ post?._links?.[ 'version-history' ]?.[ 0 ]?.count ?? 0;
33
+ return !! lastRevisionId && revisionsCount > 1;
34
+ },
35
+ callback( posts, { onActionPerformed } ) {
36
+ const post = posts[ 0 ];
37
+ const href = addQueryArgs( 'revision.php', {
38
+ revision: post?._links?.[ 'predecessor-version' ]?.[ 0 ]?.id,
39
+ } );
40
+ document.location.href = href;
41
+ if ( onActionPerformed ) {
42
+ onActionPerformed( posts );
43
+ }
44
+ },
45
+ };
46
+
47
+ export default viewPostRevisions;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { external } from '@wordpress/icons';
5
+ import { __ } from '@wordpress/i18n';
6
+ import type { Action } from '@wordpress/dataviews';
7
+
8
+ /**
9
+ * Internal dependencies
10
+ */
11
+ import type { BasePost } from '../types';
12
+
13
+ const viewPost: Action< BasePost > = {
14
+ id: 'view-post',
15
+ label: __( 'View' ),
16
+ isPrimary: true,
17
+ icon: external,
18
+ isEligible( post ) {
19
+ return post.status !== 'trash';
20
+ },
21
+ callback( posts, { onActionPerformed } ) {
22
+ const post = posts[ 0 ];
23
+ window.open( post?.link, '_blank' );
24
+ if ( onActionPerformed ) {
25
+ onActionPerformed( posts );
26
+ }
27
+ },
28
+ };
29
+
30
+ export default viewPost;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+ import type { Field } from '@wordpress/dataviews';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import type { BasePost } from '../types';
11
+ import { getItemTitle } from '../actions/utils';
12
+
13
+ export const titleField: Field< BasePost > = {
14
+ type: 'text',
15
+ id: 'title',
16
+ label: __( 'Title' ),
17
+ placeholder: __( 'No title' ),
18
+ getValue: ( { item } ) => getItemTitle( item ),
19
+ };
20
+
21
+ export const orderField: Field< BasePost > = {
22
+ type: 'integer',
23
+ id: 'menu_order',
24
+ label: __( 'Order' ),
25
+ description: __( 'Determines the order of pages.' ),
26
+ };
@@ -9,14 +9,21 @@ import { doAction } from '@wordpress/hooks';
9
9
  * Internal dependencies
10
10
  */
11
11
  import deletePost from '../actions/delete-post';
12
+ import duplicatePattern from '../actions/duplicate-pattern';
13
+ import duplicateTemplatePart from '../actions/duplicate-template-part';
12
14
  import exportPattern from '../actions/export-pattern';
13
15
  import resetPost from '../actions/reset-post';
14
16
  import trashPost from '../actions/trash-post';
15
17
  import permanentlyDeletePost from '../actions/permanently-delete-post';
18
+ import renamePost from '../actions/rename-post';
19
+ import reorderPage from '../actions/reorder-page';
16
20
  import restorePost from '../actions/restore-post';
17
21
  import type { PostType } from '../types';
18
22
  import { store as editorStore } from '../../store';
19
23
  import { unlock } from '../../lock-unlock';
24
+ import duplicatePost from '../actions/duplicate-post';
25
+ import viewPostRevisions from '../actions/view-post-revisions';
26
+ import viewPost from '../actions/view-post';
20
27
 
21
28
  export function registerEntityAction< Item >(
22
29
  kind: string,
@@ -72,7 +79,41 @@ export const registerPostTypeActions =
72
79
  .resolveSelect( coreStore )
73
80
  .getPostType( postType ) ) as PostType;
74
81
 
82
+ const canCreate = await registry
83
+ .resolveSelect( coreStore )
84
+ .canUser( 'create', {
85
+ kind: 'postType',
86
+ name: postType,
87
+ } );
88
+ const currentTheme = await registry
89
+ .resolveSelect( coreStore )
90
+ .getCurrentTheme();
91
+
75
92
  const actions = [
93
+ postTypeConfig.viewable ? viewPost : undefined,
94
+ !! postTypeConfig?.supports?.revisions
95
+ ? viewPostRevisions
96
+ : undefined,
97
+ // @ts-ignore
98
+ globalThis.IS_GUTENBERG_PLUGIN
99
+ ? ! [ 'wp_template', 'wp_block', 'wp_template_part' ].includes(
100
+ postTypeConfig.slug
101
+ ) &&
102
+ canCreate &&
103
+ duplicatePost
104
+ : undefined,
105
+ postTypeConfig.slug === 'wp_template_part' &&
106
+ canCreate &&
107
+ currentTheme?.is_block_theme
108
+ ? duplicateTemplatePart
109
+ : undefined,
110
+ canCreate && postTypeConfig.slug === 'wp_block'
111
+ ? duplicatePattern
112
+ : undefined,
113
+ postTypeConfig.supports?.title ? renamePost : undefined,
114
+ postTypeConfig?.supports?.[ 'page-attributes' ]
115
+ ? reorderPage
116
+ : undefined,
76
117
  postTypeConfig.slug === 'wp_block' ? exportPattern : undefined,
77
118
  resetPost,
78
119
  restorePost,
@@ -83,7 +124,7 @@ export const registerPostTypeActions =
83
124
 
84
125
  registry.batch( () => {
85
126
  actions.forEach( ( action ) => {
86
- if ( action === undefined ) {
127
+ if ( ! action ) {
87
128
  return;
88
129
  }
89
130
  unlock( registry.dispatch( editorStore ) ).registerEntityAction(
@@ -7,27 +7,62 @@ type PostStatus =
7
7
  | 'auto-draft'
8
8
  | 'trash';
9
9
 
10
- export interface BasePost {
10
+ export interface CommonPost {
11
11
  status?: PostStatus;
12
12
  title: string | { rendered: string } | { raw: string };
13
+ content: string | { raw: string; rendered: string };
13
14
  type: string;
14
15
  id: string | number;
16
+ blocks?: Object[];
17
+ _links?: Links;
15
18
  }
16
- export interface TemplateOrTemplatePart extends BasePost {
17
- type: 'wp_template' | 'wp_template_part';
19
+
20
+ interface Links {
21
+ 'predecessor-version'?: { href: string; id: number }[];
22
+ 'version-history'?: { href: string; count: number }[];
23
+ [ key: string ]: { href: string }[] | undefined;
24
+ }
25
+
26
+ export interface BasePost extends CommonPost {
27
+ comment_status?: 'open' | 'closed';
28
+ excerpt?: string | { raw: string; rendered: string };
29
+ meta?: Record< string, any >;
30
+ parent?: number;
31
+ password?: string;
32
+ template?: string;
33
+ format?: string;
34
+ featured_media?: number;
35
+ menu_order?: number;
36
+ ping_status?: 'open' | 'closed';
37
+ link?: string;
38
+ }
39
+
40
+ export interface Template extends CommonPost {
41
+ type: 'wp_template';
42
+ is_custom: boolean;
18
43
  source: string;
44
+ origin: string;
45
+ plugin?: string;
19
46
  has_theme_file: boolean;
20
47
  id: string;
21
48
  }
22
49
 
23
- export interface Pattern extends BasePost {
50
+ export interface TemplatePart extends CommonPost {
51
+ type: 'wp_template_part';
52
+ source: string;
53
+ origin: string;
54
+ has_theme_file: boolean;
55
+ id: string;
56
+ area: string;
57
+ }
58
+
59
+ export interface Pattern extends CommonPost {
24
60
  slug: string;
25
61
  title: { raw: string };
26
- content: { raw: string } | string;
27
62
  wp_pattern_sync_status: string;
28
63
  }
29
64
 
30
- export type Post = TemplateOrTemplatePart | Pattern | BasePost;
65
+ export type Post = Template | TemplatePart | Pattern | BasePost;
31
66
 
32
67
  export type PostWithPermissions = Post & {
33
68
  permissions: {
@@ -38,6 +73,12 @@ export type PostWithPermissions = Post & {
38
73
 
39
74
  export interface PostType {
40
75
  slug: string;
76
+ viewable: boolean;
77
+ supports?: {
78
+ 'page-attributes'?: boolean;
79
+ title?: boolean;
80
+ revisions?: boolean;
81
+ };
41
82
  }
42
83
 
43
84
  // Will be unnecessary after typescript 5.0 upgrade.
@@ -14,6 +14,7 @@ import BackButton from './components/header/back-button';
14
14
  import CreateTemplatePartModal from './components/create-template-part-modal';
15
15
  import Editor from './components/editor';
16
16
  import PluginPostExcerpt from './components/post-excerpt/plugin';
17
+ import PostCardPanel from './components/post-card-panel';
17
18
  import PreferencesModal from './components/preferences-modal';
18
19
  import { usePostActions } from './components/post-actions/actions';
19
20
  import ToolsMoreMenuGroup from './components/more-menu/tools-more-menu-group';
@@ -40,6 +41,7 @@ lock( privateApis, {
40
41
  GlobalStylesProvider,
41
42
  mergeBaseAndUserConfigs,
42
43
  PluginPostExcerpt,
44
+ PostCardPanel,
43
45
  PreferencesModal,
44
46
  usePostActions,
45
47
  ToolsMoreMenuGroup,
@@ -269,7 +269,7 @@ export const revertTemplate =
269
269
 
270
270
  const fileTemplatePath = addQueryArgs(
271
271
  `${ templateEntityConfig.baseURL }/${ template.id }`,
272
- { context: 'edit', source: 'theme' }
272
+ { context: 'edit', source: template.origin }
273
273
  );
274
274
 
275
275
  const fileTemplate = await apiFetch( { path: fileTemplatePath } );
@@ -18,6 +18,7 @@ export default function isTemplateRevertable( templateOrTemplatePart ) {
18
18
 
19
19
  return (
20
20
  templateOrTemplatePart.source === TEMPLATE_ORIGINS.custom &&
21
- templateOrTemplatePart.has_theme_file
21
+ ( Boolean( templateOrTemplatePart?.plugin ) ||
22
+ templateOrTemplatePart?.has_theme_file )
22
23
  );
23
24
  }