@wordpress/edit-site 6.30.1-next.836ecdcae.0 → 6.31.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 (81) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/add-new-template/add-custom-template-modal-content.js +1 -1
  3. package/build/components/add-new-template/add-custom-template-modal-content.js.map +1 -1
  4. package/build/components/add-new-template/index.js +1 -5
  5. package/build/components/add-new-template/index.js.map +1 -1
  6. package/build/components/add-new-template/utils.js +8 -84
  7. package/build/components/add-new-template/utils.js.map +1 -1
  8. package/build/components/dataviews-actions/index.js +51 -1
  9. package/build/components/dataviews-actions/index.js.map +1 -1
  10. package/build/components/editor/index.js +1 -1
  11. package/build/components/editor/index.js.map +1 -1
  12. package/build/components/editor/use-resolve-edited-entity.js +42 -14
  13. package/build/components/editor/use-resolve-edited-entity.js.map +1 -1
  14. package/build/components/global-styles/screen-root.js +1 -7
  15. package/build/components/global-styles/screen-root.js.map +1 -1
  16. package/build/components/page-templates/fields.js +65 -5
  17. package/build/components/page-templates/fields.js.map +1 -1
  18. package/build/components/page-templates/hooks.js +1 -1
  19. package/build/components/page-templates/hooks.js.map +1 -1
  20. package/build/components/page-templates/index.js +103 -29
  21. package/build/components/page-templates/index.js.map +1 -1
  22. package/build/components/post-list/index.js +1 -4
  23. package/build/components/post-list/index.js.map +1 -1
  24. package/build/components/sidebar-navigation-screen-templates-browse/content.js +11 -5
  25. package/build/components/sidebar-navigation-screen-templates-browse/content.js.map +1 -1
  26. package/build/components/site-editor-routes/index.js +1 -1
  27. package/build/components/site-editor-routes/index.js.map +1 -1
  28. package/build/components/site-editor-routes/template-item.js +29 -23
  29. package/build/components/site-editor-routes/template-item.js.map +1 -1
  30. package/build/hooks/commands/use-common-commands.js +3 -118
  31. package/build/hooks/commands/use-common-commands.js.map +1 -1
  32. package/build-module/components/add-new-template/add-custom-template-modal-content.js +1 -1
  33. package/build-module/components/add-new-template/add-custom-template-modal-content.js.map +1 -1
  34. package/build-module/components/add-new-template/index.js +2 -6
  35. package/build-module/components/add-new-template/index.js.map +1 -1
  36. package/build-module/components/add-new-template/utils.js +8 -84
  37. package/build-module/components/add-new-template/utils.js.map +1 -1
  38. package/build-module/components/dataviews-actions/index.js +49 -0
  39. package/build-module/components/dataviews-actions/index.js.map +1 -1
  40. package/build-module/components/editor/index.js +1 -1
  41. package/build-module/components/editor/index.js.map +1 -1
  42. package/build-module/components/editor/use-resolve-edited-entity.js +42 -14
  43. package/build-module/components/editor/use-resolve-edited-entity.js.map +1 -1
  44. package/build-module/components/global-styles/screen-root.js +1 -7
  45. package/build-module/components/global-styles/screen-root.js.map +1 -1
  46. package/build-module/components/page-templates/fields.js +65 -5
  47. package/build-module/components/page-templates/fields.js.map +1 -1
  48. package/build-module/components/page-templates/hooks.js +1 -1
  49. package/build-module/components/page-templates/hooks.js.map +1 -1
  50. package/build-module/components/page-templates/index.js +105 -31
  51. package/build-module/components/page-templates/index.js.map +1 -1
  52. package/build-module/components/post-list/index.js +1 -4
  53. package/build-module/components/post-list/index.js.map +1 -1
  54. package/build-module/components/sidebar-navigation-screen-templates-browse/content.js +11 -5
  55. package/build-module/components/sidebar-navigation-screen-templates-browse/content.js.map +1 -1
  56. package/build-module/components/site-editor-routes/index.js +2 -2
  57. package/build-module/components/site-editor-routes/index.js.map +1 -1
  58. package/build-module/components/site-editor-routes/template-item.js +28 -22
  59. package/build-module/components/site-editor-routes/template-item.js.map +1 -1
  60. package/build-module/hooks/commands/use-common-commands.js +5 -120
  61. package/build-module/hooks/commands/use-common-commands.js.map +1 -1
  62. package/build-style/posts-rtl.css +17 -10
  63. package/build-style/posts.css +17 -10
  64. package/build-style/style-rtl.css +17 -10
  65. package/build-style/style.css +17 -10
  66. package/package.json +41 -41
  67. package/src/components/add-new-template/add-custom-template-modal-content.js +1 -3
  68. package/src/components/add-new-template/index.js +1 -8
  69. package/src/components/add-new-template/utils.js +9 -118
  70. package/src/components/dataviews-actions/index.js +51 -0
  71. package/src/components/editor/index.js +1 -0
  72. package/src/components/editor/use-resolve-edited-entity.js +54 -7
  73. package/src/components/global-styles/screen-root.js +1 -7
  74. package/src/components/page-templates/fields.js +70 -4
  75. package/src/components/page-templates/hooks.js +1 -1
  76. package/src/components/page-templates/index.js +160 -57
  77. package/src/components/post-list/index.js +1 -2
  78. package/src/components/sidebar-navigation-screen-templates-browse/content.js +17 -7
  79. package/src/components/site-editor-routes/index.js +2 -1
  80. package/src/components/site-editor-routes/template-item.js +34 -26
  81. package/src/hooks/commands/use-common-commands.js +6 -135
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/edit-site",
3
- "version": "6.30.1-next.836ecdcae.0",
3
+ "version": "6.31.0",
4
4
  "description": "Edit Site Page module for WordPress.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -30,45 +30,45 @@
