@wordpress/editor 14.50.0 → 14.51.1-next.v.202607070741.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 (197) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/build/components/collab-sidebar/format.cjs +83 -0
  3. package/build/components/collab-sidebar/format.cjs.map +7 -0
  4. package/build/components/collab-sidebar/hooks.cjs +117 -16
  5. package/build/components/collab-sidebar/hooks.cjs.map +2 -2
  6. package/build/components/collab-sidebar/index.cjs +18 -2
  7. package/build/components/collab-sidebar/index.cjs.map +2 -2
  8. package/build/components/collab-sidebar/note-highlight-styles.cjs +67 -0
  9. package/build/components/collab-sidebar/note-highlight-styles.cjs.map +7 -0
  10. package/build/components/collab-sidebar/utils.cjs +139 -0
  11. package/build/components/collab-sidebar/utils.cjs.map +2 -2
  12. package/build/components/collaborators-presence/use-collaborator-notifications.cjs +55 -30
  13. package/build/components/collaborators-presence/use-collaborator-notifications.cjs.map +2 -2
  14. package/build/components/commands/index.cjs +99 -3
  15. package/build/components/commands/index.cjs.map +2 -2
  16. package/build/components/document-bar/index.cjs +28 -34
  17. package/build/components/document-bar/index.cjs.map +2 -2
  18. package/build/components/entities-saved-states/index.cjs +1 -4
  19. package/build/components/entities-saved-states/index.cjs.map +2 -2
  20. package/build/components/media-categories/index.cjs +92 -6
  21. package/build/components/media-categories/index.cjs.map +2 -2
  22. package/build/components/page-attributes/parent.cjs +0 -1
  23. package/build/components/page-attributes/parent.cjs.map +2 -2
  24. package/build/components/post-author/combobox.cjs +0 -1
  25. package/build/components/post-author/combobox.cjs.map +2 -2
  26. package/build/components/post-author/select.cjs +0 -1
  27. package/build/components/post-author/select.cjs.map +2 -2
  28. package/build/components/post-preview-button/index.cjs +29 -2
  29. package/build/components/post-preview-button/index.cjs.map +2 -2
  30. package/build/components/post-publish-panel/maybe-upload-media.cjs +15 -26
  31. package/build/components/post-publish-panel/maybe-upload-media.cjs.map +3 -3
  32. package/build/components/post-revisions-preview/revisions-slider.cjs +3 -1
  33. package/build/components/post-revisions-preview/revisions-slider.cjs.map +2 -2
  34. package/build/components/post-taxonomies/flat-term-selector.cjs +0 -1
  35. package/build/components/post-taxonomies/flat-term-selector.cjs.map +2 -2
  36. package/build/components/post-taxonomies/hierarchical-term-selector.cjs +0 -2
  37. package/build/components/post-taxonomies/hierarchical-term-selector.cjs.map +2 -2
  38. package/build/components/post-template/classic-theme.cjs +0 -1
  39. package/build/components/post-template/classic-theme.cjs.map +2 -2
  40. package/build/components/preferences-modal/index.cjs +54 -28
  41. package/build/components/preferences-modal/index.cjs.map +2 -2
  42. package/build/components/preview-dropdown/index.cjs +3 -3
  43. package/build/components/preview-dropdown/index.cjs.map +2 -2
  44. package/build/components/provider/use-block-editor-settings.cjs +23 -3
  45. package/build/components/provider/use-block-editor-settings.cjs.map +3 -3
  46. package/build/components/sidebar/dataform-post-summary.cjs +5 -1
  47. package/build/components/sidebar/dataform-post-summary.cjs.map +3 -3
  48. package/build/components/sidebar/index.cjs +29 -38
  49. package/build/components/sidebar/index.cjs.map +3 -3
  50. package/build/components/sidebar/post-summary.cjs +0 -13
  51. package/build/components/sidebar/post-summary.cjs.map +3 -3
  52. package/build/dataviews/store/private-actions.cjs +24 -19
  53. package/build/dataviews/store/private-actions.cjs.map +2 -2
  54. package/build/store/private-actions.cjs +5 -2
  55. package/build/store/private-actions.cjs.map +2 -2
  56. package/build/utils/media-sideload-from-url/index.cjs +63 -0
  57. package/build/utils/media-sideload-from-url/index.cjs.map +7 -0
  58. package/build-module/components/collab-sidebar/format.mjs +57 -0
  59. package/build-module/components/collab-sidebar/format.mjs.map +7 -0
  60. package/build-module/components/collab-sidebar/hooks.mjs +121 -16
  61. package/build-module/components/collab-sidebar/hooks.mjs.map +2 -2
  62. package/build-module/components/collab-sidebar/index.mjs +21 -5
  63. package/build-module/components/collab-sidebar/index.mjs.map +2 -2
  64. package/build-module/components/collab-sidebar/note-highlight-styles.mjs +41 -0
  65. package/build-module/components/collab-sidebar/note-highlight-styles.mjs.map +7 -0
  66. package/build-module/components/collab-sidebar/utils.mjs +133 -0
  67. package/build-module/components/collab-sidebar/utils.mjs.map +2 -2
  68. package/build-module/components/collaborators-presence/use-collaborator-notifications.mjs +55 -30
  69. package/build-module/components/collaborators-presence/use-collaborator-notifications.mjs.map +2 -2
  70. package/build-module/components/commands/index.mjs +99 -3
  71. package/build-module/components/commands/index.mjs.map +2 -2
  72. package/build-module/components/document-bar/index.mjs +28 -34
  73. package/build-module/components/document-bar/index.mjs.map +2 -2
  74. package/build-module/components/entities-saved-states/index.mjs +1 -4
  75. package/build-module/components/entities-saved-states/index.mjs.map +2 -2
  76. package/build-module/components/media-categories/index.mjs +93 -7
  77. package/build-module/components/media-categories/index.mjs.map +2 -2
  78. package/build-module/components/page-attributes/parent.mjs +0 -1
  79. package/build-module/components/page-attributes/parent.mjs.map +2 -2
  80. package/build-module/components/post-author/combobox.mjs +0 -1
  81. package/build-module/components/post-author/combobox.mjs.map +2 -2
  82. package/build-module/components/post-author/select.mjs +0 -1
  83. package/build-module/components/post-author/select.mjs.map +2 -2
  84. package/build-module/components/post-preview-button/index.mjs +29 -2
  85. package/build-module/components/post-preview-button/index.mjs.map +2 -2
  86. package/build-module/components/post-publish-panel/maybe-upload-media.mjs +19 -27
  87. package/build-module/components/post-publish-panel/maybe-upload-media.mjs.map +2 -2
  88. package/build-module/components/post-revisions-preview/revisions-slider.mjs +3 -1
  89. package/build-module/components/post-revisions-preview/revisions-slider.mjs.map +2 -2
  90. package/build-module/components/post-taxonomies/flat-term-selector.mjs +0 -1
  91. package/build-module/components/post-taxonomies/flat-term-selector.mjs.map +2 -2
  92. package/build-module/components/post-taxonomies/hierarchical-term-selector.mjs +0 -2
  93. package/build-module/components/post-taxonomies/hierarchical-term-selector.mjs.map +2 -2
  94. package/build-module/components/post-template/classic-theme.mjs +0 -1
  95. package/build-module/components/post-template/classic-theme.mjs.map +2 -2
  96. package/build-module/components/preferences-modal/index.mjs +54 -28
  97. package/build-module/components/preferences-modal/index.mjs.map +2 -2
  98. package/build-module/components/preview-dropdown/index.mjs +3 -3
  99. package/build-module/components/preview-dropdown/index.mjs.map +2 -2
  100. package/build-module/components/provider/use-block-editor-settings.mjs +23 -3
  101. package/build-module/components/provider/use-block-editor-settings.mjs.map +2 -2
  102. package/build-module/components/sidebar/dataform-post-summary.mjs +6 -2
  103. package/build-module/components/sidebar/dataform-post-summary.mjs.map +2 -2
  104. package/build-module/components/sidebar/index.mjs +29 -42
  105. package/build-module/components/sidebar/index.mjs.map +2 -2
  106. package/build-module/components/sidebar/post-summary.mjs +0 -13
  107. package/build-module/components/sidebar/post-summary.mjs.map +2 -2
  108. package/build-module/dataviews/store/private-actions.mjs +26 -19
  109. package/build-module/dataviews/store/private-actions.mjs.map +2 -2
  110. package/build-module/store/private-actions.mjs +5 -2
  111. package/build-module/store/private-actions.mjs.map +2 -2
  112. package/build-module/utils/media-sideload-from-url/index.mjs +32 -0
  113. package/build-module/utils/media-sideload-from-url/index.mjs.map +7 -0
  114. package/build-style/style-rtl.css +65 -33
  115. package/build-style/style.css +65 -33
  116. package/build-types/components/collab-sidebar/format.d.ts +17 -0
  117. package/build-types/components/collab-sidebar/format.d.ts.map +1 -0
  118. package/build-types/components/collab-sidebar/hooks.d.ts.map +1 -1
  119. package/build-types/components/collab-sidebar/index.d.ts.map +1 -1
  120. package/build-types/components/collab-sidebar/note-highlight-styles.d.ts +31 -0
  121. package/build-types/components/collab-sidebar/note-highlight-styles.d.ts.map +1 -0
  122. package/build-types/components/collab-sidebar/utils.d.ts +82 -2
  123. package/build-types/components/collab-sidebar/utils.d.ts.map +1 -1
  124. package/build-types/components/collaborators-presence/use-collaborator-notifications.d.ts.map +1 -1
  125. package/build-types/components/commands/index.d.ts.map +1 -1
  126. package/build-types/components/document-bar/index.d.ts.map +1 -1
  127. package/build-types/components/entities-saved-states/index.d.ts.map +1 -1
  128. package/build-types/components/media-categories/index.d.ts +12 -3
  129. package/build-types/components/media-categories/index.d.ts.map +1 -1
  130. package/build-types/components/page-attributes/parent.d.ts.map +1 -1
  131. package/build-types/components/post-author/combobox.d.ts.map +1 -1
  132. package/build-types/components/post-author/select.d.ts.map +1 -1
  133. package/build-types/components/post-preview-button/index.d.ts.map +1 -1
  134. package/build-types/components/post-publish-panel/maybe-upload-media.d.ts.map +1 -1
  135. package/build-types/components/post-revisions-preview/revisions-slider.d.ts.map +1 -1
  136. package/build-types/components/post-taxonomies/flat-term-selector.d.ts.map +1 -1
  137. package/build-types/components/post-taxonomies/hierarchical-term-selector.d.ts.map +1 -1
  138. package/build-types/components/post-template/classic-theme.d.ts.map +1 -1
  139. package/build-types/components/provider/use-block-editor-settings.d.ts.map +1 -1
  140. package/build-types/components/sidebar/dataform-post-summary.d.ts.map +1 -1
  141. package/build-types/components/sidebar/index.d.ts.map +1 -1
  142. package/build-types/components/sidebar/post-summary.d.ts.map +1 -1
  143. package/build-types/dataviews/store/private-actions.d.ts.map +1 -1
  144. package/build-types/store/private-actions.d.ts.map +1 -1
  145. package/build-types/store/selectors.d.ts.map +1 -1
  146. package/build-types/utils/get-template-part-icon.d.ts.map +1 -1
  147. package/build-types/utils/media-sideload-from-url/index.d.ts +18 -0
  148. package/build-types/utils/media-sideload-from-url/index.d.ts.map +1 -0
  149. package/package.json +48 -46
  150. package/src/components/collab-sidebar/format.js +72 -0
  151. package/src/components/collab-sidebar/hooks.js +203 -22
  152. package/src/components/collab-sidebar/index.js +19 -5
  153. package/src/components/collab-sidebar/note-highlight-styles.js +83 -0
  154. package/src/components/collab-sidebar/style.scss +9 -0
  155. package/src/components/collab-sidebar/test/note-highlight-styles.js +106 -0
  156. package/src/components/collab-sidebar/test/utils.js +471 -0
  157. package/src/components/collab-sidebar/utils.js +225 -2
  158. package/src/components/collaborators-presence/test/use-collaborator-notifications.ts +265 -262
  159. package/src/components/collaborators-presence/use-collaborator-notifications.ts +70 -34
  160. package/src/components/commands/index.js +142 -0
  161. package/src/components/document-bar/index.js +0 -9
  162. package/src/components/document-bar/style.scss +0 -17
  163. package/src/components/entities-saved-states/index.js +1 -5
  164. package/src/components/header/style.scss +7 -3
  165. package/src/components/media-categories/index.js +160 -6
  166. package/src/components/media-categories/test/index.js +202 -0
  167. package/src/components/page-attributes/parent.js +0 -1
  168. package/src/components/post-author/combobox.js +0 -1
  169. package/src/components/post-author/select.js +0 -1
  170. package/src/components/post-preview-button/index.js +68 -2
  171. package/src/components/post-publish-panel/maybe-upload-media.js +25 -30
  172. package/src/components/post-publish-panel/style.scss +1 -1
  173. package/src/components/post-publish-panel/test/__snapshots__/index.js.snap +11 -127
  174. package/src/components/post-revisions-preview/revisions-slider.js +4 -1
  175. package/src/components/post-revisions-preview/test/block-diff.js +2 -2
  176. package/src/components/post-taxonomies/flat-term-selector.js +0 -1
  177. package/src/components/post-taxonomies/hierarchical-term-selector.js +0 -2
  178. package/src/components/post-template/classic-theme.js +0 -1
  179. package/src/components/preferences-modal/index.js +40 -22
  180. package/src/components/preferences-modal/test/index.js +83 -0
  181. package/src/components/preview-dropdown/index.js +3 -3
  182. package/src/components/provider/use-block-editor-settings.js +42 -1
  183. package/src/components/sidebar/dataform-post-summary.js +13 -1
  184. package/src/components/sidebar/index.js +32 -47
  185. package/src/components/sidebar/post-summary.js +0 -17
  186. package/src/dataviews/store/private-actions.ts +30 -26
  187. package/src/store/private-actions.js +6 -2
  188. package/src/utils/media-sideload-from-url/index.js +54 -0
  189. package/src/utils/media-sideload-from-url/test/index.js +162 -0
  190. package/build/components/post-publish-panel/media-util.cjs +0 -72
  191. package/build/components/post-publish-panel/media-util.cjs.map +0 -7
  192. package/build-module/components/post-publish-panel/media-util.mjs +0 -46
  193. package/build-module/components/post-publish-panel/media-util.mjs.map +0 -7
  194. package/build-types/components/post-publish-panel/media-util.d.ts +0 -20
  195. package/build-types/components/post-publish-panel/media-util.d.ts.map +0 -1
  196. package/src/components/post-publish-panel/media-util.js +0 -87
  197. package/src/components/post-publish-panel/test/media-util.js +0 -118
