@wordpress/editor 13.24.0 → 13.25.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.
- package/CHANGELOG.md +2 -0
- package/build/components/document-bar/index.js +152 -0
- package/build/components/document-bar/index.js.map +1 -0
- package/build/components/editor-canvas/edit-template-blocks-notification.js +106 -0
- package/build/components/editor-canvas/edit-template-blocks-notification.js.map +1 -0
- package/build/components/editor-canvas/index.js +292 -0
- package/build/components/editor-canvas/index.js.map +1 -0
- package/build/components/index.js +24 -8
- package/build/components/index.js.map +1 -1
- package/build/components/post-publish-button/index.js +1 -0
- package/build/components/post-publish-button/index.js.map +1 -1
- package/build/components/post-publish-panel/maybe-upload-media.js +2 -4
- package/build/components/post-publish-panel/maybe-upload-media.js.map +1 -1
- package/build/components/post-saved-state/index.js +1 -0
- package/build/components/post-saved-state/index.js.map +1 -1
- package/build/components/post-schedule/panel.js +1 -1
- package/build/components/post-schedule/panel.js.map +1 -1
- package/build/components/post-template/block-theme.js +99 -0
- package/build/components/post-template/block-theme.js.map +1 -0
- package/build/components/post-template/classic-theme.js +171 -0
- package/build/components/post-template/classic-theme.js.map +1 -0
- package/build/components/post-template/create-new-template-modal.js +98 -0
- package/build/components/post-template/create-new-template-modal.js.map +1 -0
- package/build/components/post-template/create-new-template.js +55 -0
- package/build/components/post-template/create-new-template.js.map +1 -0
- package/build/components/post-template/hooks.js +88 -0
- package/build/components/post-template/hooks.js.map +1 -0
- package/build/components/post-template/panel.js +71 -0
- package/build/components/post-template/panel.js.map +1 -0
- package/build/components/post-template/reset-default-template.js +48 -0
- package/build/components/post-template/reset-default-template.js.map +1 -0
- package/build/components/post-template/swap-template-button.js +84 -0
- package/build/components/post-template/swap-template-button.js.map +1 -0
- package/build/components/post-title/index.native.js +0 -1
- package/build/components/post-title/index.native.js.map +1 -1
- package/build/components/preview-dropdown/index.js +113 -0
- package/build/components/preview-dropdown/index.js.map +1 -0
- package/build/components/provider/index.js +36 -77
- package/build/components/provider/index.js.map +1 -1
- package/build/components/provider/index.native.js +17 -8
- package/build/components/provider/index.native.js.map +1 -1
- package/build/components/provider/navigation-block-editing-mode.js +40 -0
- package/build/components/provider/navigation-block-editing-mode.js.map +1 -0
- package/build/components/provider/use-block-editor-settings.js +9 -10
- package/build/components/provider/use-block-editor-settings.js.map +1 -1
- package/build/hooks/index.js +1 -0
- package/build/hooks/index.js.map +1 -1
- package/build/hooks/pattern-partial-syncing.js +49 -0
- package/build/hooks/pattern-partial-syncing.js.map +1 -0
- package/build/private-apis.js +4 -0
- package/build/private-apis.js.map +1 -1
- package/build/store/actions.js +59 -11
- package/build/store/actions.js.map +1 -1
- package/build/store/defaults.js +2 -1
- package/build/store/defaults.js.map +1 -1
- package/build/store/index.js +3 -0
- package/build/store/index.js.map +1 -1
- package/build/store/private-actions.js +52 -0
- package/build/store/private-actions.js.map +1 -0
- package/build/store/reducer.js +32 -27
- package/build/store/reducer.js.map +1 -1
- package/build/store/reducer.native.js +0 -1
- package/build/store/reducer.native.js.map +1 -1
- package/build/store/selectors.js +31 -10
- package/build/store/selectors.js.map +1 -1
- package/build-module/components/document-bar/index.js +144 -0
- package/build-module/components/document-bar/index.js.map +1 -0
- package/build-module/components/editor-canvas/edit-template-blocks-notification.js +100 -0
- package/build-module/components/editor-canvas/edit-template-blocks-notification.js.map +1 -0
- package/build-module/components/editor-canvas/index.js +283 -0
- package/build-module/components/editor-canvas/index.js.map +1 -0
- package/build-module/components/index.js +3 -1
- package/build-module/components/index.js.map +1 -1
- package/build-module/components/post-publish-button/index.js +1 -0
- package/build-module/components/post-publish-button/index.js.map +1 -1
- package/build-module/components/post-publish-panel/maybe-upload-media.js +2 -4
- package/build-module/components/post-publish-panel/maybe-upload-media.js.map +1 -1
- package/build-module/components/post-saved-state/index.js +1 -0
- package/build-module/components/post-saved-state/index.js.map +1 -1
- package/build-module/components/post-schedule/panel.js +1 -1
- package/build-module/components/post-schedule/panel.js.map +1 -1
- package/build-module/components/post-template/block-theme.js +91 -0
- package/build-module/components/post-template/block-theme.js.map +1 -0
- package/build-module/components/post-template/classic-theme.js +162 -0
- package/build-module/components/post-template/classic-theme.js.map +1 -0
- package/build-module/components/post-template/create-new-template-modal.js +91 -0
- package/build-module/components/post-template/create-new-template-modal.js.map +1 -0
- package/build-module/components/post-template/create-new-template.js +47 -0
- package/build-module/components/post-template/create-new-template.js.map +1 -0
- package/build-module/components/post-template/hooks.js +78 -0
- package/build-module/components/post-template/hooks.js.map +1 -0
- package/build-module/components/post-template/panel.js +63 -0
- package/build-module/components/post-template/panel.js.map +1 -0
- package/build-module/components/post-template/reset-default-template.js +41 -0
- package/build-module/components/post-template/reset-default-template.js.map +1 -0
- package/build-module/components/post-template/swap-template-button.js +77 -0
- package/build-module/components/post-template/swap-template-button.js.map +1 -0
- package/build-module/components/post-title/index.native.js +0 -1
- package/build-module/components/post-title/index.native.js.map +1 -1
- package/build-module/components/preview-dropdown/index.js +105 -0
- package/build-module/components/preview-dropdown/index.js.map +1 -0
- package/build-module/components/provider/index.js +37 -78
- package/build-module/components/provider/index.js.map +1 -1
- package/build-module/components/provider/index.native.js +18 -9
- package/build-module/components/provider/index.native.js.map +1 -1
- package/build-module/components/provider/navigation-block-editing-mode.js +34 -0
- package/build-module/components/provider/navigation-block-editing-mode.js.map +1 -0
- package/build-module/components/provider/use-block-editor-settings.js +9 -10
- package/build-module/components/provider/use-block-editor-settings.js.map +1 -1
- package/build-module/hooks/index.js +1 -0
- package/build-module/hooks/index.js.map +1 -1
- package/build-module/hooks/pattern-partial-syncing.js +46 -0
- package/build-module/hooks/pattern-partial-syncing.js.map +1 -0
- package/build-module/private-apis.js +4 -0
- package/build-module/private-apis.js.map +1 -1
- package/build-module/store/actions.js +53 -9
- package/build-module/store/actions.js.map +1 -1
- package/build-module/store/defaults.js +2 -1
- package/build-module/store/defaults.js.map +1 -1
- package/build-module/store/index.js +3 -0
- package/build-module/store/index.js.map +1 -1
- package/build-module/store/private-actions.js +44 -0
- package/build-module/store/private-actions.js.map +1 -0
- package/build-module/store/reducer.js +30 -26
- package/build-module/store/reducer.js.map +1 -1
- package/build-module/store/reducer.native.js +1 -2
- package/build-module/store/reducer.native.js.map +1 -1
- package/build-module/store/selectors.js +26 -6
- package/build-module/store/selectors.js.map +1 -1
- package/build-style/style-rtl.css +182 -0
- package/build-style/style.css +182 -0
- package/package.json +32 -31
- package/src/components/document-bar/index.js +182 -0
- package/src/components/document-bar/style.scss +130 -0
- package/src/components/editor-canvas/edit-template-blocks-notification.js +108 -0
- package/src/components/editor-canvas/index.js +381 -0
- package/src/components/index.js +3 -1
- package/src/components/post-publish-button/index.js +1 -0
- package/src/components/post-publish-panel/maybe-upload-media.js +3 -8
- package/src/components/post-saved-state/index.js +1 -0
- package/src/components/post-saved-state/test/__snapshots__/index.js.snap +2 -2
- package/src/components/post-schedule/panel.js +1 -1
- package/src/components/post-template/block-theme.js +109 -0
- package/src/components/post-template/classic-theme.js +213 -0
- package/src/components/post-template/create-new-template-modal.js +139 -0
- package/src/components/post-template/create-new-template.js +50 -0
- package/src/components/post-template/hooks.js +95 -0
- package/src/components/post-template/panel.js +67 -0
- package/src/components/post-template/reset-default-template.js +43 -0
- package/src/components/post-template/style.scss +52 -0
- package/src/components/post-template/swap-template-button.js +83 -0
- package/src/components/post-title/index.native.js +0 -1
- package/src/components/preview-dropdown/index.js +136 -0
- package/src/components/preview-dropdown/style.scss +5 -0
- package/src/components/provider/index.js +39 -112
- package/src/components/provider/index.native.js +26 -12
- package/src/components/provider/navigation-block-editing-mode.js +37 -0
- package/src/components/provider/use-block-editor-settings.js +6 -9
- package/src/hooks/index.js +1 -0
- package/src/hooks/pattern-partial-syncing.js +73 -0
- package/src/private-apis.js +4 -0
- package/src/store/actions.js +51 -9
- package/src/store/defaults.js +1 -0
- package/src/store/index.js +3 -0
- package/src/store/private-actions.js +61 -0
- package/src/store/reducer.js +32 -27
- package/src/store/reducer.native.js +0 -2
- package/src/store/selectors.js +64 -42
- package/src/store/test/selectors.js +88 -147
- package/src/style.scss +3 -0
- package/build/components/post-template/index.js +0 -66
- package/build/components/post-template/index.js.map +0 -1
- package/build-module/components/post-template/index.js +0 -57
- package/build-module/components/post-template/index.js.map +0 -1
- package/src/components/post-template/index.js +0 -64
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
import { SelectControl, Dropdown, Button, Notice } from '@wordpress/components';
|
|
6
|
+
import { useSelect, useDispatch } from '@wordpress/data';
|
|
7
|
+
import { store as coreStore } from '@wordpress/core-data';
|
|
8
|
+
import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from '@wordpress/block-editor';
|
|
9
|
+
import { useState, useMemo } from '@wordpress/element';
|
|
10
|
+
import { addTemplate } from '@wordpress/icons';
|
|
11
|
+
import { store as noticesStore } from '@wordpress/notices';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Internal dependencies
|
|
15
|
+
*/
|
|
16
|
+
import { store as editorStore } from '../../store';
|
|
17
|
+
import CreateNewTemplateModal from './create-new-template-modal';
|
|
18
|
+
import { useAllowSwitchingTemplates } from './hooks';
|
|
19
|
+
|
|
20
|
+
const POPOVER_PROPS = {
|
|
21
|
+
className: 'editor-post-template__dropdown',
|
|
22
|
+
placement: 'bottom-start',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
function PostTemplateToggle( { isOpen, onClick } ) {
|
|
26
|
+
const templateTitle = useSelect( ( select ) => {
|
|
27
|
+
const templateSlug =
|
|
28
|
+
select( editorStore ).getEditedPostAttribute( 'template' );
|
|
29
|
+
|
|
30
|
+
const { supportsTemplateMode, availableTemplates } =
|
|
31
|
+
select( editorStore ).getEditorSettings();
|
|
32
|
+
if ( ! supportsTemplateMode && availableTemplates[ templateSlug ] ) {
|
|
33
|
+
return availableTemplates[ templateSlug ];
|
|
34
|
+
}
|
|
35
|
+
const template =
|
|
36
|
+
select( coreStore ).canUser( 'create', 'templates' ) &&
|
|
37
|
+
select( editorStore ).getCurrentTemplateId();
|
|
38
|
+
return (
|
|
39
|
+
template?.title ||
|
|
40
|
+
template?.slug ||
|
|
41
|
+
availableTemplates?.[ templateSlug ]
|
|
42
|
+
);
|
|
43
|
+
}, [] );
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Button
|
|
47
|
+
className="edit-post-post-template__toggle"
|
|
48
|
+
variant="tertiary"
|
|
49
|
+
aria-expanded={ isOpen }
|
|
50
|
+
aria-label={ __( 'Template options' ) }
|
|
51
|
+
onClick={ onClick }
|
|
52
|
+
>
|
|
53
|
+
{ templateTitle ?? __( 'Default template' ) }
|
|
54
|
+
</Button>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function PostTemplateDropdownContent( { onClose } ) {
|
|
59
|
+
const allowSwitchingTemplate = useAllowSwitchingTemplates();
|
|
60
|
+
const {
|
|
61
|
+
availableTemplates,
|
|
62
|
+
fetchedTemplates,
|
|
63
|
+
selectedTemplateSlug,
|
|
64
|
+
canCreate,
|
|
65
|
+
canEdit,
|
|
66
|
+
} = useSelect(
|
|
67
|
+
( select ) => {
|
|
68
|
+
const { canUser, getEntityRecords } = select( coreStore );
|
|
69
|
+
const editorSettings = select( editorStore ).getEditorSettings();
|
|
70
|
+
const canCreateTemplates = canUser( 'create', 'templates' );
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
availableTemplates: editorSettings.availableTemplates,
|
|
74
|
+
fetchedTemplates: canCreateTemplates
|
|
75
|
+
? getEntityRecords( 'postType', 'wp_template', {
|
|
76
|
+
post_type:
|
|
77
|
+
select( editorStore ).getCurrentPostType(),
|
|
78
|
+
per_page: -1,
|
|
79
|
+
} )
|
|
80
|
+
: undefined,
|
|
81
|
+
selectedTemplateSlug:
|
|
82
|
+
select( editorStore ).getEditedPostAttribute( 'template' ),
|
|
83
|
+
canCreate:
|
|
84
|
+
allowSwitchingTemplate &&
|
|
85
|
+
canCreateTemplates &&
|
|
86
|
+
editorSettings.supportsTemplateMode,
|
|
87
|
+
canEdit:
|
|
88
|
+
allowSwitchingTemplate &&
|
|
89
|
+
canCreateTemplates &&
|
|
90
|
+
editorSettings.supportsTemplateMode &&
|
|
91
|
+
!! select( editorStore ).getCurrentTemplateId(),
|
|
92
|
+
};
|
|
93
|
+
},
|
|
94
|
+
[ allowSwitchingTemplate ]
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const options = useMemo(
|
|
98
|
+
() =>
|
|
99
|
+
Object.entries( {
|
|
100
|
+
...availableTemplates,
|
|
101
|
+
...Object.fromEntries(
|
|
102
|
+
( fetchedTemplates ?? [] ).map( ( { slug, title } ) => [
|
|
103
|
+
slug,
|
|
104
|
+
title.rendered,
|
|
105
|
+
] )
|
|
106
|
+
),
|
|
107
|
+
} ).map( ( [ slug, title ] ) => ( { value: slug, label: title } ) ),
|
|
108
|
+
[ availableTemplates, fetchedTemplates ]
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const selectedOption =
|
|
112
|
+
options.find( ( option ) => option.value === selectedTemplateSlug ) ??
|
|
113
|
+
options.find( ( option ) => ! option.value ); // The default option has '' value.
|
|
114
|
+
|
|
115
|
+
const { editPost } = useDispatch( editorStore );
|
|
116
|
+
const { getEditorSettings } = useSelect( editorStore );
|
|
117
|
+
const { createSuccessNotice } = useDispatch( noticesStore );
|
|
118
|
+
const { setRenderingMode } = useDispatch( editorStore );
|
|
119
|
+
const [ isCreateModalOpen, setIsCreateModalOpen ] = useState( false );
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<div className="editor-post-template__classic-theme-dropdown">
|
|
123
|
+
<InspectorPopoverHeader
|
|
124
|
+
title={ __( 'Template' ) }
|
|
125
|
+
help={ __(
|
|
126
|
+
'Templates define the way content is displayed when viewing your site.'
|
|
127
|
+
) }
|
|
128
|
+
actions={
|
|
129
|
+
canCreate
|
|
130
|
+
? [
|
|
131
|
+
{
|
|
132
|
+
icon: addTemplate,
|
|
133
|
+
label: __( 'Add template' ),
|
|
134
|
+
onClick: () => setIsCreateModalOpen( true ),
|
|
135
|
+
},
|
|
136
|
+
]
|
|
137
|
+
: []
|
|
138
|
+
}
|
|
139
|
+
onClose={ onClose }
|
|
140
|
+
/>
|
|
141
|
+
{ ! allowSwitchingTemplate ? (
|
|
142
|
+
<Notice status="warning" isDismissible={ false }>
|
|
143
|
+
{ __( 'The posts page template cannot be changed.' ) }
|
|
144
|
+
</Notice>
|
|
145
|
+
) : (
|
|
146
|
+
<SelectControl
|
|
147
|
+
__next40pxDefaultSize
|
|
148
|
+
__nextHasNoMarginBottom
|
|
149
|
+
hideLabelFromVision
|
|
150
|
+
label={ __( 'Template' ) }
|
|
151
|
+
value={ selectedOption?.value ?? '' }
|
|
152
|
+
options={ options }
|
|
153
|
+
onChange={ ( slug ) =>
|
|
154
|
+
editPost( { template: slug || '' } )
|
|
155
|
+
}
|
|
156
|
+
/>
|
|
157
|
+
) }
|
|
158
|
+
{ canEdit && (
|
|
159
|
+
<p>
|
|
160
|
+
<Button
|
|
161
|
+
variant="link"
|
|
162
|
+
onClick={ () => {
|
|
163
|
+
setRenderingMode( 'template-only' );
|
|
164
|
+
onClose();
|
|
165
|
+
createSuccessNotice(
|
|
166
|
+
__(
|
|
167
|
+
'Editing template. Changes made here affect all posts and pages that use the template.'
|
|
168
|
+
),
|
|
169
|
+
{
|
|
170
|
+
type: 'snackbar',
|
|
171
|
+
actions: [
|
|
172
|
+
{
|
|
173
|
+
label: __( 'Go back' ),
|
|
174
|
+
onClick: () =>
|
|
175
|
+
setRenderingMode(
|
|
176
|
+
getEditorSettings()
|
|
177
|
+
.defaultRenderingMode
|
|
178
|
+
),
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
} }
|
|
184
|
+
>
|
|
185
|
+
{ __( 'Edit template' ) }
|
|
186
|
+
</Button>
|
|
187
|
+
</p>
|
|
188
|
+
) }
|
|
189
|
+
{ isCreateModalOpen && (
|
|
190
|
+
<CreateNewTemplateModal
|
|
191
|
+
onClose={ () => setIsCreateModalOpen( false ) }
|
|
192
|
+
/>
|
|
193
|
+
) }
|
|
194
|
+
</div>
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function ClassicThemeControl() {
|
|
199
|
+
return (
|
|
200
|
+
<Dropdown
|
|
201
|
+
popoverProps={ POPOVER_PROPS }
|
|
202
|
+
focusOnMount
|
|
203
|
+
renderToggle={ ( { isOpen, onToggle } ) => (
|
|
204
|
+
<PostTemplateToggle isOpen={ isOpen } onClick={ onToggle } />
|
|
205
|
+
) }
|
|
206
|
+
renderContent={ ( { onClose } ) => (
|
|
207
|
+
<PostTemplateDropdownContent onClose={ onClose } />
|
|
208
|
+
) }
|
|
209
|
+
/>
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export default ClassicThemeControl;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useSelect, useDispatch } from '@wordpress/data';
|
|
5
|
+
import { useState } from '@wordpress/element';
|
|
6
|
+
import { serialize, createBlock } from '@wordpress/blocks';
|
|
7
|
+
import {
|
|
8
|
+
Modal,
|
|
9
|
+
TextControl,
|
|
10
|
+
Button,
|
|
11
|
+
__experimentalHStack as HStack,
|
|
12
|
+
__experimentalVStack as VStack,
|
|
13
|
+
} from '@wordpress/components';
|
|
14
|
+
import { __ } from '@wordpress/i18n';
|
|
15
|
+
import { cleanForSlug } from '@wordpress/url';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Internal dependencies
|
|
19
|
+
*/
|
|
20
|
+
import { unlock } from '../../lock-unlock';
|
|
21
|
+
import { store as editorStore } from '../../store';
|
|
22
|
+
|
|
23
|
+
const DEFAULT_TITLE = __( 'Custom Template' );
|
|
24
|
+
|
|
25
|
+
export default function CreateNewTemplateModal( { onClose } ) {
|
|
26
|
+
const defaultBlockTemplate = useSelect(
|
|
27
|
+
( select ) =>
|
|
28
|
+
select( editorStore ).getEditorSettings().defaultBlockTemplate,
|
|
29
|
+
[]
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const { createTemplate, setRenderingMode } = unlock(
|
|
33
|
+
useDispatch( editorStore )
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const [ title, setTitle ] = useState( '' );
|
|
37
|
+
|
|
38
|
+
const [ isBusy, setIsBusy ] = useState( false );
|
|
39
|
+
|
|
40
|
+
const cancel = () => {
|
|
41
|
+
setTitle( '' );
|
|
42
|
+
onClose();
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const submit = async ( event ) => {
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
|
|
48
|
+
if ( isBusy ) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
setIsBusy( true );
|
|
53
|
+
|
|
54
|
+
const newTemplateContent =
|
|
55
|
+
defaultBlockTemplate ??
|
|
56
|
+
serialize( [
|
|
57
|
+
createBlock(
|
|
58
|
+
'core/group',
|
|
59
|
+
{
|
|
60
|
+
tagName: 'header',
|
|
61
|
+
layout: { inherit: true },
|
|
62
|
+
},
|
|
63
|
+
[
|
|
64
|
+
createBlock( 'core/site-title' ),
|
|
65
|
+
createBlock( 'core/site-tagline' ),
|
|
66
|
+
]
|
|
67
|
+
),
|
|
68
|
+
createBlock( 'core/separator' ),
|
|
69
|
+
createBlock(
|
|
70
|
+
'core/group',
|
|
71
|
+
{
|
|
72
|
+
tagName: 'main',
|
|
73
|
+
},
|
|
74
|
+
[
|
|
75
|
+
createBlock(
|
|
76
|
+
'core/group',
|
|
77
|
+
{
|
|
78
|
+
layout: { inherit: true },
|
|
79
|
+
},
|
|
80
|
+
[ createBlock( 'core/post-title' ) ]
|
|
81
|
+
),
|
|
82
|
+
createBlock( 'core/post-content', {
|
|
83
|
+
layout: { inherit: true },
|
|
84
|
+
} ),
|
|
85
|
+
]
|
|
86
|
+
),
|
|
87
|
+
] );
|
|
88
|
+
|
|
89
|
+
await createTemplate( {
|
|
90
|
+
slug: cleanForSlug( title || DEFAULT_TITLE ),
|
|
91
|
+
content: newTemplateContent,
|
|
92
|
+
title: title || DEFAULT_TITLE,
|
|
93
|
+
} );
|
|
94
|
+
|
|
95
|
+
setIsBusy( false );
|
|
96
|
+
cancel();
|
|
97
|
+
setRenderingMode( 'template-only' );
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<Modal
|
|
102
|
+
title={ __( 'Create custom template' ) }
|
|
103
|
+
onRequestClose={ cancel }
|
|
104
|
+
>
|
|
105
|
+
<form
|
|
106
|
+
className="editor-post-template__create-form"
|
|
107
|
+
onSubmit={ submit }
|
|
108
|
+
>
|
|
109
|
+
<VStack spacing="3">
|
|
110
|
+
<TextControl
|
|
111
|
+
__nextHasNoMarginBottom
|
|
112
|
+
label={ __( 'Name' ) }
|
|
113
|
+
value={ title }
|
|
114
|
+
onChange={ setTitle }
|
|
115
|
+
placeholder={ DEFAULT_TITLE }
|
|
116
|
+
disabled={ isBusy }
|
|
117
|
+
help={ __(
|
|
118
|
+
'Describe the template, e.g. "Post with sidebar". A custom template can be manually applied to any post or page.'
|
|
119
|
+
) }
|
|
120
|
+
/>
|
|
121
|
+
<HStack justify="right">
|
|
122
|
+
<Button variant="tertiary" onClick={ cancel }>
|
|
123
|
+
{ __( 'Cancel' ) }
|
|
124
|
+
</Button>
|
|
125
|
+
|
|
126
|
+
<Button
|
|
127
|
+
variant="primary"
|
|
128
|
+
type="submit"
|
|
129
|
+
isBusy={ isBusy }
|
|
130
|
+
aria-disabled={ isBusy }
|
|
131
|
+
>
|
|
132
|
+
{ __( 'Create' ) }
|
|
133
|
+
</Button>
|
|
134
|
+
</HStack>
|
|
135
|
+
</VStack>
|
|
136
|
+
</form>
|
|
137
|
+
</Modal>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { MenuItem } from '@wordpress/components';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
import { useSelect } from '@wordpress/data';
|
|
7
|
+
import { store as coreStore } from '@wordpress/core-data';
|
|
8
|
+
import { useState } from '@wordpress/element';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Internal dependencies
|
|
12
|
+
*/
|
|
13
|
+
import CreateNewTemplateModal from './create-new-template-modal';
|
|
14
|
+
import { useAllowSwitchingTemplates } from './hooks';
|
|
15
|
+
|
|
16
|
+
export default function CreateNewTemplate( { onClick } ) {
|
|
17
|
+
const { canCreateTemplates } = useSelect( ( select ) => {
|
|
18
|
+
const { canUser } = select( coreStore );
|
|
19
|
+
return {
|
|
20
|
+
canCreateTemplates: canUser( 'create', 'templates' ),
|
|
21
|
+
};
|
|
22
|
+
}, [] );
|
|
23
|
+
const [ isCreateModalOpen, setIsCreateModalOpen ] = useState( false );
|
|
24
|
+
const allowSwitchingTemplate = useAllowSwitchingTemplates();
|
|
25
|
+
|
|
26
|
+
// The default template in a post is indicated by an empty string.
|
|
27
|
+
if ( ! canCreateTemplates || ! allowSwitchingTemplate ) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
return (
|
|
31
|
+
<>
|
|
32
|
+
<MenuItem
|
|
33
|
+
onClick={ () => {
|
|
34
|
+
setIsCreateModalOpen( true );
|
|
35
|
+
} }
|
|
36
|
+
>
|
|
37
|
+
{ __( 'Create new template' ) }
|
|
38
|
+
</MenuItem>
|
|
39
|
+
|
|
40
|
+
{ isCreateModalOpen && (
|
|
41
|
+
<CreateNewTemplateModal
|
|
42
|
+
onClose={ () => {
|
|
43
|
+
setIsCreateModalOpen( false );
|
|
44
|
+
onClick();
|
|
45
|
+
} }
|
|
46
|
+
/>
|
|
47
|
+
) }
|
|
48
|
+
</>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useSelect } from '@wordpress/data';
|
|
5
|
+
import { useMemo } from '@wordpress/element';
|
|
6
|
+
import { store as coreStore } from '@wordpress/core-data';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Internal dependencies
|
|
10
|
+
*/
|
|
11
|
+
import { store as editorStore } from '../../store';
|
|
12
|
+
|
|
13
|
+
export function useEditedPostContext() {
|
|
14
|
+
return useSelect( ( select ) => {
|
|
15
|
+
const { getCurrentPostId, getCurrentPostType } = select( editorStore );
|
|
16
|
+
return {
|
|
17
|
+
postId: getCurrentPostId(),
|
|
18
|
+
postType: getCurrentPostType(),
|
|
19
|
+
};
|
|
20
|
+
}, [] );
|
|
21
|
+
}
|
|
22
|
+
export function useAllowSwitchingTemplates() {
|
|
23
|
+
const { postType, postId } = useEditedPostContext();
|
|
24
|
+
return useSelect(
|
|
25
|
+
( select ) => {
|
|
26
|
+
const { getEntityRecord, getEntityRecords } = select( coreStore );
|
|
27
|
+
const siteSettings = getEntityRecord( 'root', 'site' );
|
|
28
|
+
const templates = getEntityRecords( 'postType', 'wp_template', {
|
|
29
|
+
per_page: -1,
|
|
30
|
+
} );
|
|
31
|
+
const isPostsPage = +postId === siteSettings?.page_for_posts;
|
|
32
|
+
// If current page is set front page or posts page, we also need
|
|
33
|
+
// to check if the current theme has a template for it. If not
|
|
34
|
+
const isFrontPage =
|
|
35
|
+
postType === 'page' &&
|
|
36
|
+
+postId === siteSettings?.page_on_front &&
|
|
37
|
+
templates?.some( ( { slug } ) => slug === 'front-page' );
|
|
38
|
+
return ! isPostsPage && ! isFrontPage;
|
|
39
|
+
},
|
|
40
|
+
[ postId, postType ]
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function useTemplates() {
|
|
45
|
+
return useSelect(
|
|
46
|
+
( select ) =>
|
|
47
|
+
select( coreStore ).getEntityRecords( 'postType', 'wp_template', {
|
|
48
|
+
per_page: -1,
|
|
49
|
+
post_type: 'page',
|
|
50
|
+
} ),
|
|
51
|
+
[]
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function useAvailableTemplates() {
|
|
56
|
+
const currentTemplateSlug = useCurrentTemplateSlug();
|
|
57
|
+
const allowSwitchingTemplate = useAllowSwitchingTemplates();
|
|
58
|
+
const templates = useTemplates();
|
|
59
|
+
return useMemo(
|
|
60
|
+
() =>
|
|
61
|
+
allowSwitchingTemplate &&
|
|
62
|
+
templates?.filter(
|
|
63
|
+
( template ) =>
|
|
64
|
+
template.is_custom &&
|
|
65
|
+
template.slug !== currentTemplateSlug &&
|
|
66
|
+
!! template.content.raw // Skip empty templates.
|
|
67
|
+
),
|
|
68
|
+
[ templates, currentTemplateSlug, allowSwitchingTemplate ]
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function useCurrentTemplateSlug() {
|
|
73
|
+
const { postType, postId } = useEditedPostContext();
|
|
74
|
+
const templates = useTemplates();
|
|
75
|
+
const entityTemplate = useSelect(
|
|
76
|
+
( select ) => {
|
|
77
|
+
const post = select( coreStore ).getEditedEntityRecord(
|
|
78
|
+
'postType',
|
|
79
|
+
postType,
|
|
80
|
+
postId
|
|
81
|
+
);
|
|
82
|
+
return post?.template;
|
|
83
|
+
},
|
|
84
|
+
[ postType, postId ]
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
if ( ! entityTemplate ) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
// If a page has a `template` set and is not included in the list
|
|
91
|
+
// of the theme's templates, do not return it, in order to resolve
|
|
92
|
+
// to the current theme's default template.
|
|
93
|
+
return templates?.find( ( template ) => template.slug === entityTemplate )
|
|
94
|
+
?.slug;
|
|
95
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useSelect } from '@wordpress/data';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
import { store as coreStore } from '@wordpress/core-data';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Internal dependencies
|
|
10
|
+
*/
|
|
11
|
+
import { store as editorStore } from '../../store';
|
|
12
|
+
import ClassicThemeControl from './classic-theme';
|
|
13
|
+
import BlockThemeControl from './block-theme';
|
|
14
|
+
import PostPanelRow from '../post-panel-row';
|
|
15
|
+
|
|
16
|
+
export default function PostTemplatePanel() {
|
|
17
|
+
const { templateId, isBlockTheme } = useSelect( ( select ) => {
|
|
18
|
+
const { getCurrentTemplateId, getEditorSettings } =
|
|
19
|
+
select( editorStore );
|
|
20
|
+
return {
|
|
21
|
+
templateId: getCurrentTemplateId(),
|
|
22
|
+
isBlockTheme: getEditorSettings().__unstableIsBlockBasedTheme,
|
|
23
|
+
};
|
|
24
|
+
}, [] );
|
|
25
|
+
|
|
26
|
+
const isVisible = true;
|
|
27
|
+
useSelect( ( select ) => {
|
|
28
|
+
const postTypeSlug = select( editorStore ).getCurrentPostType();
|
|
29
|
+
const postType = select( coreStore ).getPostType( postTypeSlug );
|
|
30
|
+
if ( ! postType?.viewable ) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const settings = select( editorStore ).getEditorSettings();
|
|
35
|
+
const hasTemplates =
|
|
36
|
+
!! settings.availableTemplates &&
|
|
37
|
+
Object.keys( settings.availableTemplates ).length > 0;
|
|
38
|
+
if ( hasTemplates ) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if ( ! settings.supportsTemplateMode ) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const canCreateTemplates =
|
|
47
|
+
select( coreStore ).canUser( 'create', 'templates' ) ?? false;
|
|
48
|
+
return canCreateTemplates;
|
|
49
|
+
}, [] );
|
|
50
|
+
|
|
51
|
+
if ( ! isBlockTheme && isVisible ) {
|
|
52
|
+
return (
|
|
53
|
+
<PostPanelRow label={ __( 'Template' ) }>
|
|
54
|
+
<ClassicThemeControl />
|
|
55
|
+
</PostPanelRow>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if ( isBlockTheme && !! templateId ) {
|
|
60
|
+
return (
|
|
61
|
+
<PostPanelRow label={ __( 'Template' ) }>
|
|
62
|
+
<BlockThemeControl id={ templateId } />
|
|
63
|
+
</PostPanelRow>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { MenuItem } from '@wordpress/components';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
import { useDispatch } from '@wordpress/data';
|
|
7
|
+
import { store as coreStore } from '@wordpress/core-data';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Internal dependencies
|
|
11
|
+
*/
|
|
12
|
+
import {
|
|
13
|
+
useAllowSwitchingTemplates,
|
|
14
|
+
useCurrentTemplateSlug,
|
|
15
|
+
useEditedPostContext,
|
|
16
|
+
} from './hooks';
|
|
17
|
+
|
|
18
|
+
export default function ResetDefaultTemplate( { onClick } ) {
|
|
19
|
+
const currentTemplateSlug = useCurrentTemplateSlug();
|
|
20
|
+
const allowSwitchingTemplate = useAllowSwitchingTemplates();
|
|
21
|
+
const { postType, postId } = useEditedPostContext();
|
|
22
|
+
const { editEntityRecord } = useDispatch( coreStore );
|
|
23
|
+
// The default template in a post is indicated by an empty string.
|
|
24
|
+
if ( ! currentTemplateSlug || ! allowSwitchingTemplate ) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return (
|
|
28
|
+
<MenuItem
|
|
29
|
+
onClick={ () => {
|
|
30
|
+
editEntityRecord(
|
|
31
|
+
'postType',
|
|
32
|
+
postType,
|
|
33
|
+
postId,
|
|
34
|
+
{ template: '' },
|
|
35
|
+
{ undoIgnore: true }
|
|
36
|
+
);
|
|
37
|
+
onClick();
|
|
38
|
+
} }
|
|
39
|
+
>
|
|
40
|
+
{ __( 'Use default template' ) }
|
|
41
|
+
</MenuItem>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
.editor-post-template__swap-template-modal {
|
|
2
|
+
z-index: z-index(".editor-post-template__swap-template-modal");
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.editor-post-template__swap-template-modal-content .block-editor-block-patterns-list {
|
|
6
|
+
column-count: 2;
|
|
7
|
+
column-gap: $grid-unit-30;
|
|
8
|
+
|
|
9
|
+
// Small top padding required to avoid cutting off the visible outline when hovering items
|
|
10
|
+
padding-top: $border-width-focus-fallback;
|
|
11
|
+
|
|
12
|
+
@include break-medium() {
|
|
13
|
+
column-count: 3;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@include break-wide() {
|
|
17
|
+
column-count: 4;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.block-editor-block-patterns-list__list-item {
|
|
21
|
+
break-inside: avoid-column;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.block-editor-block-patterns-list__item {
|
|
25
|
+
// Avoid to override the BlockPatternList component
|
|
26
|
+
// default hover and focus styles.
|
|
27
|
+
&:not(:focus):not(:hover) .block-editor-block-preview__container {
|
|
28
|
+
box-shadow: 0 0 0 1px $gray-300;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.editor-post-template__dropdown {
|
|
34
|
+
.components-popover__content {
|
|
35
|
+
min-width: 240px;
|
|
36
|
+
}
|
|
37
|
+
.components-button.is-pressed,
|
|
38
|
+
.components-button.is-pressed:hover {
|
|
39
|
+
background: inherit;
|
|
40
|
+
color: inherit;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.editor-post-template__create-form {
|
|
45
|
+
@include break-medium() {
|
|
46
|
+
width: $grid-unit * 40;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.editor-post-template__classic-theme-dropdown {
|
|
51
|
+
padding: $grid-unit-10;
|
|
52
|
+
}
|