Skip to content

Commit 9df5714

Browse files
ntsekourasmcsf
andauthored
[Full Site Editing]: Expand the templates that can be added - custom taxonomies, specific term, specific category and tag (#41875)
* [Full Site Editing]: Expand the templates that can be added - custom taxonomies, specific term, specific category and tag * refactor: remove extraneous exports * refactor: SuggestionList * refactor: SuggestionListItem * refactor: NewTemplate (first pass) Isolate all template-computing logic in a macro hook (useMarkPersistent) * config: add getOrderBy * refactor: aliasTemplateSlug -> templateSlug Also rename and move some other variables for clarity. * minor comment tweaks * Update packages/edit-site/src/components/add-new-template/new-template.js Co-authored-by: Miguel Fonseca <miguelcsf@gmail.com> Co-authored-by: Miguel Fonseca <miguelcsf@gmail.com>
1 parent 3198c90 commit 9df5714

3 files changed

Lines changed: 468 additions & 196 deletions

File tree

packages/edit-site/src/components/add-new-template/add-custom-template-modal.js

Lines changed: 92 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,34 @@ import { useEntityRecords } from '@wordpress/core-data';
2525
import { mapToIHasNameAndId } from './utils';
2626

2727
const EMPTY_ARRAY = [];
28-
const BASE_QUERY = {
29-
order: 'asc',
30-
_fields: 'id,title,slug,link',
31-
context: 'view',
32-
};
28+
29+
function selectSuggestion( suggestion, onSelect, entityForSuggestions ) {
30+
const {
31+
labels,
32+
slug,
33+
config: { templateSlug, templatePrefix },
34+
} = entityForSuggestions;
35+
const title = sprintf(
36+
// translators: Represents the title of a user's custom template in the Site Editor, where %1$s is the singular name of a post type or taxonomy and %2$s is the name of the post or term, e.g. "Post: Hello, WordPress", "Category: shoes"
37+
__( '%1$s: %2$s' ),
38+
labels.singular_name,
39+
suggestion.name
40+
);
41+
let newTemplateSlug = `${ templateSlug || slug }-${ suggestion.slug }`;
42+
if ( templatePrefix ) {
43+
newTemplateSlug = templatePrefix + newTemplateSlug;
44+
}
45+
const newTemplate = {
46+
title,
47+
description: sprintf(
48+
// translators: Represents the description of a user's custom template in the Site Editor, e.g. "Template for Post: Hello, WordPress"
49+
__( 'Template for %1$s' ),
50+
title
51+
),
52+
slug: newTemplateSlug,
53+
};
54+
onSelect( newTemplate );
55+
}
3356

3457
function SuggestionListItem( {
3558
suggestion,
@@ -46,23 +69,9 @@ function SuggestionListItem( {
4669
as={ Button }
4770
{ ...composite }
4871
className={ baseCssClass }
49-
onClick={ () => {
50-
const title = sprintf(
51-
// translators: Represents the title of a user's custom template in the Site Editor, where %1$s is the singular name of a post type and %2$s is the name of the post, e.g. "Post: Hello, WordPress"
52-
__( '%1$s: %2$s' ),
53-
entityForSuggestions.labels.singular_name,
54-
suggestion.name
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-
} }
72+
onClick={ () =>
73+
selectSuggestion( suggestion, onSelect, entityForSuggestions )
74+
}
6675
>
6776
<span className={ `${ baseCssClass }__title` }>
6877
<TextHighlight text={ suggestion.name } highlight={ search } />
@@ -76,48 +85,73 @@ function SuggestionListItem( {
7685
);
7786
}
7887

79-
function SuggestionList( { entityForSuggestions, onSelect } ) {
80-
const composite = useCompositeState( { orientation: 'vertical' } );
81-
const [ suggestions, setSuggestions ] = useState( EMPTY_ARRAY );
82-
// We need to track two values, the search input's value(searchInputValue)
83-
// and the one we want to debounce(search) and make REST API requests.
84-
const [ searchInputValue, setSearchInputValue ] = useState( '' );
85-
const [ search, setSearch ] = useState( '' );
86-
const debouncedSearch = useDebounce( setSearch, 250 );
87-
const query = {
88-
...BASE_QUERY,
89-
search,
90-
orderby: search ? 'relevance' : 'modified',
91-
exclude: entityForSuggestions.postsToExclude,
92-
per_page: search ? 20 : 10,
93-
};
88+
function useDebouncedInput() {
89+
const [ input, setInput ] = useState( '' );
90+
const [ debounced, setter ] = useState( '' );
91+
const setDebounced = useDebounce( setter, 250 );
92+
useEffect( () => {
93+
if ( debounced !== input ) {
94+
setDebounced( input );
95+
}
96+
}, [ debounced, input ] );
97+
return [ input, setInput, debounced ];
98+
}
99+
100+
function useSearchSuggestions( entityForSuggestions, search ) {
101+
const { config, postsToExclude } = entityForSuggestions;
102+
const query = useMemo(
103+
() => ( {
104+
order: 'asc',
105+
_fields: 'id,name,title,slug,link',
106+
context: 'view',
107+
search,
108+
orderBy: config.getOrderBy( { search } ),
109+
exclude: postsToExclude,
110+
per_page: search ? 20 : 10,
111+
} ),
112+
[ search, config, postsToExclude ]
113+
);
94114
const { records: searchResults, hasResolved: searchHasResolved } =
95115
useEntityRecords(
96116
entityForSuggestions.type,
97117
entityForSuggestions.slug,
98118
query
99119
);
100-
useEffect( () => {
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.
120+
const [ suggestions, setSuggestions ] = useState( EMPTY_ARRAY );
110121
useEffect( () => {
111122
if ( ! searchHasResolved ) return;
112-
setSuggestions( entitiesInfo );
113-
}, [ entitiesInfo, searchHasResolved ] );
123+
let newSuggestions = EMPTY_ARRAY;
124+
if ( searchResults?.length ) {
125+
newSuggestions = searchResults;
126+
if ( config.recordNamePath ) {
127+
newSuggestions = mapToIHasNameAndId(
128+
newSuggestions,
129+
config.recordNamePath
130+
);
131+
}
132+
}
133+
// Update suggestions only when the query has resolved, so as to keep
134+
// the previous results in the UI.
135+
setSuggestions( newSuggestions );
136+
}, [ searchResults, searchHasResolved ] );
137+
return suggestions;
138+
}
139+
140+
function SuggestionList( { entityForSuggestions, onSelect } ) {
141+
const composite = useCompositeState( { orientation: 'vertical' } );
142+
const [ search, setSearch, debouncedSearch ] = useDebouncedInput();
143+
const suggestions = useSearchSuggestions(
144+
entityForSuggestions,
145+
debouncedSearch
146+
);
147+
const { labels } = entityForSuggestions;
114148
return (
115149
<>
116150
<SearchControl
117-
onChange={ setSearchInputValue }
118-
value={ searchInputValue }
119-
label={ entityForSuggestions.labels.search_items }
120-
placeholder={ entityForSuggestions.labels.search_items }
151+
onChange={ setSearch }
152+
value={ search }
153+
label={ labels.search_items }
154+
placeholder={ labels.search_items }
121155
/>
122156
{ !! suggestions?.length && (
123157
<Composite
@@ -129,17 +163,17 @@ function SuggestionList( { entityForSuggestions, onSelect } ) {
129163
<SuggestionListItem
130164
key={ suggestion.slug }
131165
suggestion={ suggestion }
132-
search={ search }
166+
search={ debouncedSearch }
133167
onSelect={ onSelect }
134168
entityForSuggestions={ entityForSuggestions }
135169
composite={ composite }
136170
/>
137171
) ) }
138172
</Composite>
139173
) }
140-
{ search && ! suggestions?.length && (
174+
{ debouncedSearch && ! suggestions?.length && (
141175
<p className="edit-site-custom-template-modal__no-results">
142-
{ entityForSuggestions.labels.not_found }
176+
{ labels.not_found }
143177
</p>
144178
) }
145179
</>
@@ -187,7 +221,7 @@ function AddCustomTemplateModal( { onClose, onSelect, entityForSuggestions } ) {
187221
</Heading>
188222
<Text as="span">
189223
{
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.
224+
// 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.
191225
__( 'For all items' )
192226
}
193227
</Text>
@@ -203,7 +237,7 @@ function AddCustomTemplateModal( { onClose, onSelect, entityForSuggestions } ) {
203237
</Heading>
204238
<Text as="span">
205239
{
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.
240+
// 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.
207241
__( 'For a specific item' )
208242
}
209243
</Text>

0 commit comments

Comments
 (0)