30
30
  "dependencies": {
31
31
  "@babel/runtime": "7.25.7",
32
32
  "@react-spring/web": "^9.4.5",
33
- "@wordpress/a11y": "^4.30.1-next.836ecdcae.0",
34
- "@wordpress/api-fetch": "^7.30.1-next.836ecdcae.0",
35
- "@wordpress/blob": "^4.30.1-next.836ecdcae.0",
36
- "@wordpress/block-editor": "^15.3.1-next.836ecdcae.0",
37
- "@wordpress/block-library": "^9.30.1-next.836ecdcae.0",
38
- "@wordpress/blocks": "^15.3.1-next.836ecdcae.0",
39
- "@wordpress/commands": "^1.30.1-next.836ecdcae.0",
40
- "@wordpress/components": "^30.3.2-next.836ecdcae.0",
41
- "@wordpress/compose": "^7.30.1-next.836ecdcae.0",
42
- "@wordpress/core-data": "^7.30.1-next.836ecdcae.0",
43
- "@wordpress/data": "^10.30.1-next.836ecdcae.0",
44
- "@wordpress/dataviews": "^8.0.2-next.836ecdcae.0",
45
- "@wordpress/date": "^5.30.1-next.836ecdcae.0",
46
- "@wordpress/deprecated": "^4.30.1-next.836ecdcae.0",
47
- "@wordpress/dom": "^4.30.1-next.836ecdcae.0",
48
- "@wordpress/editor": "^14.30.1-next.836ecdcae.0",
49
- "@wordpress/element": "^6.30.1-next.836ecdcae.0",
50
- "@wordpress/escape-html": "^3.30.1-next.836ecdcae.0",
51
- "@wordpress/fields": "^0.22.1-next.836ecdcae.0",
52
- "@wordpress/hooks": "^4.30.1-next.836ecdcae.0",
53
- "@wordpress/html-entities": "^4.30.1-next.836ecdcae.0",
54
- "@wordpress/i18n": "^6.3.1-next.836ecdcae.0",
55
- "@wordpress/icons": "^10.30.1-next.836ecdcae.0",
56
- "@wordpress/keyboard-shortcuts": "^5.30.1-next.836ecdcae.0",
57
- "@wordpress/keycodes": "^4.30.1-next.836ecdcae.0",
58
- "@wordpress/media-utils": "^5.30.1-next.836ecdcae.0",
59
- "@wordpress/notices": "^5.30.1-next.836ecdcae.0",
60
- "@wordpress/patterns": "^2.30.1-next.836ecdcae.0",
61
- "@wordpress/plugins": "^7.30.1-next.836ecdcae.0",
62
- "@wordpress/preferences": "^4.30.1-next.836ecdcae.0",
63
- "@wordpress/primitives": "^4.30.1-next.836ecdcae.0",
64
- "@wordpress/private-apis": "^1.30.1-next.836ecdcae.0",
65
- "@wordpress/reusable-blocks": "^5.30.1-next.836ecdcae.0",
66
- "@wordpress/router": "^1.30.1-next.836ecdcae.0",
67
- "@wordpress/style-engine": "^2.30.1-next.836ecdcae.0",
68
- "@wordpress/url": "^4.30.1-next.836ecdcae.0",
69
- "@wordpress/viewport": "^6.30.1-next.836ecdcae.0",
70
- "@wordpress/widgets": "^4.30.1-next.836ecdcae.0",
71
- "@wordpress/wordcount": "^4.30.1-next.836ecdcae.0",
33
+ "@wordpress/a11y": "^4.31.0",
34
+ "@wordpress/api-fetch": "^7.31.0",
35
+ "@wordpress/blob": "^4.31.0",
36
+ "@wordpress/block-editor": "^15.4.0",
37
+ "@wordpress/block-library": "^9.31.0",
38
+ "@wordpress/blocks": "^15.4.0",
39
+ "@wordpress/commands": "^1.31.0",
40
+ "@wordpress/components": "^30.4.0",
41
+ "@wordpress/compose": "^7.31.0",
42
+ "@wordpress/core-data": "^7.31.0",
43
+ "@wordpress/data": "^10.31.0",
44
+ "@wordpress/dataviews": "^9.0.0",
45
+ "@wordpress/date": "^5.31.0",
46
+ "@wordpress/deprecated": "^4.31.0",
47
+ "@wordpress/dom": "^4.31.0",
48
+ "@wordpress/editor": "^14.31.0",
49
+ "@wordpress/element": "^6.31.0",
50
+ "@wordpress/escape-html": "^3.31.0",
51
+ "@wordpress/fields": "^0.23.0",
52
+ "@wordpress/hooks": "^4.31.0",
53
+ "@wordpress/html-entities": "^4.31.0",
54
+ "@wordpress/i18n": "^6.4.0",
55
+ "@wordpress/icons": "^10.31.0",
56
+ "@wordpress/keyboard-shortcuts": "^5.31.0",
57
+ "@wordpress/keycodes": "^4.31.0",
58
+ "@wordpress/media-utils": "^5.31.0",
59
+ "@wordpress/notices": "^5.31.0",
60
+ "@wordpress/patterns": "^2.31.0",
61
+ "@wordpress/plugins": "^7.31.0",
62
+ "@wordpress/preferences": "^4.31.0",
63
+ "@wordpress/primitives": "^4.31.0",
64
+ "@wordpress/private-apis": "^1.31.0",
65
+ "@wordpress/reusable-blocks": "^5.31.0",
66
+ "@wordpress/router": "^1.31.0",
67
+ "@wordpress/style-engine": "^2.31.0",
68
+ "@wordpress/url": "^4.31.0",
69
+ "@wordpress/viewport": "^6.31.0",
70
+ "@wordpress/widgets": "^4.31.0",
71
+ "@wordpress/wordcount": "^4.31.0",
72
72
  "change-case": "^4.1.2",
73
73
  "clsx": "^2.1.1",
74
74
  "colord": "^2.9.2",
@@ -83,5 +83,5 @@
83
83
  "publishConfig": {
84
84
  "access": "public"
85
85
  },
86
- "gitHead": "3e60b4c1e78d7b27acbf1d7dd172bbd64358a0f2"
86
+ "gitHead": "d7601d30d49462ea942168e8ab6bf449fb93097e"
87
87
  }
