@wordpress/edit-site 4.10.0 → 4.11.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 (69) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/add-new-template/add-custom-template-modal.js +22 -42
  3. package/build/components/add-new-template/add-custom-template-modal.js.map +1 -1
  4. package/build/components/add-new-template/new-template.js +17 -20
  5. package/build/components/add-new-template/new-template.js.map +1 -1
  6. package/build/components/add-new-template/utils.js +366 -239
  7. package/build/components/add-new-template/utils.js.map +1 -1
  8. package/build/components/block-editor/index.js +1 -3
  9. package/build/components/block-editor/index.js.map +1 -1
  10. package/build/components/global-styles/dimensions-panel.js +183 -13
  11. package/build/components/global-styles/dimensions-panel.js.map +1 -1
  12. package/build/components/global-styles/hooks.js +1 -1
  13. package/build/components/global-styles/hooks.js.map +1 -1
  14. package/build/components/global-styles/use-global-styles-output.js +95 -17
  15. package/build/components/global-styles/use-global-styles-output.js.map +1 -1
  16. package/build/components/global-styles/utils.js +31 -0
  17. package/build/components/global-styles/utils.js.map +1 -1
  18. package/build/components/header/index.js +7 -6
  19. package/build/components/header/index.js.map +1 -1
  20. package/build/hooks/index.js +2 -0
  21. package/build/hooks/index.js.map +1 -1
  22. package/build/hooks/template-part-edit.js +86 -0
  23. package/build/hooks/template-part-edit.js.map +1 -0
  24. package/build-module/components/add-new-template/add-custom-template-modal.js +23 -43
  25. package/build-module/components/add-new-template/add-custom-template-modal.js.map +1 -1
  26. package/build-module/components/add-new-template/new-template.js +18 -21
  27. package/build-module/components/add-new-template/new-template.js.map +1 -1
  28. package/build-module/components/add-new-template/utils.js +365 -227
  29. package/build-module/components/add-new-template/utils.js.map +1 -1
  30. package/build-module/components/block-editor/index.js +1 -2
  31. package/build-module/components/block-editor/index.js.map +1 -1
  32. package/build-module/components/global-styles/dimensions-panel.js +183 -14
  33. package/build-module/components/global-styles/dimensions-panel.js.map +1 -1
  34. package/build-module/components/global-styles/hooks.js +1 -1
  35. package/build-module/components/global-styles/hooks.js.map +1 -1
  36. package/build-module/components/global-styles/use-global-styles-output.js +94 -22
  37. package/build-module/components/global-styles/use-global-styles-output.js.map +1 -1
  38. package/build-module/components/global-styles/utils.js +29 -0
  39. package/build-module/components/global-styles/utils.js.map +1 -1
  40. package/build-module/components/header/index.js +8 -6
  41. package/build-module/components/header/index.js.map +1 -1
  42. package/build-module/hooks/index.js +1 -0
  43. package/build-module/hooks/index.js.map +1 -1
  44. package/build-module/hooks/template-part-edit.js +67 -0
  45. package/build-module/hooks/template-part-edit.js.map +1 -0
  46. package/build-style/style-rtl.css +25 -25
  47. package/build-style/style.css +25 -25
  48. package/package.json +29 -29
  49. package/src/components/add-new-template/add-custom-template-modal.js +27 -45
  50. package/src/components/add-new-template/new-template.js +27 -64
  51. package/src/components/add-new-template/style.scss +20 -8
  52. package/src/components/add-new-template/utils.js +398 -229
  53. package/src/components/block-editor/index.js +0 -2
  54. package/src/components/global-styles/dimensions-panel.js +207 -14
  55. package/src/components/global-styles/hooks.js +2 -0
  56. package/src/components/global-styles/test/use-global-styles-output.js +64 -1
  57. package/src/components/global-styles/use-global-styles-output.js +100 -8
  58. package/src/components/global-styles/utils.js +31 -0
  59. package/src/components/header/index.js +9 -10
  60. package/src/components/header/style.scss +5 -3
  61. package/src/components/sidebar/style.scss +4 -0
  62. package/src/hooks/index.js +1 -0
  63. package/src/hooks/template-part-edit.js +82 -0
  64. package/src/style.scss +0 -1
  65. package/build/components/edit-template-part-menu-button/index.js +0 -90
  66. package/build/components/edit-template-part-menu-button/index.js.map +0 -1
  67. package/build-module/components/edit-template-part-menu-button/index.js +0 -72
  68. package/build-module/components/edit-template-part-menu-button/index.js.map +0 -1
  69. package/src/components/edit-template-part-menu-button/index.js +0 -82
