@wordpress/editor 14.42.0 → 14.43.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 (199) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/collaborators-overlay/cursor-registry.cjs +86 -0
  3. package/build/components/collaborators-overlay/cursor-registry.cjs.map +7 -0
  4. package/build/components/collaborators-overlay/index.cjs +7 -2
  5. package/build/components/collaborators-overlay/index.cjs.map +2 -2
  6. package/build/components/collaborators-overlay/overlay-iframe-styles.cjs +1 -1
  7. package/build/components/collaborators-overlay/overlay-iframe-styles.cjs.map +2 -2
  8. package/build/components/collaborators-overlay/overlay.cjs +31 -1
  9. package/build/components/collaborators-overlay/overlay.cjs.map +2 -2
  10. package/build/components/collaborators-presence/index.cjs +14 -4
  11. package/build/components/collaborators-presence/index.cjs.map +2 -2
  12. package/build/components/collaborators-presence/list.cjs +20 -4
  13. package/build/components/collaborators-presence/list.cjs.map +2 -2
  14. package/build/components/post-card-panel/index.cjs +4 -15
  15. package/build/components/post-card-panel/index.cjs.map +2 -2
  16. package/build/components/post-content-information/index.cjs +10 -13
  17. package/build/components/post-content-information/index.cjs.map +2 -2
  18. package/build/components/post-revisions-panel/index.cjs +164 -0
  19. package/build/components/post-revisions-panel/index.cjs.map +7 -0
  20. package/build/components/post-revisions-preview/revisions-slider.cjs +24 -5
  21. package/build/components/post-revisions-preview/revisions-slider.cjs.map +2 -2
  22. package/build/components/post-template/create-new-template-modal.cjs +39 -46
  23. package/build/components/post-template/create-new-template-modal.cjs.map +2 -2
  24. package/build/components/post-template/hooks.cjs +52 -6
  25. package/build/components/post-template/hooks.cjs.map +2 -2
  26. package/build/components/post-template/swap-template-button.cjs +31 -20
  27. package/build/components/post-template/swap-template-button.cjs.map +2 -2
  28. package/build/components/preferences-modal/index.cjs +35 -27
  29. package/build/components/preferences-modal/index.cjs.map +2 -2
  30. package/build/components/revision-block-diff/index.cjs +9 -32
  31. package/build/components/revision-block-diff/index.cjs.map +3 -3
  32. package/build/components/revision-diff-panel/index.cjs +68 -0
  33. package/build/components/revision-diff-panel/index.cjs.map +7 -0
  34. package/build/components/revision-fields-diff/index.cjs +96 -0
  35. package/build/components/revision-fields-diff/index.cjs.map +7 -0
  36. package/build/components/sidebar/dataform-post-summary.cjs +8 -53
  37. package/build/components/sidebar/dataform-post-summary.cjs.map +2 -2
  38. package/build/components/sidebar/index.cjs +25 -22
  39. package/build/components/sidebar/index.cjs.map +3 -3
  40. package/build/components/sidebar/post-revision-summary.cjs +74 -0
  41. package/build/components/sidebar/post-revision-summary.cjs.map +7 -0
  42. package/build/components/sidebar/post-summary.cjs +35 -42
  43. package/build/components/sidebar/post-summary.cjs.map +3 -3
  44. package/build/components/style-book/index.cjs +4 -3
  45. package/build/components/style-book/index.cjs.map +2 -2
  46. package/build/components/sync-connection-error-modal/index.cjs +2 -2
  47. package/build/components/sync-connection-error-modal/index.cjs.map +1 -1
  48. package/build/components/template-actions-panel/block-theme-content.cjs +188 -0
  49. package/build/components/template-actions-panel/block-theme-content.cjs.map +7 -0
  50. package/build/components/template-actions-panel/classic-theme-content.cjs +159 -0
  51. package/build/components/template-actions-panel/classic-theme-content.cjs.map +7 -0
  52. package/build/components/template-actions-panel/index.cjs +59 -0
  53. package/build/components/template-actions-panel/index.cjs.map +7 -0
  54. package/build/dataviews/store/private-actions.cjs +2 -0
  55. package/build/dataviews/store/private-actions.cjs.map +2 -2
  56. package/build/store/private-actions.cjs +21 -2
  57. package/build/store/private-actions.cjs.map +2 -2
  58. package/build/store/private-selectors.cjs +40 -15
  59. package/build/store/private-selectors.cjs.map +2 -2
  60. package/build-module/components/collaborators-overlay/cursor-registry.mjs +61 -0
  61. package/build-module/components/collaborators-overlay/cursor-registry.mjs.map +7 -0
  62. package/build-module/components/collaborators-overlay/index.mjs +7 -2
  63. package/build-module/components/collaborators-overlay/index.mjs.map +2 -2
  64. package/build-module/components/collaborators-overlay/overlay-iframe-styles.mjs +1 -1
  65. package/build-module/components/collaborators-overlay/overlay-iframe-styles.mjs.map +2 -2
  66. package/build-module/components/collaborators-overlay/overlay.mjs +32 -2
  67. package/build-module/components/collaborators-overlay/overlay.mjs.map +2 -2
  68. package/build-module/components/collaborators-presence/index.mjs +14 -4
  69. package/build-module/components/collaborators-presence/index.mjs.map +2 -2
  70. package/build-module/components/collaborators-presence/list.mjs +20 -4
  71. package/build-module/components/collaborators-presence/list.mjs.map +2 -2
  72. package/build-module/components/post-card-panel/index.mjs +6 -17
  73. package/build-module/components/post-card-panel/index.mjs.map +2 -2
  74. package/build-module/components/post-content-information/index.mjs +6 -13
  75. package/build-module/components/post-content-information/index.mjs.map +2 -2
  76. package/build-module/components/post-revisions-panel/index.mjs +139 -0
  77. package/build-module/components/post-revisions-panel/index.mjs.map +7 -0
  78. package/build-module/components/post-revisions-preview/revisions-slider.mjs +24 -5
  79. package/build-module/components/post-revisions-preview/revisions-slider.mjs.map +2 -2
  80. package/build-module/components/post-template/create-new-template-modal.mjs +39 -46
  81. package/build-module/components/post-template/create-new-template-modal.mjs.map +2 -2
  82. package/build-module/components/post-template/hooks.mjs +53 -7
  83. package/build-module/components/post-template/hooks.mjs.map +2 -2
  84. package/build-module/components/post-template/swap-template-button.mjs +27 -20
  85. package/build-module/components/post-template/swap-template-button.mjs.map +2 -2
  86. package/build-module/components/preferences-modal/index.mjs +35 -27
  87. package/build-module/components/preferences-modal/index.mjs.map +2 -2
  88. package/build-module/components/revision-block-diff/index.mjs +9 -32
  89. package/build-module/components/revision-block-diff/index.mjs.map +2 -2
  90. package/build-module/components/revision-diff-panel/index.mjs +37 -0
  91. package/build-module/components/revision-diff-panel/index.mjs.map +7 -0
  92. package/build-module/components/revision-fields-diff/index.mjs +65 -0
  93. package/build-module/components/revision-fields-diff/index.mjs.map +7 -0
  94. package/build-module/components/sidebar/dataform-post-summary.mjs +8 -53
  95. package/build-module/components/sidebar/dataform-post-summary.mjs.map +2 -2
  96. package/build-module/components/sidebar/index.mjs +25 -22
  97. package/build-module/components/sidebar/index.mjs.map +2 -2
  98. package/build-module/components/sidebar/post-revision-summary.mjs +43 -0
  99. package/build-module/components/sidebar/post-revision-summary.mjs.map +7 -0
  100. package/build-module/components/sidebar/post-summary.mjs +31 -42
  101. package/build-module/components/sidebar/post-summary.mjs.map +2 -2
  102. package/build-module/components/style-book/index.mjs +4 -3
  103. package/build-module/components/style-book/index.mjs.map +2 -2
  104. package/build-module/components/sync-connection-error-modal/index.mjs +2 -2
  105. package/build-module/components/sync-connection-error-modal/index.mjs.map +1 -1
  106. package/build-module/components/template-actions-panel/block-theme-content.mjs +167 -0
  107. package/build-module/components/template-actions-panel/block-theme-content.mjs.map +7 -0
  108. package/build-module/components/template-actions-panel/classic-theme-content.mjs +138 -0
  109. package/build-module/components/template-actions-panel/classic-theme-content.mjs.map +7 -0
  110. package/build-module/components/template-actions-panel/index.mjs +28 -0
  111. package/build-module/components/template-actions-panel/index.mjs.map +7 -0
  112. package/build-module/dataviews/store/private-actions.mjs +5 -1
  113. package/build-module/dataviews/store/private-actions.mjs.map +2 -2
  114. package/build-module/store/private-actions.mjs +21 -2
  115. package/build-module/store/private-actions.mjs.map +2 -2
  116. package/build-module/store/private-selectors.mjs +40 -15
  117. package/build-module/store/private-selectors.mjs.map +2 -2
  118. package/build-style/style-rtl.css +111 -42
  119. package/build-style/style.css +111 -42
  120. package/build-types/components/collaborators-overlay/cursor-registry.d.ts +36 -0
  121. package/build-types/components/collaborators-overlay/cursor-registry.d.ts.map +1 -0
  122. package/build-types/components/collaborators-overlay/index.d.ts +7 -4
  123. package/build-types/components/collaborators-overlay/index.d.ts.map +1 -1
  124. package/build-types/components/collaborators-overlay/overlay-iframe-styles.d.ts +1 -1
  125. package/build-types/components/collaborators-overlay/overlay-iframe-styles.d.ts.map +1 -1
  126. package/build-types/components/collaborators-overlay/overlay.d.ts +4 -1
  127. package/build-types/components/collaborators-overlay/overlay.d.ts.map +1 -1
  128. package/build-types/components/collaborators-presence/index.d.ts.map +1 -1
  129. package/build-types/components/collaborators-presence/list.d.ts +4 -1
  130. package/build-types/components/collaborators-presence/list.d.ts.map +1 -1
  131. package/build-types/components/post-card-panel/index.d.ts.map +1 -1
  132. package/build-types/components/post-content-information/index.d.ts +4 -1
  133. package/build-types/components/post-content-information/index.d.ts.map +1 -1
  134. package/build-types/components/post-revisions-panel/index.d.ts +2 -0
  135. package/build-types/components/post-revisions-panel/index.d.ts.map +1 -0
  136. package/build-types/components/post-revisions-preview/revisions-slider.d.ts.map +1 -1
  137. package/build-types/components/post-template/create-new-template-modal.d.ts.map +1 -1
  138. package/build-types/components/post-template/hooks.d.ts +1 -1
  139. package/build-types/components/post-template/hooks.d.ts.map +1 -1
  140. package/build-types/components/post-template/swap-template-button.d.ts +4 -0
  141. package/build-types/components/post-template/swap-template-button.d.ts.map +1 -1
  142. package/build-types/components/revision-block-diff/index.d.ts.map +1 -1
  143. package/build-types/components/revision-diff-panel/index.d.ts +14 -0
  144. package/build-types/components/revision-diff-panel/index.d.ts.map +1 -0
  145. package/build-types/components/revision-fields-diff/index.d.ts +6 -0
  146. package/build-types/components/revision-fields-diff/index.d.ts.map +1 -0
  147. package/build-types/components/sidebar/dataform-post-summary.d.ts.map +1 -1
  148. package/build-types/components/sidebar/index.d.ts.map +1 -1
  149. package/build-types/components/sidebar/post-revision-summary.d.ts +2 -0
  150. package/build-types/components/sidebar/post-revision-summary.d.ts.map +1 -0
  151. package/build-types/components/sidebar/post-summary.d.ts +3 -0
  152. package/build-types/components/sidebar/post-summary.d.ts.map +1 -1
  153. package/build-types/components/style-book/index.d.ts +2 -1
  154. package/build-types/components/style-book/index.d.ts.map +1 -1
  155. package/build-types/components/template-actions-panel/block-theme-content.d.ts +2 -0
  156. package/build-types/components/template-actions-panel/block-theme-content.d.ts.map +1 -0
  157. package/build-types/components/template-actions-panel/classic-theme-content.d.ts +2 -0
  158. package/build-types/components/template-actions-panel/classic-theme-content.d.ts.map +1 -0
  159. package/build-types/components/template-actions-panel/index.d.ts +2 -0
  160. package/build-types/components/template-actions-panel/index.d.ts.map +1 -0
  161. package/build-types/dataviews/store/private-actions.d.ts.map +1 -1
  162. package/build-types/store/private-actions.d.ts.map +1 -1
  163. package/build-types/store/private-selectors.d.ts.map +1 -1
  164. package/package.json +45 -44
  165. package/src/components/collaborators-overlay/cursor-registry.ts +96 -0
  166. package/src/components/collaborators-overlay/index.tsx +12 -4
  167. package/src/components/collaborators-overlay/overlay-iframe-styles.ts +1 -1
  168. package/src/components/collaborators-overlay/overlay.tsx +45 -1
  169. package/src/components/collaborators-presence/index.tsx +9 -1
  170. package/src/components/collaborators-presence/list.tsx +25 -1
  171. package/src/components/post-card-panel/index.js +7 -21
  172. package/src/components/post-content-information/index.js +5 -16
  173. package/src/components/post-revisions-panel/index.js +151 -0
  174. package/src/components/post-revisions-panel/style.scss +16 -0
  175. package/src/components/post-revisions-preview/revisions-slider.js +29 -7
  176. package/src/components/post-template/create-new-template-modal.js +1 -4
  177. package/src/components/post-template/hooks.js +65 -9
  178. package/src/components/post-template/style.scss +0 -6
  179. package/src/components/post-template/swap-template-button.js +30 -21
  180. package/src/components/preferences-modal/index.js +37 -25
  181. package/src/components/revision-block-diff/index.js +8 -43
  182. package/src/components/revision-diff-panel/index.js +59 -0
  183. package/src/components/revision-fields-diff/index.js +91 -0
  184. package/src/components/sidebar/dataform-post-summary.js +8 -55
  185. package/src/components/sidebar/index.js +33 -22
  186. package/src/components/sidebar/post-revision-summary.js +50 -0
  187. package/src/components/sidebar/post-summary.js +22 -40
  188. package/src/components/sidebar/style.scss +7 -0
  189. package/src/components/style-book/index.js +4 -2
  190. package/src/components/sync-connection-error-modal/index.tsx +2 -2
  191. package/src/components/template-actions-panel/block-theme-content.js +196 -0
  192. package/src/components/template-actions-panel/classic-theme-content.js +170 -0
  193. package/src/components/template-actions-panel/index.js +32 -0
  194. package/src/components/template-actions-panel/style.scss +39 -0
  195. package/src/dataviews/store/private-actions.ts +6 -0
  196. package/src/store/private-actions.js +24 -3
  197. package/src/store/private-selectors.js +46 -16
  198. package/src/style.scss +3 -1
  199. /package/src/components/{revision-block-diff → revision-diff-panel}/style.scss +0 -0
