@wordpress/edit-site 4.9.0 → 4.12.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 +6 -0
- package/build/components/add-new-template/add-custom-generic-template-modal.js +84 -0
- package/build/components/add-new-template/add-custom-generic-template-modal.js.map +1 -0
- package/build/components/add-new-template/add-custom-template-modal.js +82 -61
- package/build/components/add-new-template/add-custom-template-modal.js.map +1 -1
- package/build/components/add-new-template/new-template.js +94 -81
- package/build/components/add-new-template/new-template.js.map +1 -1
- package/build/components/add-new-template/utils.js +574 -57
- package/build/components/add-new-template/utils.js.map +1 -1
- package/build/components/block-editor/index.js +1 -3
- package/build/components/block-editor/index.js.map +1 -1
- package/build/components/code-editor/index.js +17 -4
- package/build/components/code-editor/index.js.map +1 -1
- package/build/components/editor/index.js +16 -0
- package/build/components/editor/index.js.map +1 -1
- package/build/components/error-boundary/index.js +6 -0
- package/build/components/error-boundary/index.js.map +1 -1
- package/build/components/global-styles/dimensions-panel.js +191 -21
- package/build/components/global-styles/dimensions-panel.js.map +1 -1
- package/build/components/global-styles/global-styles-provider.js +4 -2
- package/build/components/global-styles/global-styles-provider.js.map +1 -1
- package/build/components/global-styles/hooks.js +11 -2
- package/build/components/global-styles/hooks.js.map +1 -1
- package/build/components/global-styles/screen-color-palette.js +13 -17
- package/build/components/global-styles/screen-color-palette.js.map +1 -1
- package/build/components/global-styles/screen-colors.js +59 -7
- package/build/components/global-styles/screen-colors.js.map +1 -1
- package/build/components/global-styles/screen-heading-color.js +157 -0
- package/build/components/global-styles/screen-heading-color.js.map +1 -0
- package/build/components/global-styles/screen-link-color.js +48 -14
- package/build/components/global-styles/screen-link-color.js.map +1 -1
- package/build/components/global-styles/screen-typography-element.js +4 -0
- package/build/components/global-styles/screen-typography-element.js.map +1 -1
- package/build/components/global-styles/screen-typography.js +5 -0
- package/build/components/global-styles/screen-typography.js.map +1 -1
- package/build/components/global-styles/typography-panel.js +73 -12
- package/build/components/global-styles/typography-panel.js.map +1 -1
- package/build/components/global-styles/typography-utils.js +217 -0
- package/build/components/global-styles/typography-utils.js.map +1 -0
- package/build/components/global-styles/ui.js +11 -0
- package/build/components/global-styles/ui.js.map +1 -1
- package/build/components/global-styles/use-global-styles-output.js +298 -61
- package/build/components/global-styles/use-global-styles-output.js.map +1 -1
- package/build/components/global-styles/utils.js +49 -3
- package/build/components/global-styles/utils.js.map +1 -1
- package/build/components/header/index.js +22 -10
- package/build/components/header/index.js.map +1 -1
- package/build/components/header/undo-redo/redo.js +2 -1
- package/build/components/header/undo-redo/redo.js.map +1 -1
- package/build/components/keyboard-shortcut-help-modal/index.js +1 -3
- package/build/components/keyboard-shortcut-help-modal/index.js.map +1 -1
- package/build/components/list/actions/index.js +1 -1
- package/build/components/list/actions/index.js.map +1 -1
- package/build/components/save-button/index.js +2 -3
- package/build/components/save-button/index.js.map +1 -1
- package/build/components/sidebar/navigation-menu-sidebar/navigation-menu.js +2 -2
- package/build/components/sidebar/navigation-menu-sidebar/navigation-menu.js.map +1 -1
- package/build/components/sidebar/template-card/template-actions.js +1 -1
- package/build/components/sidebar/template-card/template-actions.js.map +1 -1
- package/build/components/template-details/edit-template-title.js +11 -3
- package/build/components/template-details/edit-template-title.js.map +1 -1
- package/build/components/template-details/index.js +2 -21
- package/build/components/template-details/index.js.map +1 -1
- package/build/components/template-details/template-areas.js +1 -1
- package/build/components/template-details/template-areas.js.map +1 -1
- package/build/components/template-part-converter/convert-to-template-part.js +4 -1
- package/build/components/template-part-converter/convert-to-template-part.js.map +1 -1
- package/build/hooks/index.js +2 -0
- package/build/hooks/index.js.map +1 -1
- package/build/hooks/template-part-edit.js +86 -0
- package/build/hooks/template-part-edit.js.map +1 -0
- package/build/store/selectors.js +4 -1
- package/build/store/selectors.js.map +1 -1
- package/build-module/components/add-new-template/add-custom-generic-template-modal.js +77 -0
- package/build-module/components/add-new-template/add-custom-generic-template-modal.js.map +1 -0
- package/build-module/components/add-new-template/add-custom-template-modal.js +82 -61
- package/build-module/components/add-new-template/add-custom-template-modal.js.map +1 -1
- package/build-module/components/add-new-template/new-template.js +96 -84
- package/build-module/components/add-new-template/new-template.js.map +1 -1
- package/build-module/components/add-new-template/utils.js +555 -50
- package/build-module/components/add-new-template/utils.js.map +1 -1
- package/build-module/components/block-editor/index.js +1 -2
- package/build-module/components/block-editor/index.js.map +1 -1
- package/build-module/components/code-editor/index.js +18 -5
- package/build-module/components/code-editor/index.js.map +1 -1
- package/build-module/components/editor/index.js +16 -0
- package/build-module/components/editor/index.js.map +1 -1
- package/build-module/components/error-boundary/index.js +5 -0
- package/build-module/components/error-boundary/index.js.map +1 -1
- package/build-module/components/global-styles/dimensions-panel.js +191 -22
- package/build-module/components/global-styles/dimensions-panel.js.map +1 -1
- package/build-module/components/global-styles/global-styles-provider.js +4 -2
- package/build-module/components/global-styles/global-styles-provider.js.map +1 -1
- package/build-module/components/global-styles/hooks.js +11 -2
- package/build-module/components/global-styles/hooks.js.map +1 -1
- package/build-module/components/global-styles/screen-color-palette.js +14 -19
- package/build-module/components/global-styles/screen-color-palette.js.map +1 -1
- package/build-module/components/global-styles/screen-colors.js +59 -7
- package/build-module/components/global-styles/screen-colors.js.map +1 -1
- package/build-module/components/global-styles/screen-heading-color.js +143 -0
- package/build-module/components/global-styles/screen-heading-color.js.map +1 -0
- package/build-module/components/global-styles/screen-link-color.js +47 -14
- package/build-module/components/global-styles/screen-link-color.js.map +1 -1
- package/build-module/components/global-styles/screen-typography-element.js +4 -0
- package/build-module/components/global-styles/screen-typography-element.js.map +1 -1
- package/build-module/components/global-styles/screen-typography.js +5 -0
- package/build-module/components/global-styles/screen-typography.js.map +1 -1
- package/build-module/components/global-styles/typography-panel.js +74 -13
- package/build-module/components/global-styles/typography-panel.js.map +1 -1
- package/build-module/components/global-styles/typography-utils.js +204 -0
- package/build-module/components/global-styles/typography-utils.js.map +1 -0
- package/build-module/components/global-styles/ui.js +10 -0
- package/build-module/components/global-styles/ui.js.map +1 -1
- package/build-module/components/global-styles/use-global-styles-output.js +294 -69
- package/build-module/components/global-styles/use-global-styles-output.js.map +1 -1
- package/build-module/components/global-styles/utils.js +47 -4
- package/build-module/components/global-styles/utils.js.map +1 -1
- package/build-module/components/header/index.js +25 -12
- package/build-module/components/header/index.js.map +1 -1
- package/build-module/components/header/undo-redo/redo.js +3 -2
- package/build-module/components/header/undo-redo/redo.js.map +1 -1
- package/build-module/components/keyboard-shortcut-help-modal/index.js +1 -2
- package/build-module/components/keyboard-shortcut-help-modal/index.js.map +1 -1
- package/build-module/components/list/actions/index.js +1 -1
- package/build-module/components/list/actions/index.js.map +1 -1
- package/build-module/components/save-button/index.js +3 -4
- package/build-module/components/save-button/index.js.map +1 -1
- package/build-module/components/sidebar/navigation-menu-sidebar/navigation-menu.js +3 -3
- package/build-module/components/sidebar/navigation-menu-sidebar/navigation-menu.js.map +1 -1
- package/build-module/components/sidebar/template-card/template-actions.js +1 -1
- package/build-module/components/sidebar/template-card/template-actions.js.map +1 -1
- package/build-module/components/template-details/edit-template-title.js +12 -3
- package/build-module/components/template-details/edit-template-title.js.map +1 -1
- package/build-module/components/template-details/index.js +3 -22
- package/build-module/components/template-details/index.js.map +1 -1
- package/build-module/components/template-details/template-areas.js +1 -1
- package/build-module/components/template-details/template-areas.js.map +1 -1
- package/build-module/components/template-part-converter/convert-to-template-part.js +3 -1
- package/build-module/components/template-part-converter/convert-to-template-part.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/template-part-edit.js +67 -0
- package/build-module/hooks/template-part-edit.js.map +1 -0
- package/build-module/store/selectors.js +5 -2
- package/build-module/store/selectors.js.map +1 -1
- package/build-style/style-rtl.css +55 -48
- package/build-style/style.css +55 -48
- package/package.json +29 -29
- package/src/components/add-new-template/add-custom-generic-template-modal.js +97 -0
- package/src/components/add-new-template/add-custom-template-modal.js +93 -68
- package/src/components/add-new-template/new-template.js +126 -95
- package/src/components/add-new-template/style.scss +41 -8
- package/src/components/add-new-template/utils.js +622 -80
- package/src/components/block-editor/index.js +0 -2
- package/src/components/code-editor/index.js +15 -5
- package/src/components/editor/index.js +11 -0
- package/src/components/error-boundary/index.js +5 -0
- package/src/components/global-styles/dimensions-panel.js +214 -24
- package/src/components/global-styles/global-styles-provider.js +8 -9
- package/src/components/global-styles/hooks.js +18 -0
- package/src/components/global-styles/screen-color-palette.js +25 -27
- package/src/components/global-styles/screen-colors.js +55 -7
- package/src/components/global-styles/screen-heading-color.js +201 -0
- package/src/components/global-styles/screen-link-color.js +65 -23
- package/src/components/global-styles/screen-typography-element.js +4 -0
- package/src/components/global-styles/screen-typography.js +6 -0
- package/src/components/global-styles/style.scss +14 -11
- package/src/components/global-styles/test/typography-utils.js +130 -0
- package/src/components/global-styles/test/use-global-styles-output.js +296 -2
- package/src/components/global-styles/typography-panel.js +85 -16
- package/src/components/global-styles/typography-utils.js +228 -0
- package/src/components/global-styles/ui.js +13 -0
- package/src/components/global-styles/use-global-styles-output.js +387 -89
- package/src/components/global-styles/utils.js +43 -2
- package/src/components/header/index.js +37 -13
- package/src/components/header/style.scss +5 -3
- package/src/components/header/undo-redo/redo.js +6 -2
- package/src/components/keyboard-shortcut-help-modal/index.js +1 -2
- package/src/components/keyboard-shortcut-help-modal/style.scss +0 -5
- package/src/components/list/actions/index.js +3 -1
- package/src/components/list/style.scss +0 -8
- package/src/components/save-button/index.js +10 -13
- package/src/components/sidebar/navigation-menu-sidebar/navigation-menu.js +1 -5
- package/src/components/sidebar/style.scss +4 -0
- package/src/components/sidebar/template-card/template-actions.js +3 -1
- package/src/components/template-details/edit-template-title.js +10 -2
- package/src/components/template-details/index.js +7 -22
- package/src/components/template-details/template-areas.js +3 -1
- package/src/components/template-part-converter/convert-to-template-part.js +3 -1
- package/src/components/test/error-boundary.js +38 -0
- package/src/hooks/index.js +1 -0
- package/src/hooks/template-part-edit.js +82 -0
- package/src/store/selectors.js +11 -5
- package/src/style.scss +0 -1
- package/build/components/edit-template-part-menu-button/index.js +0 -90
- package/build/components/edit-template-part-menu-button/index.js.map +0 -1
- package/build-module/components/edit-template-part-menu-button/index.js +0 -72
- package/build-module/components/edit-template-part-menu-button/index.js.map +0 -1
- package/src/components/edit-template-part-menu-button/index.js +0 -82
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { kebabCase } from 'lodash';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* WordPress dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { useState } from '@wordpress/element';
|
|
10
|
+
import { __ } from '@wordpress/i18n';
|
|
11
|
+
import {
|
|
12
|
+
Button,
|
|
13
|
+
Flex,
|
|
14
|
+
FlexItem,
|
|
15
|
+
Modal,
|
|
16
|
+
TextControl,
|
|
17
|
+
} from '@wordpress/components';
|
|
18
|
+
|
|
19
|
+
function AddCustomGenericTemplateModal( { onClose, createTemplate } ) {
|
|
20
|
+
const [ title, setTitle ] = useState( '' );
|
|
21
|
+
const defaultTitle = __( 'Custom Template' );
|
|
22
|
+
const [ isBusy, setIsBusy ] = useState( false );
|
|
23
|
+
async function onCreateTemplate( event ) {
|
|
24
|
+
event.preventDefault();
|
|
25
|
+
|
|
26
|
+
if ( isBusy ) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
setIsBusy( true );
|
|
31
|
+
|
|
32
|
+
createTemplate(
|
|
33
|
+
{
|
|
34
|
+
slug:
|
|
35
|
+
'wp-custom-template-' + kebabCase( title || defaultTitle ),
|
|
36
|
+
title: title || defaultTitle,
|
|
37
|
+
},
|
|
38
|
+
false
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
return (
|
|
42
|
+
<Modal
|
|
43
|
+
title={ __( 'Create custom template' ) }
|
|
44
|
+
closeLabel={ __( 'Close' ) }
|
|
45
|
+
onRequestClose={ () => {
|
|
46
|
+
onClose();
|
|
47
|
+
} }
|
|
48
|
+
overlayClassName="edit-site-custom-generic-template__modal"
|
|
49
|
+
>
|
|
50
|
+
<form onSubmit={ onCreateTemplate }>
|
|
51
|
+
<Flex align="flex-start" gap={ 8 }>
|
|
52
|
+
<FlexItem>
|
|
53
|
+
<TextControl
|
|
54
|
+
label={ __( 'Name' ) }
|
|
55
|
+
value={ title }
|
|
56
|
+
onChange={ setTitle }
|
|
57
|
+
placeholder={ defaultTitle }
|
|
58
|
+
disabled={ isBusy }
|
|
59
|
+
help={ __(
|
|
60
|
+
'Describe the template, e.g. "Post with sidebar".'
|
|
61
|
+
) }
|
|
62
|
+
/>
|
|
63
|
+
</FlexItem>
|
|
64
|
+
</Flex>
|
|
65
|
+
|
|
66
|
+
<Flex
|
|
67
|
+
className="edit-site-custom-generic-template__modal-actions"
|
|
68
|
+
justify="flex-end"
|
|
69
|
+
expanded={ false }
|
|
70
|
+
>
|
|
71
|
+
<FlexItem>
|
|
72
|
+
<Button
|
|
73
|
+
variant="tertiary"
|
|
74
|
+
onClick={ () => {
|
|
75
|
+
onClose();
|
|
76
|
+
} }
|
|
77
|
+
>
|
|
78
|
+
{ __( 'Cancel' ) }
|
|
79
|
+
</Button>
|
|
80
|
+
</FlexItem>
|
|
81
|
+
<FlexItem>
|
|
82
|
+
<Button
|
|
83
|
+
variant="primary"
|
|
84
|
+
type="submit"
|
|
85
|
+
isBusy={ isBusy }
|
|
86
|
+
aria-disabled={ isBusy }
|
|
87
|
+
>
|
|
88
|
+
{ __( 'Create' ) }
|
|
89
|
+
</Button>
|
|
90
|
+
</FlexItem>
|
|
91
|
+
</Flex>
|
|
92
|
+
</form>
|
|
93
|
+
</Modal>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export default AddCustomGenericTemplateModal;
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
SearchControl,
|
|
12
12
|
TextHighlight,
|
|
13
13
|
__experimentalText as Text,
|
|
14
|
-
__experimentalHeading as Heading,
|
|
15
14
|
__unstableComposite as Composite,
|
|
16
15
|
__unstableUseCompositeState as useCompositeState,
|
|
17
16
|
__unstableCompositeItem as CompositeItem,
|
|
@@ -25,11 +24,6 @@ import { useEntityRecords } from '@wordpress/core-data';
|
|
|
25
24
|
import { mapToIHasNameAndId } from './utils';
|
|
26
25
|
|
|
27
26
|
const EMPTY_ARRAY = [];
|
|
28
|
-
const BASE_QUERY = {
|
|
29
|
-
order: 'asc',
|
|
30
|
-
_fields: 'id,title,slug,link',
|
|
31
|
-
context: 'view',
|
|
32
|
-
};
|
|
33
27
|
|
|
34
28
|
function SuggestionListItem( {
|
|
35
29
|
suggestion,
|
|
@@ -46,23 +40,13 @@ function SuggestionListItem( {
|
|
|
46
40
|
as={ Button }
|
|
47
41
|
{ ...composite }
|
|
48
42
|
className={ baseCssClass }
|
|
49
|
-
onClick={ () =>
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
onSelect( {
|
|
57
|
-
title,
|
|
58
|
-
description: sprintf(
|
|
59
|
-
// translators: Represents the description of a user's custom template in the Site Editor, e.g. "Template for Post: Hello, WordPress"
|
|
60
|
-
__( 'Template for %1$s' ),
|
|
61
|
-
title
|
|
62
|
-
),
|
|
63
|
-
slug: `single-${ entityForSuggestions.slug }-${ suggestion.slug }`,
|
|
64
|
-
} );
|
|
65
|
-
} }
|
|
43
|
+
onClick={ () =>
|
|
44
|
+
onSelect(
|
|
45
|
+
entityForSuggestions.config.getSpecificTemplate(
|
|
46
|
+
suggestion
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
}
|
|
66
50
|
>
|
|
67
51
|
<span className={ `${ baseCssClass }__title` }>
|
|
68
52
|
<TextHighlight text={ suggestion.name } highlight={ search } />
|
|
@@ -76,60 +60,90 @@ function SuggestionListItem( {
|
|
|
76
60
|
);
|
|
77
61
|
}
|
|
78
62
|
|
|
79
|
-
function
|
|
80
|
-
const
|
|
81
|
-
const [
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
63
|
+
function useDebouncedInput() {
|
|
64
|
+
const [ input, setInput ] = useState( '' );
|
|
65
|
+
const [ debounced, setter ] = useState( '' );
|
|
66
|
+
const setDebounced = useDebounce( setter, 250 );
|
|
67
|
+
useEffect( () => {
|
|
68
|
+
if ( debounced !== input ) {
|
|
69
|
+
setDebounced( input );
|
|
70
|
+
}
|
|
71
|
+
}, [ debounced, input ] );
|
|
72
|
+
return [ input, setInput, debounced ];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function useSearchSuggestions( entityForSuggestions, search ) {
|
|
76
|
+
const { config } = entityForSuggestions;
|
|
77
|
+
const query = useMemo(
|
|
78
|
+
() => ( {
|
|
79
|
+
order: 'asc',
|
|
80
|
+
context: 'view',
|
|
81
|
+
search,
|
|
82
|
+
per_page: search ? 20 : 10,
|
|
83
|
+
...config.queryArgs( search ),
|
|
84
|
+
} ),
|
|
85
|
+
[ search, config ]
|
|
86
|
+
);
|
|
94
87
|
const { records: searchResults, hasResolved: searchHasResolved } =
|
|
95
88
|
useEntityRecords(
|
|
96
89
|
entityForSuggestions.type,
|
|
97
90
|
entityForSuggestions.slug,
|
|
98
91
|
query
|
|
99
92
|
);
|
|
100
|
-
|
|
101
|
-
if ( search !== searchInputValue ) {
|
|
102
|
-
debouncedSearch( searchInputValue );
|
|
103
|
-
}
|
|
104
|
-
}, [ search, searchInputValue ] );
|
|
105
|
-
const entitiesInfo = useMemo( () => {
|
|
106
|
-
if ( ! searchResults?.length ) return EMPTY_ARRAY;
|
|
107
|
-
return mapToIHasNameAndId( searchResults, 'title.rendered' );
|
|
108
|
-
}, [ searchResults ] );
|
|
109
|
-
// Update suggestions only when the query has resolved.
|
|
93
|
+
const [ suggestions, setSuggestions ] = useState( EMPTY_ARRAY );
|
|
110
94
|
useEffect( () => {
|
|
111
95
|
if ( ! searchHasResolved ) return;
|
|
112
|
-
|
|
113
|
-
|
|
96
|
+
let newSuggestions = EMPTY_ARRAY;
|
|
97
|
+
if ( searchResults?.length ) {
|
|
98
|
+
newSuggestions = searchResults;
|
|
99
|
+
if ( config.recordNamePath ) {
|
|
100
|
+
newSuggestions = mapToIHasNameAndId(
|
|
101
|
+
newSuggestions,
|
|
102
|
+
config.recordNamePath
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Update suggestions only when the query has resolved, so as to keep
|
|
107
|
+
// the previous results in the UI.
|
|
108
|
+
setSuggestions( newSuggestions );
|
|
109
|
+
}, [ searchResults, searchHasResolved ] );
|
|
110
|
+
return suggestions;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function SuggestionList( { entityForSuggestions, onSelect } ) {
|
|
114
|
+
const composite = useCompositeState( { orientation: 'vertical' } );
|
|
115
|
+
const [ search, setSearch, debouncedSearch ] = useDebouncedInput();
|
|
116
|
+
const suggestions = useSearchSuggestions(
|
|
117
|
+
entityForSuggestions,
|
|
118
|
+
debouncedSearch
|
|
119
|
+
);
|
|
120
|
+
const { labels } = entityForSuggestions;
|
|
121
|
+
const [ showSearchControl, setShowSearchControl ] = useState( false );
|
|
122
|
+
if ( ! showSearchControl && suggestions?.length > 9 ) {
|
|
123
|
+
setShowSearchControl( true );
|
|
124
|
+
}
|
|
114
125
|
return (
|
|
115
126
|
<>
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
127
|
+
{ showSearchControl && (
|
|
128
|
+
<SearchControl
|
|
129
|
+
onChange={ setSearch }
|
|
130
|
+
value={ search }
|
|
131
|
+
label={ labels.search_items }
|
|
132
|
+
placeholder={ labels.search_items }
|
|
133
|
+
/>
|
|
134
|
+
) }
|
|
122
135
|
{ !! suggestions?.length && (
|
|
123
136
|
<Composite
|
|
124
137
|
{ ...composite }
|
|
125
138
|
role="listbox"
|
|
126
139
|
className="edit-site-custom-template-modal__suggestions_list"
|
|
140
|
+
aria-label={ __( 'Suggestions list' ) }
|
|
127
141
|
>
|
|
128
142
|
{ suggestions.map( ( suggestion ) => (
|
|
129
143
|
<SuggestionListItem
|
|
130
144
|
key={ suggestion.slug }
|
|
131
145
|
suggestion={ suggestion }
|
|
132
|
-
search={
|
|
146
|
+
search={ debouncedSearch }
|
|
133
147
|
onSelect={ onSelect }
|
|
134
148
|
entityForSuggestions={ entityForSuggestions }
|
|
135
149
|
composite={ composite }
|
|
@@ -137,9 +151,9 @@ function SuggestionList( { entityForSuggestions, onSelect } ) {
|
|
|
137
151
|
) ) }
|
|
138
152
|
</Composite>
|
|
139
153
|
) }
|
|
140
|
-
{
|
|
154
|
+
{ debouncedSearch && ! suggestions?.length && (
|
|
141
155
|
<p className="edit-site-custom-template-modal__no-results">
|
|
142
|
-
{
|
|
156
|
+
{ labels.not_found }
|
|
143
157
|
</p>
|
|
144
158
|
) }
|
|
145
159
|
</>
|
|
@@ -176,34 +190,45 @@ function AddCustomTemplateModal( { onClose, onSelect, entityForSuggestions } ) {
|
|
|
176
190
|
>
|
|
177
191
|
<FlexItem
|
|
178
192
|
isBlock
|
|
193
|
+
as={ Button }
|
|
179
194
|
onClick={ () => {
|
|
180
|
-
const {
|
|
181
|
-
|
|
182
|
-
|
|
195
|
+
const {
|
|
196
|
+
slug,
|
|
197
|
+
title,
|
|
198
|
+
description,
|
|
199
|
+
templatePrefix,
|
|
200
|
+
} = entityForSuggestions.template;
|
|
201
|
+
onSelect( {
|
|
202
|
+
slug,
|
|
203
|
+
title,
|
|
204
|
+
description,
|
|
205
|
+
templatePrefix,
|
|
206
|
+
} );
|
|
183
207
|
} }
|
|
184
208
|
>
|
|
185
|
-
<
|
|
209
|
+
<Text as="span" weight={ 600 }>
|
|
186
210
|
{ entityForSuggestions.labels.all_items }
|
|
187
|
-
</
|
|
211
|
+
</Text>
|
|
188
212
|
<Text as="span">
|
|
189
213
|
{
|
|
190
|
-
// translators: The user is given the choice to set up a template for all items of a post type, or just a specific one.
|
|
214
|
+
// translators: The user is given the choice to set up a template for all items of a post type or taxonomy, or just a specific one.
|
|
191
215
|
__( 'For all items' )
|
|
192
216
|
}
|
|
193
217
|
</Text>
|
|
194
218
|
</FlexItem>
|
|
195
219
|
<FlexItem
|
|
196
220
|
isBlock
|
|
221
|
+
as={ Button }
|
|
197
222
|
onClick={ () => {
|
|
198
223
|
setShowSearchEntities( true );
|
|
199
224
|
} }
|
|
200
225
|
>
|
|
201
|
-
<
|
|
226
|
+
<Text as="span" weight={ 600 }>
|
|
202
227
|
{ entityForSuggestions.labels.singular_name }
|
|
203
|
-
</
|
|
228
|
+
</Text>
|
|
204
229
|
<Text as="span">
|
|
205
230
|
{
|
|
206
|
-
// translators: The user is given the choice to set up a template for all items of a post type, or just a specific one.
|
|
231
|
+
// translators: The user is given the choice to set up a template for all items of a post type or taxonomy, or just a specific one.
|
|
207
232
|
__( 'For a specific item' )
|
|
208
233
|
}
|
|
209
234
|
</Text>
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External dependencies
|
|
3
|
-
*/
|
|
4
|
-
import { filter, includes } from 'lodash';
|
|
5
|
-
|
|
6
1
|
/**
|
|
7
2
|
* WordPress dependencies
|
|
8
3
|
*/
|
|
4
|
+
import apiFetch from '@wordpress/api-fetch';
|
|
5
|
+
import { addQueryArgs } from '@wordpress/url';
|
|
9
6
|
import {
|
|
10
7
|
DropdownMenu,
|
|
11
8
|
MenuGroup,
|
|
@@ -13,9 +10,8 @@ import {
|
|
|
13
10
|
NavigableMenu,
|
|
14
11
|
} from '@wordpress/components';
|
|
15
12
|
import { useState } from '@wordpress/element';
|
|
16
|
-
import {
|
|
13
|
+
import { useDispatch } from '@wordpress/data';
|
|
17
14
|
import { store as coreStore } from '@wordpress/core-data';
|
|
18
|
-
import { store as editorStore } from '@wordpress/editor';
|
|
19
15
|
import {
|
|
20
16
|
archive,
|
|
21
17
|
blockMeta,
|
|
@@ -30,15 +26,23 @@ import {
|
|
|
30
26
|
postDate,
|
|
31
27
|
search,
|
|
32
28
|
tag,
|
|
29
|
+
layout as customGenericTemplateIcon,
|
|
33
30
|
} from '@wordpress/icons';
|
|
34
|
-
import { __
|
|
31
|
+
import { __ } from '@wordpress/i18n';
|
|
35
32
|
import { store as noticesStore } from '@wordpress/notices';
|
|
36
33
|
|
|
37
34
|
/**
|
|
38
35
|
* Internal dependencies
|
|
39
36
|
*/
|
|
40
37
|
import AddCustomTemplateModal from './add-custom-template-modal';
|
|
41
|
-
import {
|
|
38
|
+
import {
|
|
39
|
+
useExistingTemplates,
|
|
40
|
+
useDefaultTemplateTypes,
|
|
41
|
+
useTaxonomiesMenuItems,
|
|
42
|
+
usePostTypeMenuItems,
|
|
43
|
+
useAuthorMenuItem,
|
|
44
|
+
} from './utils';
|
|
45
|
+
import AddCustomGenericTemplateModal from './add-custom-generic-template-modal';
|
|
42
46
|
import { useHistory } from '../routes';
|
|
43
47
|
import { store as editSiteStore } from '../../store';
|
|
44
48
|
|
|
@@ -74,31 +78,34 @@ const TEMPLATE_ICONS = {
|
|
|
74
78
|
};
|
|
75
79
|
|
|
76
80
|
export default function NewTemplate( { postType } ) {
|
|
77
|
-
const history = useHistory();
|
|
78
|
-
const postTypes = usePostTypes();
|
|
79
81
|
const [ showCustomTemplateModal, setShowCustomTemplateModal ] =
|
|
80
82
|
useState( false );
|
|
83
|
+
const [
|
|
84
|
+
showCustomGenericTemplateModal,
|
|
85
|
+
setShowCustomGenericTemplateModal,
|
|
86
|
+
] = useState( false );
|
|
81
87
|
const [ entityForSuggestions, setEntityForSuggestions ] = useState( {} );
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
existingTemplates: select( coreStore ).getEntityRecords(
|
|
85
|
-
'postType',
|
|
86
|
-
'wp_template',
|
|
87
|
-
{ per_page: -1 }
|
|
88
|
-
),
|
|
89
|
-
defaultTemplateTypes:
|
|
90
|
-
select( editorStore ).__experimentalGetDefaultTemplateTypes(),
|
|
91
|
-
} ),
|
|
92
|
-
[]
|
|
93
|
-
);
|
|
94
|
-
const postTypesEntitiesInfo = usePostTypesEntitiesInfo( existingTemplates );
|
|
88
|
+
|
|
89
|
+
const history = useHistory();
|
|
95
90
|
const { saveEntityRecord } = useDispatch( coreStore );
|
|
96
91
|
const { createErrorNotice } = useDispatch( noticesStore );
|
|
97
92
|
const { setTemplate } = useDispatch( editSiteStore );
|
|
98
93
|
|
|
99
|
-
async function createTemplate( template ) {
|
|
94
|
+
async function createTemplate( template, isWPSuggestion = true ) {
|
|
100
95
|
try {
|
|
101
|
-
const { title, description, slug } = template;
|
|
96
|
+
const { title, description, slug, templatePrefix } = template;
|
|
97
|
+
let templateContent = template.content;
|
|
98
|
+
// Try to find fallback content from existing templates.
|
|
99
|
+
if ( ! templateContent ) {
|
|
100
|
+
const fallbackTemplate = await apiFetch( {
|
|
101
|
+
path: addQueryArgs( '/wp/v2/templates/lookup', {
|
|
102
|
+
slug,
|
|
103
|
+
is_custom: ! isWPSuggestion,
|
|
104
|
+
template_prefix: templatePrefix,
|
|
105
|
+
} ),
|
|
106
|
+
} );
|
|
107
|
+
templateContent = fallbackTemplate.content;
|
|
108
|
+
}
|
|
102
109
|
const newTemplate = await saveEntityRecord(
|
|
103
110
|
'postType',
|
|
104
111
|
'wp_template',
|
|
@@ -108,8 +115,9 @@ export default function NewTemplate( { postType } ) {
|
|
|
108
115
|
slug: slug.toString(),
|
|
109
116
|
status: 'publish',
|
|
110
117
|
title,
|
|
118
|
+
content: templateContent,
|
|
111
119
|
// This adds a post meta field in template that is part of `is_custom` value calculation.
|
|
112
|
-
is_wp_suggestion:
|
|
120
|
+
is_wp_suggestion: isWPSuggestion,
|
|
113
121
|
},
|
|
114
122
|
{ throwOnError: true }
|
|
115
123
|
);
|
|
@@ -135,78 +143,14 @@ export default function NewTemplate( { postType } ) {
|
|
|
135
143
|
} );
|
|
136
144
|
}
|
|
137
145
|
}
|
|
138
|
-
const existingTemplateSlugs = ( existingTemplates || [] ).map(
|
|
139
|
-
( { slug } ) => slug
|
|
140
|
-
);
|
|
141
|
-
const missingTemplates = filter(
|
|
142
|
-
defaultTemplateTypes,
|
|
143
|
-
( template ) =>
|
|
144
|
-
includes( DEFAULT_TEMPLATE_SLUGS, template.slug ) &&
|
|
145
|
-
! includes( existingTemplateSlugs, template.slug )
|
|
146
|
-
);
|
|
147
146
|
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const hasGeneralTemplate = existingTemplateSlugs?.includes(
|
|
152
|
-
`single-${ slug }`
|
|
153
|
-
);
|
|
154
|
-
const hasEntities = postTypesEntitiesInfo?.[ slug ]?.hasEntities;
|
|
155
|
-
const menuItem = {
|
|
156
|
-
slug: `single-${ slug }`,
|
|
157
|
-
title: sprintf(
|
|
158
|
-
// translators: %s: Name of the post type e.g: "Post".
|
|
159
|
-
__( 'Single item: %s' ),
|
|
160
|
-
labels.singular_name
|
|
161
|
-
),
|
|
162
|
-
description: sprintf(
|
|
163
|
-
// translators: %s: Name of the post type e.g: "Post".
|
|
164
|
-
__( 'Displays a single item: %s.' ),
|
|
165
|
-
labels.singular_name
|
|
166
|
-
),
|
|
167
|
-
// `icon` is the `menu_icon` property of a post type. We
|
|
168
|
-
// only handle `dashicons` for now, even if the `menu_icon`
|
|
169
|
-
// also supports urls and svg as values.
|
|
170
|
-
icon: icon?.startsWith( 'dashicons-' )
|
|
171
|
-
? icon.slice( 10 )
|
|
172
|
-
: null,
|
|
173
|
-
};
|
|
174
|
-
// We have a different template creation flow only if they have entities.
|
|
175
|
-
if ( hasEntities ) {
|
|
176
|
-
menuItem.onClick = ( template ) => {
|
|
177
|
-
setShowCustomTemplateModal( true );
|
|
178
|
-
setEntityForSuggestions( {
|
|
179
|
-
type: 'postType',
|
|
180
|
-
slug,
|
|
181
|
-
labels,
|
|
182
|
-
hasGeneralTemplate,
|
|
183
|
-
template,
|
|
184
|
-
postsToExclude:
|
|
185
|
-
postTypesEntitiesInfo[ slug ].existingPosts,
|
|
186
|
-
} );
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
// We don't need to add the menu item if there are no
|
|
190
|
-
// entities and the general template exists.
|
|
191
|
-
if ( ! hasGeneralTemplate || hasEntities ) {
|
|
192
|
-
accumulator.push( menuItem );
|
|
193
|
-
}
|
|
194
|
-
return accumulator;
|
|
195
|
-
},
|
|
196
|
-
[]
|
|
147
|
+
const missingTemplates = useMissingTemplates(
|
|
148
|
+
setEntityForSuggestions,
|
|
149
|
+
setShowCustomTemplateModal
|
|
197
150
|
);
|
|
198
|
-
if ( ! missingTemplates.length
|
|
151
|
+
if ( ! missingTemplates.length ) {
|
|
199
152
|
return null;
|
|
200
153
|
}
|
|
201
|
-
// Update the sort order to match the DEFAULT_TEMPLATE_SLUGS order.
|
|
202
|
-
missingTemplates?.sort( ( template1, template2 ) => {
|
|
203
|
-
return (
|
|
204
|
-
DEFAULT_TEMPLATE_SLUGS.indexOf( template1.slug ) -
|
|
205
|
-
DEFAULT_TEMPLATE_SLUGS.indexOf( template2.slug )
|
|
206
|
-
);
|
|
207
|
-
} );
|
|
208
|
-
// Append all extra templates at the end of the list for now.
|
|
209
|
-
missingTemplates.push( ...extraTemplates );
|
|
210
154
|
return (
|
|
211
155
|
<>
|
|
212
156
|
<DropdownMenu
|
|
@@ -253,6 +197,21 @@ export default function NewTemplate( { postType } ) {
|
|
|
253
197
|
);
|
|
254
198
|
} ) }
|
|
255
199
|
</MenuGroup>
|
|
200
|
+
<MenuGroup>
|
|
201
|
+
<MenuItem
|
|
202
|
+
icon={ customGenericTemplateIcon }
|
|
203
|
+
iconPosition="left"
|
|
204
|
+
info={ __(
|
|
205
|
+
'Custom templates can be applied to any post or page.'
|
|
206
|
+
) }
|
|
207
|
+
key="custom-template"
|
|
208
|
+
onClick={ () =>
|
|
209
|
+
setShowCustomGenericTemplateModal( true )
|
|
210
|
+
}
|
|
211
|
+
>
|
|
212
|
+
{ __( 'Custom template' ) }
|
|
213
|
+
</MenuItem>
|
|
214
|
+
</MenuGroup>
|
|
256
215
|
</NavigableMenu>
|
|
257
216
|
) }
|
|
258
217
|
</DropdownMenu>
|
|
@@ -263,6 +222,78 @@ export default function NewTemplate( { postType } ) {
|
|
|
263
222
|
entityForSuggestions={ entityForSuggestions }
|
|
264
223
|
/>
|
|
265
224
|
) }
|
|
225
|
+
{ showCustomGenericTemplateModal && (
|
|
226
|
+
<AddCustomGenericTemplateModal
|
|
227
|
+
onClose={ () => setShowCustomGenericTemplateModal( false ) }
|
|
228
|
+
createTemplate={ createTemplate }
|
|
229
|
+
/>
|
|
230
|
+
) }
|
|
266
231
|
</>
|
|
267
232
|
);
|
|
268
233
|
}
|
|
234
|
+
|
|
235
|
+
function useMissingTemplates(
|
|
236
|
+
setEntityForSuggestions,
|
|
237
|
+
setShowCustomTemplateModal
|
|
238
|
+
) {
|
|
239
|
+
const existingTemplates = useExistingTemplates();
|
|
240
|
+
const defaultTemplateTypes = useDefaultTemplateTypes();
|
|
241
|
+
const existingTemplateSlugs = ( existingTemplates || [] ).map(
|
|
242
|
+
( { slug } ) => slug
|
|
243
|
+
);
|
|
244
|
+
const missingDefaultTemplates = ( defaultTemplateTypes || [] ).filter(
|
|
245
|
+
( template ) =>
|
|
246
|
+
DEFAULT_TEMPLATE_SLUGS.includes( template.slug ) &&
|
|
247
|
+
! existingTemplateSlugs.includes( template.slug )
|
|
248
|
+
);
|
|
249
|
+
const onClickMenuItem = ( _entityForSuggestions ) => {
|
|
250
|
+
setShowCustomTemplateModal( true );
|
|
251
|
+
setEntityForSuggestions( _entityForSuggestions );
|
|
252
|
+
};
|
|
253
|
+
// We need to replace existing default template types with
|
|
254
|
+
// the create specific template functionality. The original
|
|
255
|
+
// info (title, description, etc.) is preserved in the
|
|
256
|
+
// used hooks.
|
|
257
|
+
const enhancedMissingDefaultTemplateTypes = [ ...missingDefaultTemplates ];
|
|
258
|
+
const { defaultTaxonomiesMenuItems, taxonomiesMenuItems } =
|
|
259
|
+
useTaxonomiesMenuItems( onClickMenuItem );
|
|
260
|
+
const { defaultPostTypesMenuItems, postTypesMenuItems } =
|
|
261
|
+
usePostTypeMenuItems( onClickMenuItem );
|
|
262
|
+
|
|
263
|
+
const authorMenuItem = useAuthorMenuItem( onClickMenuItem );
|
|
264
|
+
[
|
|
265
|
+
...defaultTaxonomiesMenuItems,
|
|
266
|
+
...defaultPostTypesMenuItems,
|
|
267
|
+
authorMenuItem,
|
|
268
|
+
].forEach( ( menuItem ) => {
|
|
269
|
+
if ( ! menuItem ) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
const matchIndex = enhancedMissingDefaultTemplateTypes.findIndex(
|
|
273
|
+
( template ) => template.slug === menuItem.slug
|
|
274
|
+
);
|
|
275
|
+
// Some default template types might have been filtered above from
|
|
276
|
+
// `missingDefaultTemplates` because they only check for the general
|
|
277
|
+
// template. So here we either replace or append the item, augmented
|
|
278
|
+
// with the check if it has available specific item to create a
|
|
279
|
+
// template for.
|
|
280
|
+
if ( matchIndex > -1 ) {
|
|
281
|
+
enhancedMissingDefaultTemplateTypes[ matchIndex ] = menuItem;
|
|
282
|
+
} else {
|
|
283
|
+
enhancedMissingDefaultTemplateTypes.push( menuItem );
|
|
284
|
+
}
|
|
285
|
+
} );
|
|
286
|
+
// Update the sort order to match the DEFAULT_TEMPLATE_SLUGS order.
|
|
287
|
+
enhancedMissingDefaultTemplateTypes?.sort( ( template1, template2 ) => {
|
|
288
|
+
return (
|
|
289
|
+
DEFAULT_TEMPLATE_SLUGS.indexOf( template1.slug ) -
|
|
290
|
+
DEFAULT_TEMPLATE_SLUGS.indexOf( template2.slug )
|
|
291
|
+
);
|
|
292
|
+
} );
|
|
293
|
+
const missingTemplates = [
|
|
294
|
+
...enhancedMissingDefaultTemplateTypes,
|
|
295
|
+
...postTypesMenuItems,
|
|
296
|
+
...taxonomiesMenuItems,
|
|
297
|
+
];
|
|
298
|
+
return missingTemplates;
|
|
299
|
+
}
|