@@ -279,7 +279,6 @@ export function FlatTermSelector( { slug } ) {
279
279
  return (
280
280
  <Stack direction="column" gap="lg">
281
281
  <FormTokenField
282
- __next40pxDefaultSize
283
282
  value={ values }
284
283
  suggestions={ suggestions }
285
284
  onChange={ onChange }
@@ -417,7 +417,6 @@ export function HierarchicalTermSelector( { slug } ) {
417
417
  <Flex direction="column" gap="4">
418
418
  { showFilter && ! loading && (
419
419
  <SearchControl
420
- __next40pxDefaultSize
421
420
  label={ filterLabel }
422
421
  placeholder={ filterLabel }
423
422
  value={ filterValue }
@@ -470,7 +469,6 @@ export function HierarchicalTermSelector( { slug } ) {
470
469
  />
471
470
  { !! availableTerms.length && (
472
471
  <TreeSelect
473
- __next40pxDefaultSize
474
472
  label={ parentSelectLabel }
475
473
  noOptionLabel={ noParentOption }
476
474
  onChange={ onChangeFormParent }
@@ -159,7 +159,6 @@ function PostTemplateDropdownContent( { onClose } ) {
159
159
  </Notice>
160
160
  ) : (
161
161
  <SelectControl
162
- __next40pxDefaultSize
163
162
  hideLabelFromVision
164
163
  label={ __( 'Template' ) }
165
164
  value={ selectedOption?.value ?? '' }
@@ -126,30 +126,48 @@ function PreferencesModalContents( { extraSections = {} } ) {
126
126
  label={ __( 'Show starter patterns' ) }
127
127
  />
128
128
  { showCollaborationOptions && (
129
- <>
130
- <PreferenceToggleControl
131
- scope="core"
132
- featureName="showCollaborationCursor"
133
- help={ __(
134
- 'Show your own avatar inside blocks during collaborative editing sessions.'
135
- ) }
136
- label={ __(
137
- 'Show avatar in blocks'
138
- ) }
139
- />
140
- <PreferenceToggleControl
141
- scope="core"
142
- featureName="showCollaborationNotifications"
143
- help={ __(
144
- 'Show notifications when collaborators join, leave, or save the post.'
145
- ) }
146
- label={ __(
147
- 'Show collaboration notifications'
148
- ) }
149
- />
150
- </>
129
+ <PreferenceToggleControl
130
+ scope="core"
131
+ featureName="showCollaborationCursor"
132
+ help={ __(
133
+ 'Show your own avatar inside blocks during collaborative editing sessions.'
134
+ ) }
135
+ label={ __( 'Show avatar in blocks' ) }
136
+ />
151
137
  ) }
152
138
  </PreferencesModalSection>
139
+ { showCollaborationOptions && (
140
+ <PreferencesModalSection
141
+ title={ __(
142
+ 'Collaboration notifications'
143
+ ) }
144
+ >
145
+ <PreferenceToggleControl
146
+ scope="core"
147
+ featureName="showCollaborationJoinNotifications"
148
+ help={ __(
149
+ 'Show notifications when collaborators join the post.'
150
+ ) }
151
+ label={ __( 'Collaborator joined' ) }
152
+ />
153
+ <PreferenceToggleControl
154
+ scope="core"
155
+ featureName="showCollaborationLeaveNotifications"
156
+ help={ __(
157
+ 'Show notifications when collaborators leave the post.'
158
+ ) }
159
+ label={ __( 'Collaborator left' ) }
160
+ />
161
+ <PreferenceToggleControl
162
+ scope="core"
163
+ featureName="showCollaborationPostSaveNotifications"
164
+ help={ __(
165
+ 'Show notifications when collaborators save, update, or publish the post.'
166
+ ) }
167
+ label={ __( 'Post updated' ) }
168
+ />
169
+ </PreferencesModalSection>
170
+ ) }
153
171
  <PreferencesModalSection
154
172
  title={ __( 'Document settings' ) }
155
173
  description={ __(
@@ -2,22 +2,84 @@
2
2
  * External dependencies
3
3
  */
4
4
  import { render, screen } from '@testing-library/react';
5
+ import userEvent from '@testing-library/user-event';
5
6
 
6
7
  /**
7
8
  * WordPress dependencies
8
9
  */
9
10
  import { useSelect } from '@wordpress/data';
11
+ import { useViewportMatch } from '@wordpress/compose';
12
+ import { store as preferencesStore } from '@wordpress/preferences';
13
+ import { store as interfaceStore } from '@wordpress/interface';
14
+ import { store as coreStore } from '@wordpress/core-data';
15
+ import { SlotFillProvider } from '@wordpress/components';
10
16
 
11
17
  /**
12
18
  * Internal dependencies
13
19
  */
14
20
  import EditPostPreferencesModal from '../';
21
+ import { store as editorStore } from '../../../store';
22
+ import { lock } from '../../../lock-unlock';
15
23
 
16
24
  // This allows us to tweak the returned value on each test.
17
25
  jest.mock( '@wordpress/data/src/components/use-select', () => jest.fn() );
18
26
  jest.mock( '@wordpress/compose/src/hooks/use-viewport-match', () => jest.fn() );
19
27
 
28
+ function setupActiveModal( preferences = {} ) {
29
+ const user = userEvent.setup();
30
+ const editorSelectors = {
31
+ getCurrentPostType: () => 'post',
32
+ getEditedPostAttribute: () => 'post',
33
+ isPublishSidebarEnabled: () => false,
34
+ };
35
+ lock( editorSelectors, {
36
+ getEditorSettings: () => ( {
37
+ richEditingEnabled: true,
38
+ } ),
39
+ isCollaborationEnabledForCurrentPost: () => true,
40
+ } );
41
+
42
+ useViewportMatch.mockReturnValue( true );
43
+ useSelect.mockImplementation( ( mapSelect ) =>
44
+ mapSelect( ( store ) => {
45
+ if ( store === interfaceStore ) {
46
+ return {
47
+ isModalActive: () => true,
48
+ };
49
+ }
50
+ if ( store === editorStore ) {
51
+ return editorSelectors;
52
+ }
53
+ if ( store === preferencesStore ) {
54
+ return {
55
+ get: ( scope, featureName ) => preferences[ featureName ],
56
+ };
57
+ }
58
+ if ( store === coreStore ) {
59
+ return {
60
+ getEntityRecords: () => [],
61
+ getPostType: () => ( { supports: {} } ),
62
+ getThemeSupports: () => ( {} ),
63
+ };
64
+ }
65
+ } )
66
+ );
67
+
68
+ render(
69
+ <SlotFillProvider>
70
+ <EditPostPreferencesModal />
71
+ </SlotFillProvider>
72
+ );
73
+
74
+ return user;
75
+ }
76
+
20
77
  describe( 'EditPostPreferencesModal', () => {
78
+ beforeEach( () => {
79
+ useSelect.mockReset();
80
+ useViewportMatch.mockReset();
81
+ } );
82
+
21
83
  it( 'should not render when the modal is not active', () => {
22
84
  useSelect.mockImplementation( () => false );
23
85
  render( <EditPostPreferencesModal /> );
@@ -25,4 +87,25 @@ describe( 'EditPostPreferencesModal', () => {
25
87
  screen.queryByRole( 'dialog', { name: 'Preferences' } )
26
88
  ).not.toBeInTheDocument();
27
89
  } );
90
+
91
+ it( 'shows collaboration notification controls', async () => {
92
+ const user = setupActiveModal();
93
+ await user.click( screen.getByRole( 'tab', { name: 'General' } ) );
94
+
95
+ expect(
96
+ await screen.findByRole( 'checkbox', {
97
+ name: 'Collaborator joined',
98
+ } )
99
+ ).toBeInTheDocument();
100
+ expect(
101
+ screen.getByRole( 'checkbox', {
102
+ name: 'Collaborator left',
103
+ } )
104
+ ).toBeInTheDocument();
105
+ expect(
106
+ screen.getByRole( 'checkbox', {
107
+ name: 'Post updated',
108
+ } )
109
+ ).toBeInTheDocument();
110
+ } );
28
111
  } );
@@ -133,7 +133,7 @@ export default function PreviewDropdown( { forceIsAutosaveable, disabled } ) {
133
133
  label: __( 'Tablet' ),
134
134
  icon: tablet,
135
135
  info: isResponsiveEditing
136
- ? __( 'Make tablet exclusive changes.' )
136
+ ? __( 'Make tablet exclusive style changes.' )
137
137
  : __( 'Preview tablet viewport.' ),
138
138
  },
139
139
  {
@@ -141,7 +141,7 @@ export default function PreviewDropdown( { forceIsAutosaveable, disabled } ) {
141
141
  label: __( 'Mobile' ),
142
142
  icon: mobile,
143
143
  info: isResponsiveEditing
144
- ? __( 'Make mobile exclusive changes.' )
144
+ ? __( 'Make mobile exclusive style changes.' )
145
145
  : __( 'Preview mobile viewport.' ),
146
146
  },
147
147
  ];
@@ -175,7 +175,7 @@ export default function PreviewDropdown( { forceIsAutosaveable, disabled } ) {
175
175
  role="menuitemcheckbox"
176
176
  onClick={ handleResponsiveEditingChange }
177
177
  info={ __(
178
- 'Edits apply only to the current state.'
178
+ 'Style changes apply only to the current viewport.'
179
179
  ) }
180
180
  >
181
181
  { __( 'Responsive editing' ) }
@@ -22,10 +22,11 @@ import { privateApis as mediaEditorPrivateApis } from '@wordpress/media-editor';
22
22
  /**
23
23
  * Internal dependencies
24
24
  */
25
- import inserterMediaCategories from '../media-categories';
25
+ import getInserterMediaCategories from '../media-categories';
26
26
  import { mediaUpload } from '../../utils';
27
27
  import mediaUploadOnSuccess from '../../utils/media-upload/on-success';
28
28
  import { default as mediaSideload } from '../../utils/media-sideload';
29
+ import { default as mediaSideloadFromUrl } from '../../utils/media-sideload-from-url';
29
30
  import { default as mediaFinalize } from '../../utils/media-finalize';
30
31
  import { default as mediaDelete } from '../../utils/media-delete';
31
32
  import { store as editorStore } from '../../store';
@@ -117,6 +118,7 @@ const {
117
118
  isNavigationOverlayContextKey,
118
119
  isNavigationPostEditorKey,
119
120
  mediaUploadOnSuccessKey,
121
+ mediaSideloadFromUrlKey,
120
122
  openMediaEditorModalKey,
121
123
  } = unlock( privateApis );
122
124
 
@@ -152,6 +154,8 @@ function useBlockEditorSettings( settings, postType, postId, renderingMode ) {
152
154
  deviceType,
153
155
  isNavigationOverlayContext,
154
156
  isRevisionsMode,
157
+ viewablePostTypeLabel,
158
+ currentPostId,
155
159
  } = useSelect(
156
160
  ( select ) => {
157
161
  const {
@@ -159,9 +163,12 @@ function useBlockEditorSettings( settings, postType, postId, renderingMode ) {
159
163
  getRawEntityRecord,
160
164
  getEntityRecord,
161
165
  getBlockPatternCategories,
166
+ getPostType,
162
167
  } = select( coreStore );
163
168
  const { get } = select( preferencesStore );
164
169
  const { getBlockTypes } = select( blocksStore );
170
+ const { getCurrentPostId, getCurrentPostType } =
171
+ select( editorStore );
165
172
  const { getDeviceType, isRevisionsMode: _isRevisionsMode } = unlock(
166
173
  select( editorStore )
167
174
  );
@@ -177,6 +184,19 @@ function useBlockEditorSettings( settings, postType, postId, renderingMode ) {
177
184
  // Fetch image sizes from REST API index for client-side media processing.
178
185
  const baseData = getEntityRecord( 'root', '__unstableBase' );
179
186
 
187
+ // The attached-images category follows the post being edited, not the
188
+ // root-level entity in `postType`/`postId`. With "Show template" on,
189
+ // the root becomes the template (wp_template), but media still attaches
190
+ // to the page being edited.
191
+ //
192
+ // Guard on a truthy slug: `getPostType()` with no slug resolves the
193
+ // whole `/wp/v2/types` collection rather than the single, already
194
+ // fetched record for the current type.
195
+ const currentPostType = getCurrentPostType();
196
+ const postTypeObject = currentPostType
197
+ ? getPostType( currentPostType )
198
+ : undefined;
199
+
180
200
  function getSectionRootBlock() {
181
201
  if ( renderingMode === 'template-locked' ) {
182
202
  return getBlocksByName( 'core/post-content' )?.[ 0 ] ?? '';
@@ -220,6 +240,14 @@ function useBlockEditorSettings( settings, postType, postId, renderingMode ) {
220
240
  } ),
221
241
  pageOnFront: siteSettings?.page_on_front,
222
242
  pageForPosts: siteSettings?.page_for_posts,
243
+ // The post type's singular name, but only for real, front-end
244
+ // rendered content (`viewable`). Empty for synced patterns,
245
+ // navigation and templates, which gates the attached-images
246
+ // category off for them and words its copy for everything else.
247
+ viewablePostTypeLabel: postTypeObject?.viewable
248
+ ? postTypeObject?.labels?.singular_name
249
+ : undefined,
250
+ currentPostId: getCurrentPostId(),
223
251
  restBlockPatternCategories: getBlockPatternCategories(),
224
252
  sectionRootClientId: getSectionRootBlock(),
225
253
  deviceType: getDeviceType(),
@@ -321,6 +349,15 @@ function useBlockEditorSettings( settings, postType, postId, renderingMode ) {
321
349
 
322
350
  const forceDisableFocusMode = settings.focusMode === false;
323
351
 
352
+ // The "Attachments" media category depends on the edited post and its post
353
+ // type label (which gates whether it's offered and words its copy), so the
354
+ // categories are derived rather than being a static list.
355
+ const inserterMediaCategories = useMemo(
356
+ () =>
357
+ getInserterMediaCategories( currentPostId, viewablePostTypeLabel ),
358
+ [ currentPostId, viewablePostTypeLabel ]
359
+ );
360
+
324
361
  return useMemo( () => {
325
362
  const blockEditorSettings = {
326
363
  ...Object.fromEntries(
@@ -355,6 +392,9 @@ function useBlockEditorSettings( settings, postType, postId, renderingMode ) {
355
392
  ? mediaUploadOnSuccess
356
393
  : undefined,
357
394
  mediaSideload: hasUploadPermissions ? mediaSideload : undefined,
395
+ [ mediaSideloadFromUrlKey ]: hasUploadPermissions
396
+ ? mediaSideloadFromUrl
397
+ : undefined,
358
398
  mediaFinalize: hasUploadPermissions ? mediaFinalize : undefined,
359
399
  mediaDelete: hasUploadPermissions ? mediaDelete : undefined,
360
400
  __experimentalBlockPatterns: blockPatterns,
@@ -435,6 +475,7 @@ function useBlockEditorSettings( settings, postType, postId, renderingMode ) {
435
475
  hasUploadPermissions,
436
476
  blockPatterns,
437
477
  blockPatternCategories,
478
+ inserterMediaCategories,
438
479
  canUseUnfilteredHTML,
439
480
  undo,
440
481
  createPageEntity,
@@ -13,6 +13,7 @@ import { useViewConfig } from '@wordpress/views';
13
13
  * Internal dependencies
14
14
  */
15
15
  import PostCardPanel from '../post-card-panel';
16
+ import PluginPostStatusInfo from '../plugin-post-status-info';
16
17
  import PostPanelSection from '../post-panel-section';
17
18
  import { store as editorStore } from '../../store';
18
19
  import PostTrash from '../post-trash';
@@ -394,7 +395,18 @@ export default function DataFormPostSummary( { onActionPerformed } ) {
394
395
  onChange={ onChange }
395
396
  />
396
397
  { ! isPostStatusRemoved && (
397
- <PostTrash onActionPerformed={ onActionPerformed } />
398
+ <>
399
+ <PluginPostStatusInfo.Slot>
400
+ { ( fills ) =>
401
+ fills.length > 0 && (
402
+ <Stack direction="column" gap="xs">
403
+ { fills }
404
+ </Stack>
405
+ )
406
+ }
407
+ </PluginPostStatusInfo.Slot>
408
+ <PostTrash onActionPerformed={ onActionPerformed } />
409
+ </>
398
410
  ) }
399
411
  </Stack>
400
412
  </PostPanelSection>
@@ -20,6 +20,7 @@ import PatternOverridesPanel from '../pattern-overrides-panel';
20
20
  import PluginDocumentSettingPanel from '../plugin-document-setting-panel';
21
21
  import PluginSidebar from '../plugin-sidebar';
22
22
  import PostSummary from './post-summary';
23
+ import DataFormPostSummary from './dataform-post-summary';
23
24
  import PostRevisionSummary from './post-revision-summary';
24
25
  import PostTaxonomiesPanel from '../post-taxonomies/panel';
25
26
  import PostTransformPanel from '../post-transform-panel';
@@ -32,11 +33,6 @@ import useAutoSwitchEditorSidebars from '../provider/use-auto-switch-editor-side
32
33
  import { sidebars } from './constants';
33
34
  import { unlock } from '../../lock-unlock';
34
35
  import { store as editorStore } from '../../store';
35
- import {
36
- NAVIGATION_POST_TYPE,
37
- TEMPLATE_PART_POST_TYPE,
38
- TEMPLATE_POST_TYPE,
39
- } from '../../store/constants';
40
36
 
41
37
  const { Tabs } = unlock( componentsPrivateApis );
42
38
 
@@ -47,7 +43,6 @@ const SidebarContent = ( {
47
43
  keyboardShortcut,
48
44
  onActionPerformed,
49
45
  extraPanels,
50
- postType,
51
46
  } ) => {
52
47
  const tabListRef = useRef( null );
53
48
  // Because `PluginSidebar` renders a `ComplementaryArea`, we
@@ -89,15 +84,20 @@ const SidebarContent = ( {
89
84
  if ( isRevisionsMode ) {
90
85
  tabContent = <PostRevisionSummary />;
91
86
  } else {
87
+ const isDataFormInspectorEnabled =
88
+ window?.__experimentalDataFormInspector;
92
89
  tabContent = (
93
90
  <>
94
- <PostSummary onActionPerformed={ onActionPerformed } />
91
+ { isDataFormInspectorEnabled ? (
92
+ <DataFormPostSummary
93
+ onActionPerformed={ onActionPerformed }
94
+ />
95
+ ) : (
96
+ <PostSummary onActionPerformed={ onActionPerformed } />
97
+ ) }
95
98
  <PluginDocumentSettingPanel.Slot />
96
99
  <TemplateContentPanel />
97
- { window?.__experimentalDataFormInspector &&
98
- [ 'page', 'post' ].includes( postType ) && (
99
- <TemplateActionsPanel />
100
- ) }
100
+ { isDataFormInspectorEnabled && <TemplateActionsPanel /> }
101
101
  <TemplatePartContentPanel />
102
102
  <PostTransformPanel />
103
103
  <PostTaxonomiesPanel />
@@ -144,42 +144,29 @@ const SidebarContent = ( {
144
144
 
145
145
  const Sidebar = ( { extraPanels, onActionPerformed } ) => {
146
146
  useAutoSwitchEditorSidebars();
147
- const { tabName, keyboardShortcut, showSummary, postType } = useSelect(
148
- ( select ) => {
149
- const shortcut = select(
150
- keyboardShortcutsStore
151
- ).getShortcutRepresentation( 'core/editor/toggle-sidebar' );
152
-
153
- const sidebar =
154
- select( interfaceStore ).getActiveComplementaryArea( 'core' );
155
- const _isEditorSidebarOpened = [
156
- sidebars.block,
157
- sidebars.document,
158
- ].includes( sidebar );
159
- let _tabName = sidebar;
160
- if ( ! _isEditorSidebarOpened ) {
161
- _tabName = !! select(
162
- blockEditorStore
163
- ).getBlockSelectionStart()
164
- ? sidebars.block
165
- : sidebars.document;
166
- }
147
+ const { tabName, keyboardShortcut } = useSelect( ( select ) => {
148
+ const shortcut = select(
149
+ keyboardShortcutsStore
150
+ ).getShortcutRepresentation( 'core/editor/toggle-sidebar' );
167
151
 
168
- const _postType = select( editorStore ).getCurrentPostType();
152
+ const sidebar =
153
+ select( interfaceStore ).getActiveComplementaryArea( 'core' );
154
+ const _isEditorSidebarOpened = [
155
+ sidebars.block,
156
+ sidebars.document,
157
+ ].includes( sidebar );
158
+ let _tabName = sidebar;
159
+ if ( ! _isEditorSidebarOpened ) {
160
+ _tabName = !! select( blockEditorStore ).getBlockSelectionStart()
161
+ ? sidebars.block
162
+ : sidebars.document;
163
+ }
169
164
 
170
- return {
171
- tabName: _tabName,
172
- keyboardShortcut: shortcut,
173
- showSummary: ! [
174
- TEMPLATE_POST_TYPE,
175
- TEMPLATE_PART_POST_TYPE,
176
- NAVIGATION_POST_TYPE,
177
- ].includes( _postType ),
178
- postType: _postType,
179
- };
180
- },
181
- []
182
- );
165
+ return {
166
+ tabName: _tabName,
167
+ keyboardShortcut: shortcut,
168
+ };
169
+ }, [] );
183
170
 
184
171
  const { enableComplementaryArea } = useDispatch( interfaceStore );
185
172
 
@@ -201,10 +188,8 @@ const Sidebar = ( { extraPanels, onActionPerformed } ) => {
201
188
  <SidebarContent
202
189
  tabName={ tabName }
203
190
  keyboardShortcut={ keyboardShortcut }
204
- showSummary={ showSummary }
205
191
  onActionPerformed={ onActionPerformed }
206
192
  extraPanels={ extraPanels }
207
- postType={ postType }
208
193
  />
209
194
  </Tabs>
210
195
  );
@@ -7,7 +7,6 @@ import { useSelect } from '@wordpress/data';
7
7
  /**
8
8
  * Internal dependencies
9
9
  */
10
- import DataFormPostSummary from './dataform-post-summary';
11
10
  import PluginPostStatusInfo from '../plugin-post-status-info';
12
11
  import PostAuthorPanel from '../post-author/panel';
13
12
  import PostCardPanel from '../post-card-panel';
@@ -37,22 +36,6 @@ import PostTrash from '../post-trash';
37
36
  const PANEL_NAME = 'post-status';
38
37
 
39
38
  export default function PostSummary( { onActionPerformed } ) {
40
- const postType = useSelect(
41
- ( select ) => select( editorStore ).getCurrentPostType(),
42
- []
43
- );
44
- if (
45
- window?.__experimentalDataFormInspector &&
46
- [ 'page', 'post', 'wp_template', 'wp_template_part' ].includes(
47
- postType
48
- )
49
- ) {
50
- return <DataFormPostSummary onActionPerformed={ onActionPerformed } />;
51
- }
52
- return <ClassicPostSummary onActionPerformed={ onActionPerformed } />;
53
- }
54
-
55
- function ClassicPostSummary( { onActionPerformed } ) {
56
39
  const { isRemovedPostStatusPanel, postType, postId } = useSelect(
57
40
  ( select ) => {
58
41
  // We use isEditorPanelRemoved to hide the panel if it was programmatically removed. We do
@@ -37,6 +37,8 @@ import {
37
37
  templateTitleField,
38
38
  pageTitleField,
39
39
  patternTitleField,
40
+ patternDescriptionField,
41
+ patternSyncStatusField,
40
42
  notesField,
41
43
  scheduledDateField,
42
44
  lastEditedDateField,
@@ -265,59 +267,59 @@ export const registerPostTypeSchema =
265
267
  if ( postType === ATTACHMENT_POST_TYPE ) {
266
268
  fields = ORDERED_MEDIA_FIELDS;
267
269
  } else {
270
+ const postTypeSlug = postTypeConfig.slug;
271
+ const isDesignPostType = DESIGN_POST_TYPES.includes( postTypeSlug );
272
+ const isPattern = postTypeSlug === 'wp_block';
273
+
268
274
  fields = [
269
275
  postTypeConfig.supports?.thumbnail &&
270
276
  currentTheme?.theme_supports?.[ 'post-thumbnails' ] &&
271
277
  featuredImageField,
272
- ! DESIGN_POST_TYPES.includes( postTypeConfig.slug ) &&
278
+ ! isDesignPostType &&
273
279
  postTypeConfig.supports?.author &&
274
280
  authorField,
275
- postTypeConfig.slug === 'wp_template' && templateAuthorField,
276
- postTypeConfig.slug === 'wp_template_part' &&
277
- templatePartAuthorField,
278
- ! DESIGN_POST_TYPES.includes( postTypeConfig.slug ) &&
279
- statusField,
280
- ! DESIGN_POST_TYPES.includes( postTypeConfig.slug ) &&
281
- dateField,
282
- ! DESIGN_POST_TYPES.includes( postTypeConfig.slug ) &&
283
- scheduledDateField,
281
+ postTypeSlug === 'wp_template' && templateAuthorField,
282
+ postTypeSlug === 'wp_template_part' && templatePartAuthorField,
283
+ ! isDesignPostType && statusField,
284
+ ! isDesignPostType && dateField,
285
+ ! isDesignPostType && scheduledDateField,
284
286
  lastEditedDateField,
285
- ! DESIGN_POST_TYPES.includes( postTypeConfig.slug ) &&
286
- slugField,
287
- ! DESIGN_POST_TYPES.includes( postTypeConfig.slug ) &&
287
+ ! isDesignPostType && slugField,
288
+ ! isDesignPostType &&
288
289
  postTypeConfig.supports?.excerpt &&
289
290
  excerptField,
291
+ isPattern &&
292
+ postTypeConfig.supports?.excerpt &&
293
+ patternDescriptionField,
290
294
  postTypeConfig.supports?.[ 'page-attributes' ] && parentField,
291
295
  postTypeConfig.supports?.comments && commentStatusField,
292
296
  postTypeConfig.supports?.trackbacks && pingStatusField,
293
297
  ( postTypeConfig.supports?.comments ||
294
298
  postTypeConfig.supports?.trackbacks ) &&
295
299
  discussionField,
296
- ! DESIGN_POST_TYPES.includes( postTypeConfig.slug ) &&
297
- templateField,
300
+ ! isDesignPostType && templateField,
298
301
  postTypeConfig.supports?.[ 'post-formats' ] &&
299
302
  ! disablePostFormats &&
300
303
  formatField,
301
- ! DESIGN_POST_TYPES.includes( postTypeConfig.slug ) &&
304
+ ( ! isDesignPostType || isPattern ) &&
302
305
  postTypeConfig.supports?.editor &&
303
306
  postContentInfoField,
304
- ! DESIGN_POST_TYPES.includes( postTypeConfig.slug ) &&
305
- passwordField,
306
- postTypeConfig.slug === 'post' && stickyField,
307
- postTypeConfig.slug === 'wp_template' && descriptionField,
308
- postTypeConfig.slug === 'wp_template' &&
309
- readOnlyDescriptionField,
307
+ ! isDesignPostType && passwordField,
308
+ postTypeSlug === 'post' && stickyField,
309
+ postTypeSlug === 'wp_template' && descriptionField,
310
+ postTypeSlug === 'wp_template' && readOnlyDescriptionField,
310
311
  // The `home`/`index` template summary exposes a few fields that
311
312
  // target other entities (`root/site` and the posts page).
312
313
  // `DataFormPostSummary` overrides them to read/write the right
313
314
  // entity and to control their visibility.
314
- postTypeConfig.slug === 'wp_template' && postsPageTitleField,
315
- postTypeConfig.slug === 'wp_template' && postsPerPageField,
316
- postTypeConfig.slug === 'wp_template' && siteDiscussionField,
315
+ postTypeSlug === 'wp_template' && postsPageTitleField,
316
+ postTypeSlug === 'wp_template' && postsPerPageField,
317
+ postTypeSlug === 'wp_template' && siteDiscussionField,
317
318
  postTypeConfig.supports?.editor &&
318
319
  postTypeConfig.viewable &&
319
320
  postPreviewField,
320
321
  hasEditorNotesSupport( postTypeConfig.supports ) && notesField,
322
+ isPattern && patternSyncStatusField,
321
323
  ].filter( Boolean );
322
324
  if ( postTypeConfig.supports?.title ) {
323
325
  let _titleField;
@@ -325,7 +327,9 @@ export const registerPostTypeSchema =
325
327
  _titleField = pageTitleField;
326
328
  } else if ( postType === 'wp_template' ) {
327
329
  _titleField = templateTitleField;
328
- } else if ( postType === 'wp_block' ) {
330
+ } else if (
331
+ [ 'wp_block', 'wp_template_part' ].includes( postType )
332
+ ) {
329
333
  _titleField = patternTitleField;
330
334
  } else {
331
335
  _titleField = titleField;
@@ -209,9 +209,13 @@ export const saveDirtyEntities =
209
209
  registry
210
210
  .dispatch( blockEditorStore )
211
211
  .__unstableMarkLastChangeAsPersistent();
212
+
212
213
  Promise.all( pendingSavedRecords )
213
- .then( ( values ) => {
214
- return onSave ? onSave( values ) : values;
214
+ .then( async ( values ) => {
215
+ if ( onSave ) {
216
+ await onSave();
217
+ }
218
+ return values;
215
219
  } )
216
220
  .then( ( values ) => {
217
221
  if (