@@ -23,7 +23,6 @@ import { PrivatePostExcerptPanel as PostExcerptPanel } from '../post-excerpt/pan
23
23
  import PostFeaturedImagePanel from '../post-featured-image/panel';
24
24
  import PostFormatPanel from '../post-format/panel';
25
25
  import PostLastEditedPanel from '../post-last-edited-panel';
26
- import RevisionCreatedPanel from '../revision-created-panel';
27
26
  import PostPanelSection from '../post-panel-section';
28
27
  import PostSchedulePanel from '../post-schedule/panel';
29
28
  import PostStatusPanel from '../post-status';
@@ -36,14 +35,24 @@ import SiteDiscussion from '../site-discussion';
36
35
  import { store as editorStore } from '../../store';
37
36
  import { PrivatePostLastRevision } from '../post-last-revision';
38
37
  import PostTrash from '../post-trash';
39
- import RevisionAuthorPanel from '../revision-author-panel';
40
- import { unlock } from '../../lock-unlock';
41
38
 
42
39
  /**
43
40
  * Module Constants
44
41
  */
45
42
  const PANEL_NAME = 'post-status';
46
43
 
44
+ export function OpenRevisionsClassicScreen( { revisionId } ) {
45
+ return (
46
+ <ExternalLink
47
+ href={ addQueryArgs( 'revision.php', {
48
+ revision: revisionId,
49
+ } ) }
50
+ >
51
+ { __( 'Open classic revisions screen' ) }
52
+ </ExternalLink>
53
+ );
54
+ }
55
+
47
56
  export default function PostSummary( { onActionPerformed } ) {
48
57
  const postType = useSelect(
49
58
  ( select ) => select( editorStore ).getCurrentPostType(),
@@ -59,28 +68,23 @@ export default function PostSummary( { onActionPerformed } ) {
59
68
  }
60
69
 
61
70
  function ClassicPostSummary( { onActionPerformed } ) {
62
- const { isRemovedPostStatusPanel, postType, postId, revisionId } =
63
- useSelect( ( select ) => {
71
+ const { isRemovedPostStatusPanel, postType, postId } = useSelect(
72
+ ( select ) => {
64
73
  // We use isEditorPanelRemoved to hide the panel if it was programmatically removed. We do
65
74
  // not use isEditorPanelEnabled since this panel should not be disabled through the UI.
66
75
  const {
67
76
  isEditorPanelRemoved,
68
77
  getCurrentPostType,
69
78
  getCurrentPostId,
70
- getCurrentRevisionId,
71
- } = unlock( select( editorStore ) );
79
+ } = select( editorStore );
72
80
  return {
73
81
  isRemovedPostStatusPanel: isEditorPanelRemoved( PANEL_NAME ),
74
82
  postType: getCurrentPostType(),
75
83
  postId: getCurrentPostId(),
76
- revisionId: getCurrentRevisionId(),
77
84
  };
78
- }, [] );
79
-
80
- const isRevisionsMode = !! revisionId;
81
- const shouldShowPostStatusPanel =
82
- ! isRemovedPostStatusPanel && ! isRevisionsMode;
83
-
85
+ },
86
+ []
87
+ );
84
88
  return (
85
89
  <PostPanelSection className="editor-post-summary">
86
90
  <PluginPostStatusInfo.Slot>
@@ -92,35 +96,13 @@ function ClassicPostSummary( { onActionPerformed } ) {
92
96
  postId={ postId }
93
97
  onActionPerformed={ onActionPerformed }
94
98
  />
95
- { ! isRevisionsMode && (
96
- <PostFeaturedImagePanel
97
- withPanelBody={ false }
98
- />
99
- ) }
100
- { ! isRevisionsMode && <PostExcerptPanel /> }
99
+ <PostFeaturedImagePanel withPanelBody={ false } />
100
+ <PostExcerptPanel />
101
101
  <VStack spacing={ 1 }>
102
102
  <PostContentInformation />
103
- { isRevisionsMode ? (
104
- <RevisionCreatedPanel />
105
- ) : (
106
- <PostLastEditedPanel />
107
- ) }
103
+ <PostLastEditedPanel />
108
104
  </VStack>
109
- { isRevisionsMode && revisionId && (
110
- <>
111
- <ExternalLink
112
- href={ addQueryArgs( 'revision.php', {
113
- revision: revisionId,
114
- } ) }
115
- >
116
- { __(
117
- 'Open classic revisions screen'
118
- ) }
119
- </ExternalLink>
120
- <RevisionAuthorPanel />
121
- </>
122
- ) }
123
- { shouldShowPostStatusPanel && (
105
+ { ! isRemovedPostStatusPanel && (
124
106
  <VStack spacing={ 4 }>
125
107
  <VStack spacing={ 1 }>
126
108
  <PostStatusPanel />
@@ -28,3 +28,10 @@
28
28
  font-size: $default-font-size;
29
29
  }
30
30
  }
31
+
32
+ // TODO: These styles should be absorbed by DataForm API.
33
+ // @see https://github.com/WordPress/gutenberg/issues/75916
34
+ .fields-controls__password {
35
+ border-top: $border-width solid $gray-200;
36
+ padding-top: $grid-unit-20;
37
+ }
@@ -375,6 +375,7 @@ function StyleBook(
375
375
  * @param {Function} props.onPathChange Callback when the path changes.
376
376
  * @param {Object} props.userConfig User configuration.
377
377
  * @param {boolean} props.isStatic Whether the stylebook is static or clickable.
378
+ * @param {Object} props.settings Optional editor settings to use instead of the editor store settings.
378
379
  * @return {Object} Style Book Preview component.
379
380
  */
380
381
  export const StyleBookPreview = ( {
@@ -382,10 +383,11 @@ export const StyleBookPreview = ( {
382
383
  isStatic = false,
383
384
  path,
384
385
  onPathChange,
386
+ settings: settingsProp,
385
387
  } ) => {
386
388
  const editorSettings = useSelect(
387
- ( select ) => select( editorStore ).getEditorSettings(),
388
- []
389
+ ( select ) => settingsProp ?? select( editorStore ).getEditorSettings(),
390
+ [ settingsProp ]
389
391
  );
390
392
 
391
393
  const canUserUploadMedia = useSelect(
@@ -35,11 +35,11 @@ const { BlockCanvasCover } = unlock( privateApis );
35
35
  const { retrySyncConnection } = unlock( coreDataPrivateApis );
36
36
 
37
37
  // Debounce time for initial disconnected status to allow connection to establish.
38
- const INITIAL_DISCONNECTED_DEBOUNCE_MS = 5000;
38
+ const INITIAL_DISCONNECTED_DEBOUNCE_MS = 20000;
39
39
 
40
40
  // Debounce time for showing the disconnect dialog after the intial connection,
41
41
  // allowing brief network interruptions to resolve.
42
- const DISCONNECTED_DEBOUNCE_MS = 2000;
42
+ const DISCONNECTED_DEBOUNCE_MS = 8000;
43
43
 
44
44
  export interface SyncConnectionErrorModalProps {
45
45
  description: string; // Modal description.
@@ -0,0 +1,196 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useSelect, useDispatch } from '@wordpress/data';
5
+ import {
6
+ useEntityRecord,
7
+ useEntityBlockEditor,
8
+ store as coreStore,
9
+ } from '@wordpress/core-data';
10
+ import { BlockPreview } from '@wordpress/block-editor';
11
+ import {
12
+ PanelBody,
13
+ Button,
14
+ Tooltip,
15
+ __experimentalHStack as HStack,
16
+ __experimentalVStack as VStack,
17
+ } from '@wordpress/components';
18
+ import { useState } from '@wordpress/element';
19
+ import { __, sprintf } from '@wordpress/i18n';
20
+ import { decodeEntities } from '@wordpress/html-entities';
21
+ import { store as noticesStore } from '@wordpress/notices';
22
+ import { store as preferencesStore } from '@wordpress/preferences';
23
+
24
+ /**
25
+ * Internal dependencies
26
+ */
27
+ import { store as editorStore } from '../../store';
28
+ import CreateNewTemplateModal from '../post-template/create-new-template-modal';
29
+ import { SwapTemplateModal } from '../post-template/swap-template-button';
30
+ import { useAvailableTemplates } from '../post-template/hooks';
31
+
32
+ export default function TemplateActionsPanelContent() {
33
+ const templateId = useSelect(
34
+ ( select ) => select( editorStore ).getCurrentTemplateId(),
35
+ []
36
+ );
37
+ const [ isCreateModalOpen, setIsCreateModalOpen ] = useState( false );
38
+ const [ isSwapModalOpen, setIsSwapModalOpen ] = useState( false );
39
+
40
+ const availableTemplates = useAvailableTemplates();
41
+ const hasSwapTargets = !! availableTemplates?.length;
42
+
43
+ const {
44
+ onNavigateToEntityRecord,
45
+ canCreateTemplate,
46
+ hasGoBack,
47
+ getEditorSettings,
48
+ } = useSelect( ( select ) => {
49
+ const { getEditorSettings: _getEditorSettings } = select( editorStore );
50
+ const editorSettings = _getEditorSettings();
51
+ return {
52
+ onNavigateToEntityRecord: editorSettings.onNavigateToEntityRecord,
53
+ canCreateTemplate: !! select( coreStore ).canUser( 'create', {
54
+ kind: 'postType',
55
+ name: 'wp_template',
56
+ } ),
57
+ hasGoBack: editorSettings.hasOwnProperty(
58
+ 'onNavigateToPreviousEntityRecord'
59
+ ),
60
+ getEditorSettings: _getEditorSettings,
61
+ };
62
+ }, [] );
63
+
64
+ const { get: getPreference } = useSelect( preferencesStore );
65
+ const { createSuccessNotice } = useDispatch( noticesStore );
66
+
67
+ const { editedRecord: template, hasResolved } = useEntityRecord(
68
+ 'postType',
69
+ 'wp_template',
70
+ templateId
71
+ );
72
+
73
+ const [ blocks ] = useEntityBlockEditor( 'postType', 'wp_template', {
74
+ id: templateId,
75
+ } );
76
+
77
+ if ( ! hasResolved ) {
78
+ return null;
79
+ }
80
+
81
+ // The site editor does not have a `onNavigateToPreviousEntityRecord` setting as it uses its own routing
82
+ // and assigns its own backlink to focusMode pages.
83
+ const notificationAction = hasGoBack
84
+ ? [
85
+ {
86
+ label: __( 'Go back' ),
87
+ onClick: () =>
88
+ getEditorSettings().onNavigateToPreviousEntityRecord(),
89
+ },
90
+ ]
91
+ : undefined;
92
+
93
+ const mayShowTemplateEditNotice = () => {
94
+ if ( ! getPreference( 'core/edit-site', 'welcomeGuideTemplate' ) ) {
95
+ createSuccessNotice(
96
+ __(
97
+ 'Editing template. Changes made here affect all posts and pages that use the template.'
98
+ ),
99
+ { type: 'snackbar', actions: notificationAction }
100
+ );
101
+ }
102
+ };
103
+
104
+ const templateName = decodeEntities( template.title );
105
+
106
+ const previewContent = !! blocks?.length && (
107
+ <BlockPreview.Async>
108
+ <BlockPreview blocks={ blocks } />
109
+ </BlockPreview.Async>
110
+ );
111
+
112
+ const renderPreview = () => {
113
+ if ( ! previewContent ) {
114
+ return null;
115
+ }
116
+
117
+ if ( hasSwapTargets ) {
118
+ const tooltipText = __( 'Change template' );
119
+ return (
120
+ <Tooltip text={ tooltipText }>
121
+ <div
122
+ className="editor-template-actions-panel__preview"
123
+ role="button"
124
+ tabIndex={ 0 }
125
+ aria-label={ tooltipText }
126
+ onClick={ () => setIsSwapModalOpen( true ) }
127
+ onKeyPress={ () => setIsSwapModalOpen( true ) }
128
+ >
129
+ { previewContent }
130
+ </div>
131
+ </Tooltip>
132
+ );
133
+ }
134
+
135
+ return (
136
+ <div className="editor-template-actions-panel__preview">
137
+ { previewContent }
138
+ </div>
139
+ );
140
+ };
141
+
142
+ return (
143
+ <>
144
+ <PanelBody
145
+ title={ sprintf(
146
+ /* translators: %s: template name */
147
+ __( 'Template: %s' ),
148
+ templateName
149
+ ) }
150
+ initialOpen={ false }
151
+ >
152
+ <VStack>
153
+ { renderPreview() }
154
+ <HStack>
155
+ { onNavigateToEntityRecord && (
156
+ <Button
157
+ className="editor-template-actions-panel__action"
158
+ __next40pxDefaultSize
159
+ variant="secondary"
160
+ onClick={ () => {
161
+ onNavigateToEntityRecord( {
162
+ postId: template.id,
163
+ postType: 'wp_template',
164
+ } );
165
+ mayShowTemplateEditNotice();
166
+ } }
167
+ >
168
+ { __( 'Edit' ) }
169
+ </Button>
170
+ ) }
171
+ { canCreateTemplate && (
172
+ <Button
173
+ className="editor-template-actions-panel__action"
174
+ __next40pxDefaultSize
175
+ variant="secondary"
176
+ onClick={ () => setIsCreateModalOpen( true ) }
177
+ >
178
+ { __( 'Create new' ) }
179
+ </Button>
180
+ ) }
181
+ </HStack>
182
+ </VStack>
183
+ </PanelBody>
184
+ { isCreateModalOpen && (
185
+ <CreateNewTemplateModal
186
+ onClose={ () => setIsCreateModalOpen( false ) }
187
+ />
188
+ ) }
189
+ { isSwapModalOpen && (
190
+ <SwapTemplateModal
191
+ onRequestClose={ () => setIsSwapModalOpen( false ) }
192
+ />
193
+ ) }
194
+ </>
195
+ );
196
+ }
@@ -0,0 +1,170 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useSelect, useDispatch } from '@wordpress/data';
5
+ import {
6
+ useEntityRecord,
7
+ useEntityBlockEditor,
8
+ store as coreStore,
9
+ } from '@wordpress/core-data';
10
+ import { BlockPreview } from '@wordpress/block-editor';
11
+ import {
12
+ PanelBody,
13
+ Button,
14
+ __experimentalText as Text,
15
+ __experimentalHStack as HStack,
16
+ __experimentalVStack as VStack,
17
+ } from '@wordpress/components';
18
+ import { useState } from '@wordpress/element';
19
+ import { __, sprintf } from '@wordpress/i18n';
20
+ import { decodeEntities } from '@wordpress/html-entities';
21
+ import { store as noticesStore } from '@wordpress/notices';
22
+ import { store as preferencesStore } from '@wordpress/preferences';
23
+
24
+ /**
25
+ * Internal dependencies
26
+ */
27
+ import { store as editorStore } from '../../store';
28
+ import CreateNewTemplateModal from '../post-template/create-new-template-modal';
29
+
30
+ export default function ClassicThemeContent() {
31
+ const templateId = useSelect(
32
+ ( select ) => select( editorStore ).getCurrentTemplateId(),
33
+ []
34
+ );
35
+ const [ isCreateModalOpen, setIsCreateModalOpen ] = useState( false );
36
+ const {
37
+ onNavigateToEntityRecord,
38
+ canCreateTemplate,
39
+ hasGoBack,
40
+ getEditorSettings,
41
+ } = useSelect( ( select ) => {
42
+ const { getEditorSettings: _getEditorSettings } = select( editorStore );
43
+ const editorSettings = _getEditorSettings();
44
+ return {
45
+ onNavigateToEntityRecord: editorSettings.onNavigateToEntityRecord,
46
+ canCreateTemplate:
47
+ !! select( coreStore ).canUser( 'create', {
48
+ kind: 'postType',
49
+ name: 'wp_template',
50
+ } ) && editorSettings.supportsTemplateMode,
51
+ hasGoBack: editorSettings.hasOwnProperty(
52
+ 'onNavigateToPreviousEntityRecord'
53
+ ),
54
+ getEditorSettings: _getEditorSettings,
55
+ };
56
+ }, [] );
57
+ const { get: getPreference } = useSelect( preferencesStore );
58
+ const { createSuccessNotice } = useDispatch( noticesStore );
59
+ const { editedRecord: template } = useEntityRecord(
60
+ 'postType',
61
+ 'wp_template',
62
+ templateId
63
+ );
64
+ const [ blocks ] = useEntityBlockEditor( 'postType', 'wp_template', {
65
+ id: templateId,
66
+ } );
67
+
68
+ // Path A: No block template and cannot create templates.
69
+ if ( ! templateId && ! canCreateTemplate ) {
70
+ return null;
71
+ }
72
+
73
+ const notificationAction = hasGoBack
74
+ ? [
75
+ {
76
+ label: __( 'Go back' ),
77
+ onClick: () =>
78
+ getEditorSettings().onNavigateToPreviousEntityRecord(),
79
+ },
80
+ ]
81
+ : undefined;
82
+
83
+ const mayShowTemplateEditNotice = () => {
84
+ if ( ! getPreference( 'core/edit-site', 'welcomeGuideTemplate' ) ) {
85
+ createSuccessNotice(
86
+ __(
87
+ 'Editing template. Changes made here affect all posts and pages that use the template.'
88
+ ),
89
+ { type: 'snackbar', actions: notificationAction }
90
+ );
91
+ }
92
+ };
93
+
94
+ const templateName = template
95
+ ? decodeEntities( template.title )
96
+ : undefined;
97
+
98
+ const previewContent = !! blocks?.length && (
99
+ <BlockPreview.Async>
100
+ <BlockPreview blocks={ blocks } />
101
+ </BlockPreview.Async>
102
+ );
103
+
104
+ return (
105
+ <>
106
+ <PanelBody
107
+ title={
108
+ template
109
+ ? sprintf(
110
+ /* translators: %s: template name */
111
+ __( 'Template: %s' ),
112
+ templateName
113
+ )
114
+ : __( 'Template' )
115
+ }
116
+ initialOpen={ false }
117
+ >
118
+ <VStack>
119
+ { ! templateId && (
120
+ <Text>
121
+ { __(
122
+ 'This page uses a classic template. To edit this template with blocks, create a block template.'
123
+ ) }
124
+ </Text>
125
+ ) }
126
+ { template && previewContent && (
127
+ <div className="editor-template-actions-panel__preview">
128
+ { previewContent }
129
+ </div>
130
+ ) }
131
+ <HStack>
132
+ { template && onNavigateToEntityRecord && (
133
+ <Button
134
+ className="editor-template-actions-panel__action"
135
+ __next40pxDefaultSize
136
+ variant="secondary"
137
+ onClick={ () => {
138
+ onNavigateToEntityRecord( {
139
+ postId: template.id,
140
+ postType: 'wp_template',
141
+ } );
142
+ mayShowTemplateEditNotice();
143
+ } }
144
+ >
145
+ { __( 'Edit' ) }
146
+ </Button>
147
+ ) }
148
+ { canCreateTemplate && (
149
+ <Button
150
+ className="editor-template-actions-panel__action"
151
+ __next40pxDefaultSize
152
+ variant="secondary"
153
+ onClick={ () => setIsCreateModalOpen( true ) }
154
+ >
155
+ { ! templateId
156
+ ? __( 'Create block template' )
157
+ : __( 'Create new' ) }
158
+ </Button>
159
+ ) }
160
+ </HStack>
161
+ </VStack>
162
+ </PanelBody>
163
+ { isCreateModalOpen && (
164
+ <CreateNewTemplateModal
165
+ onClose={ () => setIsCreateModalOpen( false ) }
166
+ />
167
+ ) }
168
+ </>
169
+ );
170
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useSelect } from '@wordpress/data';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import { store as editorStore } from '../../store';
10
+ import { usePostTemplatePanelMode } from '../post-template/hooks';
11
+ import BlockThemeContent from './block-theme-content';
12
+ import ClassicThemeContent from './classic-theme-content';
13
+
14
+ export default function TemplateActionsPanel() {
15
+ const postType = useSelect(
16
+ ( select ) => select( editorStore ).getCurrentPostType(),
17
+ []
18
+ );
19
+ const mode = usePostTemplatePanelMode();
20
+ // This check is because the experiment is gated for these post
21
+ // types for now. Later we should use `postType.viewable`.
22
+ if ( ! [ 'page', 'post' ].includes( postType ) ) {
23
+ return null;
24
+ }
25
+ if ( mode === 'classic' ) {
26
+ return <ClassicThemeContent />;
27
+ }
28
+ if ( mode === 'block-theme' ) {
29
+ return <BlockThemeContent />;
30
+ }
31
+ return null;
32
+ }
@@ -0,0 +1,39 @@
1
+ @use "@wordpress/base-styles/variables" as *;
2
+ @use "@wordpress/base-styles/colors" as *;
3
+
4
+ .editor-template-actions-panel__preview {
5
+ .block-editor-block-preview__container {
6
+ display: flex;
7
+ aspect-ratio: 4/3;
8
+ overflow: hidden;
9
+ border-radius: $radius-medium;
10
+
11
+ &::after {
12
+ outline: $border-width solid rgba($black, 0.1);
13
+ outline-offset: -$border-width;
14
+ border-radius: $radius-medium;
15
+ @media not (prefers-reduced-motion) {
16
+ transition: outline 0.1s linear;
17
+ }
18
+ }
19
+ }
20
+
21
+ &[role="button"] {
22
+ cursor: pointer;
23
+
24
+ &:hover .block-editor-block-preview__container::after {
25
+ outline-color: rgba($black, 0.3);
26
+ }
27
+
28
+ &:focus-visible .block-editor-block-preview__container::after {
29
+ outline-color: var(--wp-admin-theme-color);
30
+ outline-width: var(--wp-admin-border-width-focus);
31
+ outline-offset: calc(-1 * var(--wp-admin-border-width-focus));
32
+ }
33
+ }
34
+ }
35
+
36
+ .editor-template-actions-panel__action {
37
+ flex: 1;
38
+ justify-content: center;
39
+ }
@@ -19,6 +19,7 @@ import {
19
19
  resetPost,
20
20
  deletePost,
21
21
  duplicateTemplatePart,
22
+ excerptField,
22
23
  featuredImageField,
23
24
  dateField,
24
25
  parentField,
@@ -38,6 +39,7 @@ import {
38
39
  scheduledDateField,
39
40
  formatField,
40
41
  postContentInfoField,
42
+ stickyField,
41
43
  } from '@wordpress/fields';
42
44
  import {
43
45
  altTextField,
@@ -267,6 +269,9 @@ export const registerPostTypeSchema =
267
269
  ! DESIGN_POST_TYPES.includes( postTypeConfig.slug ) &&
268
270
  scheduledDateField,
269
271
  slugField,
272
+ ! DESIGN_POST_TYPES.includes( postTypeConfig.slug ) &&
273
+ postTypeConfig.supports?.excerpt &&
274
+ excerptField,
270
275
  postTypeConfig.supports?.[ 'page-attributes' ] && parentField,
271
276
  postTypeConfig.supports?.comments && commentStatusField,
272
277
  postTypeConfig.supports?.trackbacks && pingStatusField,
@@ -281,6 +286,7 @@ export const registerPostTypeSchema =
281
286
  postTypeConfig.supports?.editor &&
282
287
  postContentInfoField,
283
288
  passwordField,
289
+ postTypeConfig.slug === 'post' && stickyField,
284
290
  postTypeConfig.supports?.editor &&
285
291
  postTypeConfig.viewable &&
286
292
  postPreviewField,
@@ -627,6 +627,11 @@ export const restoreRevision =
627
627
  const postType = select.getCurrentPostType();
628
628
  const postId = select.getCurrentPostId();
629
629
 
630
+ const entityConfig = registry
631
+ .select( coreStore )
632
+ .getEntityConfig( 'postType', postType );
633
+ const revisionKey = entityConfig?.revisionKey || 'id';
634
+
630
635
  // Use resolveSelect to ensure the revision is fetched if not yet
631
636
  // in the store. The _fields parameter matches the query used by
632
637
  // getRevisions so the result is served from cache without an
@@ -635,8 +640,19 @@ export const restoreRevision =
635
640
  .resolveSelect( coreStore )
636
641
  .getRevision( 'postType', postType, postId, revisionId, {
637
642
  context: 'edit',
638
- _fields:
639
- 'id,date,author,meta,title.raw,excerpt.raw,content.raw',
643
+ _fields: [
644
+ ...new Set( [
645
+ 'id',
646
+ 'date',
647
+ 'modified',
648
+ 'author',
649
+ 'meta',
650
+ 'title.raw',
651
+ 'excerpt.raw',
652
+ 'content.raw',
653
+ revisionKey,
654
+ ] ),
655
+ ].join(),
640
656
  } );
641
657
 
642
658
  if ( ! revision ) {
@@ -672,7 +688,12 @@ export const restoreRevision =
672
688
  sprintf(
673
689
  /* translators: %s: Date and time of the revision. */
674
690
  __( 'Restored to revision from %s.' ),
675
- dateI18n( getDateSettings().formats.datetime, revision.date )
691
+ dateI18n(
692
+ getDateSettings().formats.datetime,
693
+ // Template revisions use the template REST API format, which
694
+ // exposes 'modified' instead of 'date'.
695
+ revisionKey === 'wp_id' ? revision.modified : revision.date
696
+ )
676
697
  ),
677
698
  {
678
699
  type: 'snackbar',