@@ -40,73 +40,6 @@ export const mapToIHasNameAndId = (entities, path) => {
40
40
  * @property {number[]} existingEntitiesIds An array of the existing entities ids.
41
41
  */
42
42
 
43
- /**
44
- * @typedef {Object} EntityConfig
45
- * @property {string} entityName The entity's name.
46
- * @property {Function} getOrderBy Getter for an entity's `orderBy` query parameter, given the object
47
- * {search} as argument.
48
- * @property {Function} getIcon Getter function for returning an entity's icon for the menu item.
49
- * @property {Function} getTitle Getter function for returning an entity's title for the menu item.
50
- * @property {Function} getDescription Getter function for returning an entity's description for the menu item.
51
- * @property {string} recordNamePath The path to an entity's properties to use as a `name`. If not provided
52
- * is assumed that `name` property exists.
53
- * @property {string} templatePrefix The template prefix to create new templates and check against existing
54
- * templates. For example custom post types need a `single-` prefix to all
55
- * templates(`single-post-hello`), whereas `pages` don't (`page-hello`).
56
- * @property {string} templateSlug If this property is provided, it is going to be used for the creation of
57
- * new templates and the check against existing templates in the place
58
- * of the actual entity's `slug`. An example is `Tag` templates where the
59
- * the Tag's taxonomy slug is `post_tag`, but template hierarchy is based
60
- * on `tag` alias.
61
- */
62
-
63
- const taxonomyBaseConfig = {
64
- entityName: 'taxonomy',
65
- getOrderBy: _ref => {
66
- let {
67
- search
68
- } = _ref;
69
- return search ? 'name' : 'count';
70
- },
71
- getIcon: () => blockMeta,
72
- getTitle: labels => sprintf( // translators: %s: Name of the taxonomy e.g: "Cagegory".
73
- __('Single taxonomy: %s'), labels.singular_name),
74
- getDescription: labels => sprintf( // translators: %s: Name of the taxonomy e.g: "Product Categories".
75
- __('Displays a single taxonomy: %s.'), labels.singular_name)
76
- };
77
- const postTypeBaseConfig = {
78
- entityName: 'postType',
79
- getOrderBy: _ref2 => {
80
- let {
81
- search
82
- } = _ref2;
83
- return search ? 'relevance' : 'modified';
84
- },
85
- recordNamePath: 'title.rendered',
86
- // `icon` is the `menu_icon` property of a post type. We
87
- // only handle `dashicons` for now, even if the `menu_icon`
88
- // also supports urls and svg as values.
89
- getIcon: _icon => _icon !== null && _icon !== void 0 && _icon.startsWith('dashicons-') ? _icon.slice(10) : post,
90
- getTitle: labels => sprintf( // translators: %s: Name of the post type e.g: "Post".
91
- __('Single item: %s'), labels.singular_name),
92
- getDescription: labels => sprintf( // translators: %s: Name of the post type e.g: "Post".
93
- __('Displays a single item: %s.'), labels.singular_name)
94
- };
95
- export const entitiesConfig = {
96
- postType: { ...postTypeBaseConfig,
97
- templatePrefix: 'single-'
98
- },
99
- page: { ...postTypeBaseConfig
100
- },
101
- taxonomy: { ...taxonomyBaseConfig,
102
- templatePrefix: 'taxonomy-'
103
- },
104
- category: { ...taxonomyBaseConfig
105
- },
106
- tag: { ...taxonomyBaseConfig,
107
- templateSlug: 'tag'
108
- }
109
- };
110
43
  export const useExistingTemplates = () => {
111
44
  return useSelect(select => select(coreStore).getEntityRecords('postType', 'wp_template', {
112
45
  per_page: -1
@@ -122,40 +55,14 @@ const usePublicPostTypes = () => {
122
55
  }), []);
123
56
  return useMemo(() => {
124
57
  const excludedPostTypes = ['attachment'];
125
- return postTypes === null || postTypes === void 0 ? void 0 : postTypes.filter(_ref3 => {
58
+ return postTypes === null || postTypes === void 0 ? void 0 : postTypes.filter(_ref => {
126
59
  let {
127
60
  viewable,
128
61
  slug
129
- } = _ref3;
62
+ } = _ref;
130
63
  return viewable && !excludedPostTypes.includes(slug);
131
64
  });
132
65
  }, [postTypes]);
133
- }; // `page` post type is a special case in the template hierarchy,
134
- // so we exclude it from the list of post types and we handle it
135
- // separately.
136
-
137
-
138
- export const usePostTypes = () => {
139
- const postTypes = usePublicPostTypes();
140
- return useMemo(() => {
141
- return postTypes === null || postTypes === void 0 ? void 0 : postTypes.filter(_ref4 => {
142
- let {
143
- slug
144
- } = _ref4;
145
- return slug !== 'page';
146
- });
147
- }, [postTypes]);
148
- };
149
- export const usePostTypePage = () => {
150
- const postTypes = usePublicPostTypes();
151
- return useMemo(() => {
152
- return postTypes === null || postTypes === void 0 ? void 0 : postTypes.filter(_ref5 => {
153
- let {
154
- slug
155
- } = _ref5;
156
- return slug === 'page';
157
- });
158
- }, [postTypes]);
159
66
  };
160
67
 
161
68
  const usePublicTaxonomies = () => {
@@ -163,80 +70,348 @@ const usePublicTaxonomies = () => {
163
70
  per_page: -1
164
71
  }), []);
165
72
  return useMemo(() => {
166
- return taxonomies === null || taxonomies === void 0 ? void 0 : taxonomies.filter(_ref6 => {
73
+ return taxonomies === null || taxonomies === void 0 ? void 0 : taxonomies.filter(_ref2 => {
167
74
  let {
168
75
  visibility
169
- } = _ref6;
76
+ } = _ref2;
170
77
  return visibility === null || visibility === void 0 ? void 0 : visibility.publicly_queryable;
171
78
  });
172
79
  }, [taxonomies]);
173
80
  };
174
- /**
175
- * `category` and `post_tag` are handled specifically in template
176
- * hierarchy so we need to differentiate them and return the rest,
177
- * e.g. `category-$slug` and `taxonomy-$taxonomy-$term`.
178
- */
179
81
 
82
+ export const usePostTypeMenuItems = onClickMenuItem => {
83
+ const publicPostTypes = usePublicPostTypes();
84
+ const existingTemplates = useExistingTemplates();
85
+ const defaultTemplateTypes = useDefaultTemplateTypes(); // `page`is a special case in template hierarchy.
180
86
 
181
- export const useTaxonomies = () => {
182
- const taxonomies = usePublicTaxonomies();
183
- const specialTaxonomies = ['category', 'post_tag'];
184
- return useMemo(() => taxonomies === null || taxonomies === void 0 ? void 0 : taxonomies.filter(_ref7 => {
87
+ const templatePrefixes = useMemo(() => publicPostTypes === null || publicPostTypes === void 0 ? void 0 : publicPostTypes.reduce((accumulator, _ref3) => {
185
88
  let {
186
89
  slug
187
- } = _ref7;
188
- return !specialTaxonomies.includes(slug);
189
- }), [taxonomies]);
190
- };
191
- export const useTaxonomyCategory = () => {
192
- const taxonomies = usePublicTaxonomies();
193
- return useMemo(() => taxonomies === null || taxonomies === void 0 ? void 0 : taxonomies.filter(_ref8 => {
90
+ } = _ref3;
91
+ let suffix = slug;
92
+
93
+ if (slug !== 'page') {
94
+ suffix = `single-${suffix}`;
95
+ }
96
+
97
+ accumulator[slug] = suffix;
98
+ return accumulator;
99
+ }, {}), [publicPostTypes]); // We need to keep track of naming conflicts. If a conflict
100
+ // occurs, we need to add slug.
101
+
102
+ const postTypeLabels = publicPostTypes === null || publicPostTypes === void 0 ? void 0 : publicPostTypes.reduce((accumulator, _ref4) => {
103
+ let {
104
+ labels
105
+ } = _ref4;
106
+ const singularName = labels.singular_name.toLowerCase();
107
+ accumulator[singularName] = (accumulator[singularName] || 0) + 1;
108
+ return accumulator;
109
+ }, {});
110
+
111
+ const needsUniqueIdentifier = (labels, slug) => {
112
+ const singularName = labels.singular_name.toLowerCase();
113
+ return postTypeLabels[singularName] > 1 && singularName !== slug;
114
+ };
115
+
116
+ const postTypesInfo = useEntitiesInfo('postType', templatePrefixes);
117
+ const existingTemplateSlugs = (existingTemplates || []).map(_ref5 => {
194
118
  let {
195
119
  slug
196
- } = _ref8;
197
- return slug === 'category';
198
- }), [taxonomies]);
120
+ } = _ref5;
121
+ return slug;
122
+ });
123
+ const menuItems = (publicPostTypes || []).reduce((accumulator, postType) => {
124
+ var _postTypesInfo$slug;
125
+
126
+ const {
127
+ slug,
128
+ labels,
129
+ icon
130
+ } = postType; // We need to check if the general template is part of the
131
+ // defaultTemplateTypes. If it is, just use that info and
132
+ // augment it with the specific template functionality.
133
+
134
+ const generalTemplateSlug = templatePrefixes[slug];
135
+ const defaultTemplateType = defaultTemplateTypes === null || defaultTemplateTypes === void 0 ? void 0 : defaultTemplateTypes.find(_ref6 => {
136
+ let {
137
+ slug: _slug
138
+ } = _ref6;
139
+ return _slug === generalTemplateSlug;
140
+ });
141
+ const hasGeneralTemplate = existingTemplateSlugs === null || existingTemplateSlugs === void 0 ? void 0 : existingTemplateSlugs.includes(generalTemplateSlug);
142
+
143
+ const _needsUniqueIdentifier = needsUniqueIdentifier(labels, slug);
144
+
145
+ let menuItemTitle = sprintf( // translators: %s: Name of the post type e.g: "Post".
146
+ __('Single item: %s'), labels.singular_name);
147
+
148
+ if (_needsUniqueIdentifier) {
149
+ menuItemTitle = sprintf( // translators: %1s: Name of the post type e.g: "Post"; %2s: Slug of the post type e.g: "book".
150
+ __('Single item: %1$s (%2$s)'), labels.singular_name, slug);
151
+ }
152
+
153
+ const menuItem = defaultTemplateType ? { ...defaultTemplateType
154
+ } : {
155
+ slug: generalTemplateSlug,
156
+ title: menuItemTitle,
157
+ description: sprintf( // translators: %s: Name of the post type e.g: "Post".
158
+ __('Displays a single item: %s.'), labels.singular_name),
159
+ // `icon` is the `menu_icon` property of a post type. We
160
+ // only handle `dashicons` for now, even if the `menu_icon`
161
+ // also supports urls and svg as values.
162
+ icon: icon !== null && icon !== void 0 && icon.startsWith('dashicons-') ? icon.slice(10) : post
163
+ };
164
+ const hasEntities = postTypesInfo === null || postTypesInfo === void 0 ? void 0 : (_postTypesInfo$slug = postTypesInfo[slug]) === null || _postTypesInfo$slug === void 0 ? void 0 : _postTypesInfo$slug.hasEntities; // We have a different template creation flow only if they have entities.
165
+
166
+ if (hasEntities) {
167
+ menuItem.onClick = template => {
168
+ onClickMenuItem({
169
+ type: 'postType',
170
+ slug,
171
+ config: {
172
+ recordNamePath: 'title.rendered',
173
+ queryArgs: _ref7 => {
174
+ let {
175
+ search
176
+ } = _ref7;
177
+ return {
178
+ _fields: 'id,title,slug,link',
179
+ orderBy: search ? 'relevance' : 'modified',
180
+ exclude: postTypesInfo[slug].existingEntitiesIds
181
+ };
182
+ },
183
+ getSpecificTemplate: suggestion => {
184
+ let title = sprintf( // 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. "Page: Hello".
185
+ __('%1$s: %2$s'), labels.singular_name, suggestion.name);
186
+ const description = sprintf( // translators: Represents the description of a user's custom template in the Site Editor, e.g. "Template for Page: Hello"
187
+ __('Template for %1$s'), title);
188
+
189
+ if (_needsUniqueIdentifier) {
190
+ title = sprintf( // translators: Represents the title of a user's custom template in the Site Editor, where %1$s is the template title and %2$s is the slug of the post type, e.g. "Project: Hello (project_type)"
191
+ __('%1$s %2$s'), title, `(${slug})`);
192
+ }
193
+
194
+ return {
195
+ title,
196
+ description,
197
+ slug: `${templatePrefixes[slug]}-${suggestion.slug}`
198
+ };
199
+ }
200
+ },
201
+ labels,
202
+ hasGeneralTemplate,
203
+ template
204
+ });
205
+ };
206
+ } // We don't need to add the menu item if there are no
207
+ // entities and the general template exists.
208
+
209
+
210
+ if (!hasGeneralTemplate || hasEntities) {
211
+ accumulator.push(menuItem);
212
+ }
213
+
214
+ return accumulator;
215
+ }, []); // Split menu items into two groups: one for the default post types
216
+ // and one for the rest.
217
+
218
+ const postTypesMenuItems = useMemo(() => menuItems.reduce((accumulator, postType) => {
219
+ const {
220
+ slug
221
+ } = postType;
222
+ let key = 'postTypesMenuItems';
223
+
224
+ if (slug === 'page') {
225
+ key = 'defaultPostTypesMenuItems';
226
+ }
227
+
228
+ accumulator[key].push(postType);
229
+ return accumulator;
230
+ }, {
231
+ defaultPostTypesMenuItems: [],
232
+ postTypesMenuItems: []
233
+ }), [menuItems]);
234
+ return postTypesMenuItems;
199
235
  };
200
- export const useTaxonomyTag = () => {
201
- const taxonomies = usePublicTaxonomies();
202
- return useMemo(() => taxonomies === null || taxonomies === void 0 ? void 0 : taxonomies.filter(_ref9 => {
236
+ export const useTaxonomiesMenuItems = onClickMenuItem => {
237
+ const publicTaxonomies = usePublicTaxonomies();
238
+ const existingTemplates = useExistingTemplates();
239
+ const defaultTemplateTypes = useDefaultTemplateTypes(); // `category` and `post_tag` are special cases in template hierarchy.
240
+
241
+ const templatePrefixes = useMemo(() => publicTaxonomies === null || publicTaxonomies === void 0 ? void 0 : publicTaxonomies.reduce((accumulator, _ref8) => {
203
242
  let {
204
243
  slug
244
+ } = _ref8;
245
+ let suffix = slug;
246
+
247
+ if (!['category', 'post_tag'].includes(slug)) {
248
+ suffix = `taxonomy-${suffix}`;
249
+ }
250
+
251
+ if (slug === 'post_tag') {
252
+ suffix = `tag`;
253
+ }
254
+
255
+ accumulator[slug] = suffix;
256
+ return accumulator;
257
+ }, {}), [publicTaxonomies]); // We need to keep track of naming conflicts. If a conflict
258
+ // occurs, we need to add slug.
259
+
260
+ const taxonomyLabels = publicTaxonomies === null || publicTaxonomies === void 0 ? void 0 : publicTaxonomies.reduce((accumulator, _ref9) => {
261
+ let {
262
+ labels
205
263
  } = _ref9;
206
- return slug === 'post_tag';
207
- }), [taxonomies]);
264
+ const singularName = labels.singular_name.toLowerCase();
265
+ accumulator[singularName] = (accumulator[singularName] || 0) + 1;
266
+ return accumulator;
267
+ }, {});
268
+
269
+ const needsUniqueIdentifier = (labels, slug) => {
270
+ if (['category', 'post_tag'].includes(slug)) {
271
+ return false;
272
+ }
273
+
274
+ const singularName = labels.singular_name.toLowerCase();
275
+ return taxonomyLabels[singularName] > 1 && singularName !== slug;
276
+ };
277
+
278
+ const taxonomiesInfo = useEntitiesInfo('taxonomy', templatePrefixes);
279
+ const existingTemplateSlugs = (existingTemplates || []).map(_ref10 => {
280
+ let {
281
+ slug
282
+ } = _ref10;
283
+ return slug;
284
+ });
285
+ const menuItems = (publicTaxonomies || []).reduce((accumulator, taxonomy) => {
286
+ var _taxonomiesInfo$slug;
287
+
288
+ const {
289
+ slug,
290
+ labels
291
+ } = taxonomy; // We need to check if the general template is part of the
292
+ // defaultTemplateTypes. If it is, just use that info and
293
+ // augment it with the specific template functionality.
294
+
295
+ const generalTemplateSlug = templatePrefixes[slug];
296
+ const defaultTemplateType = defaultTemplateTypes === null || defaultTemplateTypes === void 0 ? void 0 : defaultTemplateTypes.find(_ref11 => {
297
+ let {
298
+ slug: _slug
299
+ } = _ref11;
300
+ return _slug === generalTemplateSlug;
301
+ });
302
+ const hasGeneralTemplate = existingTemplateSlugs === null || existingTemplateSlugs === void 0 ? void 0 : existingTemplateSlugs.includes(generalTemplateSlug);
303
+
304
+ const _needsUniqueIdentifier = needsUniqueIdentifier(labels, slug);
305
+
306
+ let menuItemTitle = labels.singular_name;
307
+
308
+ if (_needsUniqueIdentifier) {
309
+ menuItemTitle = sprintf( // translators: %1s: Name of the taxonomy e.g: "Category"; %2s: Slug of the taxonomy e.g: "product_cat".
310
+ __('%1$s (%2$s)'), labels.singular_name, slug);
311
+ }
312
+
313
+ const menuItem = defaultTemplateType ? { ...defaultTemplateType
314
+ } : {
315
+ slug: generalTemplateSlug,
316
+ title: menuItemTitle,
317
+ description: sprintf( // translators: %s: Name of the taxonomy e.g: "Product Categories".
318
+ __('Displays taxonomy: %s.'), labels.singular_name),
319
+ icon: blockMeta
320
+ };
321
+ const hasEntities = taxonomiesInfo === null || taxonomiesInfo === void 0 ? void 0 : (_taxonomiesInfo$slug = taxonomiesInfo[slug]) === null || _taxonomiesInfo$slug === void 0 ? void 0 : _taxonomiesInfo$slug.hasEntities; // We have a different template creation flow only if they have entities.
322
+
323
+ if (hasEntities) {
324
+ menuItem.onClick = template => {
325
+ onClickMenuItem({
326
+ type: 'taxonomy',
327
+ slug,
328
+ config: {
329
+ queryArgs: _ref12 => {
330
+ let {
331
+ search
332
+ } = _ref12;
333
+ return {
334
+ _fields: 'id,name,slug,link',
335
+ orderBy: search ? 'name' : 'count',
336
+ exclude: taxonomiesInfo[slug].existingEntitiesIds
337
+ };
338
+ },
339
+ getSpecificTemplate: suggestion => {
340
+ let title = sprintf( // translators: Represents the title of a user's custom template in the Site Editor, where %1$s is the singular name of a taxonomy and %2$s is the name of the term, e.g. "Category: shoes".
341
+ __('%1$s: %2$s'), labels.singular_name, suggestion.name);
342
+ const description = sprintf( // translators: Represents the description of a user's custom template in the Site Editor, e.g. "Template for Category: shoes"
343
+ __('Template for %1$s'), title);
344
+
345
+ if (_needsUniqueIdentifier) {
346
+ title = sprintf( // translators: Represents the title of a user's custom template in the Site Editor, where %1$s is the template title and %2$s is the slug of the taxonomy, e.g. "Category: shoes (product_tag)"
347
+ __('%1$s %2$s'), title, `(${slug})`);
348
+ }
349
+
350
+ return {
351
+ title,
352
+ description,
353
+ slug: `${templatePrefixes[slug]}-${suggestion.slug}`
354
+ };
355
+ }
356
+ },
357
+ labels,
358
+ hasGeneralTemplate,
359
+ template
360
+ });
361
+ };
362
+ } // We don't need to add the menu item if there are no
363
+ // entities and the general template exists.
364
+
365
+
366
+ if (!hasGeneralTemplate || hasEntities) {
367
+ accumulator.push(menuItem);
368
+ }
369
+
370
+ return accumulator;
371
+ }, []); // Split menu items into two groups: one for the default taxonomies
372
+ // and one for the rest.
373
+
374
+ const taxonomiesMenuItems = useMemo(() => menuItems.reduce((accumulator, taxonomy) => {
375
+ const {
376
+ slug
377
+ } = taxonomy;
378
+ let key = 'taxonomiesMenuItems';
379
+
380
+ if (['category', 'tag'].includes(slug)) {
381
+ key = 'defaultTaxonomiesMenuItems';
382
+ }
383
+
384
+ accumulator[key].push(taxonomy);
385
+ return accumulator;
386
+ }, {
387
+ defaultTaxonomiesMenuItems: [],
388
+ taxonomiesMenuItems: []
389
+ }), [menuItems]);
390
+ return taxonomiesMenuItems;
208
391
  };
209
392
  /**
210
- * Helper hook that returns information about an entity having
211
- * records that we can create a specific template for.
393
+ * Helper hook that filters all the existing templates by the given
394
+ * object with the entity's slug as key and the template prefix as value.
212
395
  *
213
- * For example we can search for `terms` in `taxonomy` entity or
214
- * `posts` in `postType` entity.
396
+ * Example:
397
+ * `existingTemplates` is: [ { slug: tag-apple }, { slug: page-about }, { slug: tag } ]
398
+ * `templatePrefixes` is: { post_tag: 'tag' }
399
+ * It will return: { post_tag: [apple] }
215
400
  *
216
- * First we need to find the existing records with an associated template,
217
- * to query afterwards for any remaing record, by excluding them.
401
+ * Note: We append the `-` to the given template prefix in this function for our checks.
218
402
  *
219
- * @param {string[]} existingTemplates The existing templates.
220
- * @param {Object[]} entities The array of entities we need to get extra information.
221
- * @param {EntityConfig} entityConfig The entity config.
222
- * @return {Record<string,EntitiesInfo>} An object with the `entities.slug` as `keys` and EntitiesInfo as values.
403
+ * @param {Record<string,string>} templatePrefixes An object with the entity's slug as key and the template prefix as value.
404
+ * @return {Record<string,string[]>} An object with the entity's slug as key and an array with the existing template slugs as value.
223
405
  */
224
406
 
225
- const useEntitiesInfo = (existingTemplates, entities, _ref10) => {
226
- let {
227
- entityName,
228
- templatePrefix,
229
- templateSlug
230
- } = _ref10;
231
- const slugsToExcludePerEntity = useMemo(() => {
232
- return entities === null || entities === void 0 ? void 0 : entities.reduce((accumulator, entity) => {
233
- let _prefix = `${templateSlug || entity.slug}-`;
234
-
235
- if (templatePrefix) {
236
- _prefix = templatePrefix + _prefix;
237
- }
238
-
407
+ const useExistingTemplateSlugs = templatePrefixes => {
408
+ const existingTemplates = useExistingTemplates();
409
+ const existingSlugs = useMemo(() => {
410
+ return Object.entries(templatePrefixes || {}).reduce((accumulator, _ref13) => {
411
+ let [slug, prefix] = _ref13;
239
412
  const slugsWithTemplates = (existingTemplates || []).reduce((_accumulator, existingTemplate) => {
413
+ const _prefix = `${prefix}-`;
414
+
240
415
  if (existingTemplate.slug.startsWith(_prefix)) {
241
416
  _accumulator.push(existingTemplate.slug.substring(_prefix.length));
242
417
  }
@@ -245,43 +420,70 @@ const useEntitiesInfo = (existingTemplates, entities, _ref10) => {
245
420
  }, []);
246
421
 
247
422
  if (slugsWithTemplates.length) {
248
- accumulator[entity.slug] = slugsWithTemplates;
423
+ accumulator[slug] = slugsWithTemplates;
249
424
  }
250
425
 
251
426
  return accumulator;
252
427
  }, {});
253
- }, [entities, existingTemplates]);
254
- const recordsToExcludePerEntity = useSelect(select => {
255
- if (!slugsToExcludePerEntity) {
256
- return;
257
- }
428
+ }, [templatePrefixes, existingTemplates]);
429
+ return existingSlugs;
430
+ };
431
+ /**
432
+ * Helper hook that finds the existing records with an associated template,
433
+ * as they need to be excluded from the template suggestions.
434
+ *
435
+ * @param {string} entityName The entity's name.
436
+ * @param {Record<string,string>} templatePrefixes An object with the entity's slug as key and the template prefix as value.
437
+ * @return {Record<string,EntitiesInfo>} An object with the entity's slug as key and the existing records as value.
438
+ */
439
+
258
440
 
259
- return Object.entries(slugsToExcludePerEntity).reduce((accumulator, _ref11) => {
260
- let [slug, slugsWithTemplates] = _ref11;
261
- const postsWithTemplates = select(coreStore).getEntityRecords(entityName, slug, {
441
+ const useTemplatesToExclude = (entityName, templatePrefixes) => {
442
+ const slugsToExcludePerEntity = useExistingTemplateSlugs(templatePrefixes);
443
+ const recordsToExcludePerEntity = useSelect(select => {
444
+ return Object.entries(slugsToExcludePerEntity || {}).reduce((accumulator, _ref14) => {
445
+ let [slug, slugsWithTemplates] = _ref14;
446
+ const entitiesWithTemplates = select(coreStore).getEntityRecords(entityName, slug, {
262
447
  _fields: 'id',
263
448
  context: 'view',
264
449
  slug: slugsWithTemplates
265
450
  });
266
451
 
267
- if (postsWithTemplates !== null && postsWithTemplates !== void 0 && postsWithTemplates.length) {
268
- accumulator[slug] = postsWithTemplates;
452
+ if (entitiesWithTemplates !== null && entitiesWithTemplates !== void 0 && entitiesWithTemplates.length) {
453
+ accumulator[slug] = entitiesWithTemplates;
269
454
  }
270
455
 
271
456
  return accumulator;
272
457
  }, {});
273
458
  }, [slugsToExcludePerEntity]);
459
+ return recordsToExcludePerEntity;
460
+ };
461
+ /**
462
+ * Helper hook that returns information about an entity having
463
+ * records that we can create a specific template for.
464
+ *
465
+ * For example we can search for `terms` in `taxonomy` entity or
466
+ * `posts` in `postType` entity.
467
+ *
468
+ * First we need to find the existing records with an associated template,
469
+ * to query afterwards for any remaining record, by excluding them.
470
+ *
471
+ * @param {string} entityName The entity's name.
472
+ * @param {Record<string,string>} templatePrefixes An object with the entity's slug as key and the template prefix as value.
473
+ * @return {Record<string,EntitiesInfo>} An object with the entity's slug as key and the EntitiesInfo as value.
474
+ */
475
+
476
+
477
+ const useEntitiesInfo = (entityName, templatePrefixes) => {
478
+ const recordsToExcludePerEntity = useTemplatesToExclude(entityName, templatePrefixes);
274
479
  const entitiesInfo = useSelect(select => {
275
- return entities === null || entities === void 0 ? void 0 : entities.reduce((accumulator, _ref12) => {
480
+ return Object.keys(templatePrefixes || {}).reduce((accumulator, slug) => {
276
481
  var _recordsToExcludePerE, _select$getEntityReco;
277
482
 
278
- let {
279
- slug
280
- } = _ref12;
281
- const existingEntitiesIds = (recordsToExcludePerEntity === null || recordsToExcludePerEntity === void 0 ? void 0 : (_recordsToExcludePerE = recordsToExcludePerEntity[slug]) === null || _recordsToExcludePerE === void 0 ? void 0 : _recordsToExcludePerE.map(_ref13 => {
483
+ const existingEntitiesIds = (recordsToExcludePerEntity === null || recordsToExcludePerEntity === void 0 ? void 0 : (_recordsToExcludePerE = recordsToExcludePerEntity[slug]) === null || _recordsToExcludePerE === void 0 ? void 0 : _recordsToExcludePerE.map(_ref15 => {
282
484
  let {
283
485
  id
284
- } = _ref13;
486
+ } = _ref15;
285
487
  return id;
286
488
  })) || [];
287
489
  accumulator[slug] = {
@@ -295,71 +497,7 @@ const useEntitiesInfo = (existingTemplates, entities, _ref10) => {
295
497
  };
296
498
  return accumulator;
297
499
  }, {});
298
- }, [entities, recordsToExcludePerEntity]);
500
+ }, [templatePrefixes, recordsToExcludePerEntity]);
299
501
  return entitiesInfo;
300
502
  };
301
-
302
- export const useExtraTemplates = (entities, entityConfig, onClickMenuItem) => {
303
- const existingTemplates = useExistingTemplates();
304
- const defaultTemplateTypes = useDefaultTemplateTypes();
305
- const entitiesInfo = useEntitiesInfo(existingTemplates, entities, entityConfig);
306
- const existingTemplateSlugs = (existingTemplates || []).map(_ref14 => {
307
- let {
308
- slug
309
- } = _ref14;
310
- return slug;
311
- });
312
- const extraTemplates = (entities || []).reduce((accumulator, entity) => {
313
- var _entityConfig$getIcon, _entitiesInfo$slug;
314
-
315
- const {
316
- slug,
317
- labels,
318
- icon
319
- } = entity;
320
- const slugForGeneralTemplate = entityConfig.templateSlug || slug; // We need to check if the general template is part of the
321
- // defaultTemplateTypes. If it is, just use that info and
322
- // augment it with the specific template functionality.
323
-
324
- const defaultTemplateType = defaultTemplateTypes === null || defaultTemplateTypes === void 0 ? void 0 : defaultTemplateTypes.find(_ref15 => {
325
- let {
326
- slug: _slug
327
- } = _ref15;
328
- return _slug === slugForGeneralTemplate;
329
- });
330
- const generalTemplateSlug = (defaultTemplateType === null || defaultTemplateType === void 0 ? void 0 : defaultTemplateType.slug) || `${entityConfig.templatePrefix}${slug}`;
331
- const hasGeneralTemplate = existingTemplateSlugs === null || existingTemplateSlugs === void 0 ? void 0 : existingTemplateSlugs.includes(generalTemplateSlug);
332
- const menuItem = defaultTemplateType ? { ...defaultTemplateType
333
- } : {
334
- slug: generalTemplateSlug,
335
- title: entityConfig.getTitle(labels),
336
- description: entityConfig.getDescription(labels),
337
- icon: (_entityConfig$getIcon = entityConfig.getIcon) === null || _entityConfig$getIcon === void 0 ? void 0 : _entityConfig$getIcon.call(entityConfig, icon)
338
- };
339
- const hasEntities = entitiesInfo === null || entitiesInfo === void 0 ? void 0 : (_entitiesInfo$slug = entitiesInfo[slug]) === null || _entitiesInfo$slug === void 0 ? void 0 : _entitiesInfo$slug.hasEntities; // We have a different template creation flow only if they have entities.
340
-
341
- if (hasEntities) {
342
- menuItem.onClick = template => {
343
- onClickMenuItem({
344
- type: entityConfig.entityName,
345
- slug,
346
- config: entityConfig,
347
- labels,
348
- hasGeneralTemplate,
349
- template,
350
- postsToExclude: entitiesInfo[slug].existingEntitiesIds
351
- });
352
- };
353
- } // We don't need to add the menu item if there are no
354
- // entities and the general template exists.
355
-
356
-
357
- if (!hasGeneralTemplate || hasEntities) {
358
- accumulator.push(menuItem);
359
- }
360
-
361
- return accumulator;
362
- }, []);
363
- return extraTemplates;
364
- };
365
503
  //# sourceMappingURL=utils.js.map