@@ -172,9 +172,7 @@ function AddCustomTemplateModalContent( {
172
172
  onBack,
173
173
  containerRef,
174
174
  } ) {
175
- const [ showSearchEntities, setShowSearchEntities ] = useState(
176
- entityForSuggestions.hasGeneralTemplate
177
- );
175
+ const [ showSearchEntities, setShowSearchEntities ] = useState();
178
176
 
179
177
  // Focus on the first focusable element when the modal opens.
180
178
  // We handle focus management in the parent modal, just need to focus on the first focusable element.
@@ -53,7 +53,6 @@ import { TEMPLATE_POST_TYPE } from '../../utils/constants';
53
53
  */
54
54
  import AddCustomTemplateModalContent from './add-custom-template-modal-content';
55
55
  import {
56
- useExistingTemplates,
57
56
  useDefaultTemplateTypes,
58
57
  useTaxonomiesMenuItems,
59
58
  usePostTypeMenuItems,
@@ -387,15 +386,9 @@ function NewTemplate() {
387
386
  }
388
387
 
389
388
  function useMissingTemplates( setEntityForSuggestions, onClick ) {
390
- const existingTemplates = useExistingTemplates();
391
389
  const defaultTemplateTypes = useDefaultTemplateTypes();
392
- const existingTemplateSlugs = ( existingTemplates || [] ).map(
393
- ( { slug } ) => slug
394
- );
395
390
  const missingDefaultTemplates = ( defaultTemplateTypes || [] ).filter(
396
- ( template ) =>
397
- DEFAULT_TEMPLATE_SLUGS.includes( template.slug ) &&
398
- ! existingTemplateSlugs.includes( template.slug )
391
+ ( template ) => DEFAULT_TEMPLATE_SLUGS.includes( template.slug )
399
392
  );
400
393
  const onClickMenuItem = ( _entityForSuggestions ) => {
401
394
  onClick?.();
@@ -189,7 +189,6 @@ export function usePostTypeArchiveMenuItems() {
189
189
 
190
190
  export const usePostTypeMenuItems = ( onClickMenuItem ) => {
191
191
  const publicPostTypes = usePublicPostTypes();
192
- const existingTemplates = useExistingTemplates();
193
192
  const defaultTemplateTypes = useDefaultTemplateTypes();
194
193
  // We need to keep track of naming conflicts. If a conflict
195
194
  // occurs, we need to add slug.
@@ -229,9 +228,6 @@ export const usePostTypeMenuItems = ( onClickMenuItem ) => {
229
228
  [ publicPostTypes ]
230
229
  );
231
230
  const postTypesInfo = useEntitiesInfo( 'postType', templatePrefixes );
232
- const existingTemplateSlugs = ( existingTemplates || [] ).map(
233
- ( { slug } ) => slug
234
- );
235
231
  const menuItems = ( publicPostTypes || [] ).reduce(
236
232
  ( accumulator, postType ) => {
237
233
  const { slug, labels, icon } = postType;
@@ -242,8 +238,6 @@ export const usePostTypeMenuItems = ( onClickMenuItem ) => {
242
238
  const defaultTemplateType = defaultTemplateTypes?.find(
243
239
  ( { slug: _slug } ) => _slug === generalTemplateSlug
244
240
  );
245
- const hasGeneralTemplate =
246
- existingTemplateSlugs?.includes( generalTemplateSlug );
247
241
  const _needsUniqueIdentifier = needsUniqueIdentifier( postType );
248
242
  let menuItemTitle =
249
243
  labels.template_name ||
@@ -321,14 +315,12 @@ export const usePostTypeMenuItems = ( onClickMenuItem ) => {
321
315
  },
322
316
  },
323
317
  labels,
324
- hasGeneralTemplate,
325
318
  template,
326
319
  } );
327
320
  };
328
321
  }
329
- // We don't need to add the menu item if there are no
330
- // entities and the general template exists.
331
- if ( ! hasGeneralTemplate || hasEntities ) {
322
+ // We don't need to add the menu item if there are no entities.
323
+ if ( hasEntities ) {
332
324
  accumulator.push( menuItem );
333
325
  }
334
326
  return accumulator;
@@ -555,7 +547,11 @@ export function useAuthorMenuItem( onClickMenuItem ) {
555
547
  getSpecificTemplate: ( suggestion ) => {
556
548
  const templateSlug = `author-${ suggestion.slug }`;
557
549
  return {
558
- title: templateSlug,
550
+ title: sprintf(
551
+ // translators: %s: Name of the author e.g: "Admin".
552
+ __( 'Author: %s' ),
553
+ suggestion.name
554
+ ),
559
555
  slug: templateSlug,
560
556
  templatePrefix: 'author',
561
557
  };
@@ -577,91 +573,6 @@ export function useAuthorMenuItem( onClickMenuItem ) {
577
573
  }
578
574
  }
579
575
 
580
- /**
581
- * Helper hook that filters all the existing templates by the given
582
- * object with the entity's slug as key and the template prefix as value.
583
- *
584
- * Example:
585
- * `existingTemplates` is: [ { slug: 'tag-apple' }, { slug: 'page-about' }, { slug: 'tag' } ]
586
- * `templatePrefixes` is: { post_tag: 'tag' }
587
- * It will return: { post_tag: ['apple'] }
588
- *
589
- * Note: We append the `-` to the given template prefix in this function for our checks.
590
- *
591
- * @param {Record<string,string>} templatePrefixes An object with the entity's slug as key and the template prefix as value.
592
- * @return {Record<string,string[]>} An object with the entity's slug as key and an array with the existing template slugs as value.
593
- */
594
- const useExistingTemplateSlugs = ( templatePrefixes ) => {
595
- const existingTemplates = useExistingTemplates();
596
- const existingSlugs = useMemo( () => {
597
- return Object.entries( templatePrefixes || {} ).reduce(
598
- ( accumulator, [ slug, prefix ] ) => {
599
- const slugsWithTemplates = ( existingTemplates || [] ).reduce(
600
- ( _accumulator, existingTemplate ) => {
601
- const _prefix = `${ prefix }-`;
602
- if ( existingTemplate.slug.startsWith( _prefix ) ) {
603
- _accumulator.push(
604
- existingTemplate.slug.substring(
605
- _prefix.length
606
- )
607
- );
608
- }
609
- return _accumulator;
610
- },
611
- []
612
- );
613
- if ( slugsWithTemplates.length ) {
614
- accumulator[ slug ] = slugsWithTemplates;
615
- }
616
- return accumulator;
617
- },
618
- {}
619
- );
620
- }, [ templatePrefixes, existingTemplates ] );
621
- return existingSlugs;
622
- };
623
-
624
- /**
625
- * Helper hook that finds the existing records with an associated template,
626
- * as they need to be excluded from the template suggestions.
627
- *
628
- * @param {string} entityName The entity's name.
629
- * @param {Record<string,string>} templatePrefixes An object with the entity's slug as key and the template prefix as value.
630
- * @param {Record<string,Object>} additionalQueryParameters An object with the entity's slug as key and additional query parameters as value.
631
- * @return {Record<string,EntitiesInfo>} An object with the entity's slug as key and the existing records as value.
632
- */
633
- const useTemplatesToExclude = (
634
- entityName,
635
- templatePrefixes,
636
- additionalQueryParameters = {}
637
- ) => {
638
- const slugsToExcludePerEntity =
639
- useExistingTemplateSlugs( templatePrefixes );
640
- const recordsToExcludePerEntity = useSelect(
641
- ( select ) => {
642
- return Object.entries( slugsToExcludePerEntity || {} ).reduce(
643
- ( accumulator, [ slug, slugsWithTemplates ] ) => {
644
- const entitiesWithTemplates = select(
645
- coreStore
646
- ).getEntityRecords( entityName, slug, {
647
- _fields: 'id',
648
- context: 'view',
649
- slug: slugsWithTemplates,
650
- ...additionalQueryParameters[ slug ],
651
- } );
652
- if ( entitiesWithTemplates?.length ) {
653
- accumulator[ slug ] = entitiesWithTemplates;
654
- }
655
- return accumulator;
656
- },
657
- {}
658
- );
659
- },
660
- [ slugsToExcludePerEntity ]
661
- );
662
- return recordsToExcludePerEntity;
663
- };
664
-
665
576
  /**
666
577
  * Helper hook that returns information about an entity having
667
578
  * records that we can create a specific template for.
@@ -682,26 +593,16 @@ const useEntitiesInfo = (
682
593
  templatePrefixes,
683
594
  additionalQueryParameters = EMPTY_OBJECT
684
595
  ) => {
685
- const recordsToExcludePerEntity = useTemplatesToExclude(
686
- entityName,
687
- templatePrefixes,
688
- additionalQueryParameters
689
- );
690
596
  const entitiesHasRecords = useSelect(
691
597
  ( select ) => {
692
598
  return Object.keys( templatePrefixes || {} ).reduce(
693
599
  ( accumulator, slug ) => {
694
- const existingEntitiesIds =
695
- recordsToExcludePerEntity?.[ slug ]?.map(
696
- ( { id } ) => id
697
- ) || [];
698
600
  accumulator[ slug ] = !! select(
699
601
  coreStore
700
602
  ).getEntityRecords( entityName, slug, {
701
603
  per_page: 1,
702
604
  _fields: 'id',
703
605
  context: 'view',
704
- exclude: existingEntitiesIds,
705
606
  ...additionalQueryParameters[ slug ],
706
607
  } )?.length;
707
608
  return accumulator;
@@ -709,28 +610,18 @@ const useEntitiesInfo = (
709
610
  {}
710
611
  );
711
612
  },
712
- [
713
- templatePrefixes,
714
- recordsToExcludePerEntity,
715
- entityName,
716
- additionalQueryParameters,
717
- ]
613
+ [ templatePrefixes, entityName, additionalQueryParameters ]
718
614
  );
719
615
  const entitiesInfo = useMemo( () => {
720
616
  return Object.keys( templatePrefixes || {} ).reduce(
721
617
  ( accumulator, slug ) => {
722
- const existingEntitiesIds =
723
- recordsToExcludePerEntity?.[ slug ]?.map(
724
- ( { id } ) => id
725
- ) || [];
726
618
  accumulator[ slug ] = {
727
619
  hasEntities: entitiesHasRecords[ slug ],
728
- existingEntitiesIds,
729
620
  };
730
621
  return accumulator;
731
622
  },
732
623
  {}
733
624
  );
734
- }, [ templatePrefixes, recordsToExcludePerEntity, entitiesHasRecords ] );
625
+ }, [ templatePrefixes, entitiesHasRecords ] );
735
626
  return entitiesInfo;
736
627
  };
@@ -5,6 +5,8 @@ import { __ } from '@wordpress/i18n';
5
5
  import { edit } from '@wordpress/icons';
6
6
  import { useMemo } from '@wordpress/element';
7
7
  import { privateApis as routerPrivateApis } from '@wordpress/router';
8
+ import { useDispatch, useSelect } from '@wordpress/data';
9
+ import { store as coreStore } from '@wordpress/core-data';
8
10
 
9
11
  /**
10
12
  * Internal dependencies
@@ -14,6 +16,55 @@ import { unlock } from '../../lock-unlock';
14
16
 
15
17
  const { useHistory } = unlock( routerPrivateApis );
16
18
 
19
+ export const useSetActiveTemplateAction = () => {
20
+ const { getEntityRecord } = useSelect( coreStore );
21
+ const { editEntityRecord, saveEditedEntityRecord } =
22
+ useDispatch( coreStore );
23
+ return useMemo(
24
+ () => ( {
25
+ id: 'set-active-template',
26
+ label( items ) {
27
+ return items.some( ( item ) => item._isActive )
28
+ ? __( 'Deactivate' )
29
+ : __( 'Activate' );
30
+ },
31
+ isPrimary: true,
32
+ icon: edit,
33
+ isEligible( item ) {
34
+ return ! ( item.slug === 'index' && item.source === 'theme' );
35
+ },
36
+ async callback( items ) {
37
+ const deactivate = items.some( ( item ) => item._isActive );
38
+ // current active templates
39
+ const activeTemplates = {
40
+ ...( ( await getEntityRecord( 'root', 'site' )
41
+ .active_templates ) ?? {} ),
42
+ };
43
+ for ( const item of items ) {
44
+ if ( deactivate ) {
45
+ if ( item.source === 'theme' ) {
46
+ activeTemplates[ item.slug ] = false;
47
+ } else {
48
+ delete activeTemplates[ item.slug ];
49
+ }
50
+ } else {
51
+ activeTemplates[ item.slug ] = item.id;
52
+ }
53
+ }
54
+ // To do: figure out why the REST API deletes the option when
55
+ // it's set to an empty object. That would trigger the migration
56
+ // function, which will make all templates in the database active.
57
+ activeTemplates.__preventCollapse = 0;
58
+ await editEntityRecord( 'root', 'site', undefined, {
59
+ active_templates: activeTemplates,
60
+ } );
61
+ await saveEditedEntityRecord( 'root', 'site' );
62
+ },
63
+ } ),
64
+ [ editEntityRecord, saveEditedEntityRecord, getEntityRecord ]
65
+ );
66
+ };
67
+
17
68
  export const useEditPostAction = () => {
18
69
  const history = useHistory();
19
70
  return useMemo(
@@ -110,6 +110,7 @@ function getNavigationPath( location, postType ) {
110
110
  'template-part-item',
111
111
  'page-item',
112
112
  'template-item',
113
+ 'static-template-item',
113
114
  'post-item',
114
115
  ].includes( name )
115
116
  ) {
@@ -25,13 +25,12 @@ const postTypesWithoutParentTemplate = [
25
25
  TEMPLATE_PART_POST_TYPE,
26
26
  NAVIGATION_POST_TYPE,
27
27
  PATTERN_TYPES.user,
28
+ 'wp_registered_template',
28
29
  ];
29
30
 
30
31
  const authorizedPostTypes = [ 'page', 'post' ];
31
32
 
32
- export function useResolveEditedEntity() {
33
- const { name, params = {}, query } = useLocation();
34
- const { postId = query?.postId } = params; // Fallback to query param for postId for list view routes.
33
+ function getPostType( name, postId ) {
35
34
  let postType;
36
35
  if ( name === 'navigation-item' ) {
37
36
  postType = NAVIGATION_POST_TYPE;
@@ -39,19 +38,48 @@ export function useResolveEditedEntity() {
39
38
  postType = PATTERN_TYPES.user;
40
39
  } else if ( name === 'template-part-item' ) {
41
40
  postType = TEMPLATE_PART_POST_TYPE;
42
- } else if ( name === 'template-item' || name === 'templates' ) {
41
+ } else if ( name === 'templates' ) {
42
+ postType = /^\d+$/.test( postId )
43
+ ? TEMPLATE_POST_TYPE
44
+ : 'wp_registered_template';
45
+ } else if ( name === 'template-item' ) {
43
46
  postType = TEMPLATE_POST_TYPE;
47
+ } else if ( name === 'static-template-item' ) {
48
+ postType = 'wp_registered_template';
44
49
  } else if ( name === 'page-item' || name === 'pages' ) {
45
50
  postType = 'page';
46
51
  } else if ( name === 'post-item' || name === 'posts' ) {
47
52
  postType = 'post';
48
53
  }
49
54
 
55
+ return postType;
56
+ }
57
+
58
+ export function useResolveEditedEntity() {
59
+ const { name, params = {}, query } = useLocation();
60
+ const { postId: _postId = query?.postId } = params; // Fallback to query param for postId for list view routes.
61
+ const _postType = getPostType( name, _postId ) ?? query?.postType;
62
+
50
63
  const homePage = useSelect( ( select ) => {
51
64
  const { getHomePage } = unlock( select( coreDataStore ) );
52
65
  return getHomePage();
53
66
  }, [] );
54
67
 
68
+ const [ postType, postId ] = useSelect(
69
+ ( select ) => {
70
+ if ( _postType !== 'wp_registered_template' ) {
71
+ return [ _postType, _postId ];
72
+ }
73
+ return [
74
+ TEMPLATE_POST_TYPE,
75
+ unlock( select( coreDataStore ) ).getTemplateAutoDraftId(
76
+ _postId
77
+ ),
78
+ ];
79
+ },
80
+ [ _postType, _postId ]
81
+ );
82
+
55
83
  /**
56
84
  * This is a hook that recreates the logic to resolve a template for a given WordPress postID postTypeId
57
85
  * in order to match the frontend as closely as possible in the site editor.
@@ -98,6 +126,18 @@ export function useResolveEditedEntity() {
98
126
  [ homePage, postId, postType ]
99
127
  );
100
128
 
129
+ const editableResolvedTemplateId = useSelect(
130
+ ( select ) => {
131
+ if ( typeof resolvedTemplateId !== 'string' ) {
132
+ return resolvedTemplateId;
133
+ }
134
+ return unlock( select( coreDataStore ) ).getTemplateAutoDraftId(
135
+ resolvedTemplateId
136
+ );
137
+ },
138
+ [ resolvedTemplateId ]
139
+ );
140
+
101
141
  const context = useMemo( () => {
102
142
  if ( postTypesWithoutParentTemplate.includes( postType ) && postId ) {
103
143
  return {};
@@ -121,9 +161,9 @@ export function useResolveEditedEntity() {
121
161
 
122
162
  if ( !! homePage ) {
123
163
  return {
124
- isReady: resolvedTemplateId !== undefined,
164
+ isReady: editableResolvedTemplateId !== undefined,
125
165
  postType: TEMPLATE_POST_TYPE,
126
- postId: resolvedTemplateId,
166
+ postId: editableResolvedTemplateId,
127
167
  context,
128
168
  };
129
169
  }
@@ -141,7 +181,14 @@ export function useSyncDeprecatedEntityIntoState( {
141
181
 
142
182
  useEffect( () => {
143
183
  if ( isReady ) {
144
- setEditedEntity( postType, postId, context );
184
+ // setEditedEntity expects a string (because the postId used to be
185
+ // the template slug, even for edited templates). Now the postId can
186
+ // be a number (either because it's an auto-draft or edited
187
+ // template). Passing a number could break plugins doing things like
188
+ // `id.includes`. It would be way more complex to keep passing the
189
+ // template slug, while also being incorrect, so the easiest
190
+ // solution is to cast the postId to a string.
191
+ setEditedEntity( postType, String( postId ), context );
145
192
  }
146
193
  }, [ isReady, postType, postId, context, setEditedEntity ] );
147
194
  }
@@ -16,7 +16,6 @@ import { isRTL, __ } from '@wordpress/i18n';
16
16
  import { chevronLeft, chevronRight } from '@wordpress/icons';
17
17
  import { useSelect } from '@wordpress/data';
18
18
  import { store as coreStore } from '@wordpress/core-data';
19
- import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor';
20
19
 
21
20
  /**
22
21
  * Internal dependencies
@@ -25,13 +24,8 @@ import { IconWithCurrentColor } from './icon-with-current-color';
25
24
  import { NavigationButtonAsItem } from './navigation-button';
26
25
  import RootMenu from './root-menu';
27
26
  import PreviewStyles from './preview-styles';
28
- import { unlock } from '../../lock-unlock';
29
-
30
- const { useGlobalStyle } = unlock( blockEditorPrivateApis );
31
27
 
32
28
  function ScreenRoot() {
33
- const [ customCSS ] = useGlobalStyle( 'css' );
34
-
35
29
  const { hasVariations, canEditCSS } = useSelect( ( select ) => {
36
30
  const {
37
31
  getEntityRecord,
@@ -116,7 +110,7 @@ function ScreenRoot() {
116
110
  </ItemGroup>
117
111
  </CardBody>
118
112
 
119
- { canEditCSS && !! customCSS && (
113
+ { canEditCSS && (
120
114
  <>
121
115
  <CardDivider />
122
116
  <CardBody>
@@ -6,7 +6,11 @@ import clsx from 'clsx';
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
- import { Icon, __experimentalHStack as HStack } from '@wordpress/components';
9
+ import {
10
+ Icon,
11
+ __experimentalHStack as HStack,
12
+ privateApis as componentsPrivateApis,
13
+ } from '@wordpress/components';
10
14
  import { __ } from '@wordpress/i18n';
11
15
  import { useState, useMemo } from '@wordpress/element';
12
16
  import { decodeEntities } from '@wordpress/html-entities';
@@ -16,15 +20,40 @@ import {
16
20
  privateApis as blockEditorPrivateApis,
17
21
  } from '@wordpress/block-editor';
18
22
  import { EditorProvider } from '@wordpress/editor';
23
+ import { privateApis as corePrivateApis } from '@wordpress/core-data';
19
24
 
20
25
  /**
21
26
  * Internal dependencies
22
27
  */
23
28
  import { useAddedBy } from './hooks';
29
+ import { useDefaultTemplateTypes } from '../add-new-template/utils';
24
30
  import usePatternSettings from '../page-patterns/use-pattern-settings';
25
31
  import { unlock } from '../../lock-unlock';
26
32
 
27
33
  const { useGlobalStyle } = unlock( blockEditorPrivateApis );
34
+ const { Badge } = unlock( componentsPrivateApis );
35
+ const { useEntityRecordsWithPermissions } = unlock( corePrivateApis );
36
+
37
+ function useAllDefaultTemplateTypes() {
38
+ const defaultTemplateTypes = useDefaultTemplateTypes();
39
+ const { records: staticRecords } = useEntityRecordsWithPermissions(
40
+ 'postType',
41
+ 'wp_registered_template',
42
+ { per_page: -1 }
43
+ );
44
+ return [
45
+ ...defaultTemplateTypes,
46
+ ...staticRecords
47
+ ?.filter( ( record ) => ! record.is_custom )
48
+ .map( ( record ) => {
49
+ return {
50
+ slug: record.slug,
51
+ title: record.title.rendered,
52
+ description: record.description,
53
+ };
54
+ } ),
55
+ ];
56
+ }
28
57
 
29
58
  function PreviewField( { item } ) {
30
59
  const settings = usePatternSettings();
@@ -68,8 +97,14 @@ export const previewField = {
68
97
  export const descriptionField = {
69
98
  label: __( 'Description' ),
70
99
  id: 'description',
71
- render: ( { item } ) => {
72
- return item.description && decodeEntities( item.description );
100
+ render: function RenderDescription( { item } ) {
101
+ const defaultTemplateTypes = useAllDefaultTemplateTypes();
102
+ const defaultTemplateType = defaultTemplateTypes.find(
103
+ ( type ) => type.slug === item.slug
104
+ );
105
+ return item.description
106
+ ? decodeEntities( item.description )
107
+ : defaultTemplateType?.description;
73
108
  },
74
109
  enableSorting: false,
75
110
  enableGlobalSearch: true,
@@ -107,6 +142,37 @@ function AuthorField( { item } ) {
107
142
  export const authorField = {
108
143
  label: __( 'Author' ),
109
144
  id: 'author',
110
- getValue: ( { item } ) => item.author_text,
145
+ getValue: ( { item } ) => item.author_text ?? item.author,
111
146
  render: AuthorField,
112
147
  };
148
+
149
+ export const activeField = {
150
+ label: __( 'Status' ),
151
+ id: 'active',
152
+ getValue: ( { item } ) => item._isActive,
153
+ render: function Render( { item } ) {
154
+ const isActive = item._isActive;
155
+ return (
156
+ <Badge intent={ isActive ? 'success' : 'default' }>
157
+ { isActive ? __( 'Active' ) : __( 'Inactive' ) }
158
+ </Badge>
159
+ );
160
+ },
161
+ };
162
+
163
+ export const slugField = {
164
+ label: __( 'Template Type' ),
165
+ id: 'slug',
166
+ getValue: ( { item } ) => item.slug,
167
+ render: function Render( { item } ) {
168
+ const defaultTemplateTypes = useAllDefaultTemplateTypes();
169
+ const defaultTemplateType = defaultTemplateTypes.find(
170
+ ( type ) => type.slug === item.slug
171
+ );
172
+ return (
173
+ defaultTemplateType?.title ||
174
+ // translators: %s is the slug of a custom template.
175
+ __( 'Custom' )
176
+ );
177
+ },
178
+ };
@@ -89,7 +89,7 @@ export function useAddedBy( postType, postId ) {
89
89
  type: 'user',
90
90
  icon: authorIcon,
91
91
  imageUrl: user?.avatar_urls?.[ 48 ],
92
- text: authorText,
92
+ text: authorText ?? user?.name,
93
93
  isCustomized: false,
94
94
  };
95
95
  }