@wordpress/edit-site 3.0.26 → 3.0.29

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 (130) hide show
  1. package/build/components/add-new-template/new-template-part.js +4 -1
  2. package/build/components/add-new-template/new-template-part.js.map +1 -1
  3. package/build/components/editor/global-styles-renderer.js +7 -3
  4. package/build/components/editor/global-styles-renderer.js.map +1 -1
  5. package/build/components/error-boundary/index.js +11 -27
  6. package/build/components/error-boundary/index.js.map +1 -1
  7. package/build/components/error-boundary/warning.js +70 -0
  8. package/build/components/error-boundary/warning.js.map +1 -0
  9. package/build/components/global-styles/screen-background-color.js +8 -9
  10. package/build/components/global-styles/screen-background-color.js.map +1 -1
  11. package/build/components/global-styles/screen-link-color.js +6 -10
  12. package/build/components/global-styles/screen-link-color.js.map +1 -1
  13. package/build/components/global-styles/screen-text-color.js +6 -10
  14. package/build/components/global-styles/screen-text-color.js.map +1 -1
  15. package/build/components/header/more-menu/index.js +68 -39
  16. package/build/components/header/more-menu/index.js.map +1 -1
  17. package/build/{plugins → components/header/more-menu}/site-export.js +0 -0
  18. package/build/components/header/more-menu/site-export.js.map +1 -0
  19. package/build/{plugins → components/header/more-menu}/welcome-guide-menu-item.js +1 -1
  20. package/build/components/header/more-menu/welcome-guide-menu-item.js.map +1 -0
  21. package/build/components/header/tools-more-menu-group/index.js +1 -5
  22. package/build/components/header/tools-more-menu-group/index.js.map +1 -1
  23. package/build/components/keyboard-shortcut-help-modal/config.js +45 -0
  24. package/build/components/keyboard-shortcut-help-modal/config.js.map +1 -0
  25. package/build/components/keyboard-shortcut-help-modal/dynamic-shortcut.js +56 -0
  26. package/build/components/keyboard-shortcut-help-modal/dynamic-shortcut.js.map +1 -0
  27. package/build/components/keyboard-shortcut-help-modal/index.js +137 -0
  28. package/build/components/keyboard-shortcut-help-modal/index.js.map +1 -0
  29. package/build/components/keyboard-shortcut-help-modal/shortcut.js +65 -0
  30. package/build/components/keyboard-shortcut-help-modal/shortcut.js.map +1 -0
  31. package/build/components/keyboard-shortcuts/index.js +9 -0
  32. package/build/components/keyboard-shortcuts/index.js.map +1 -1
  33. package/build/components/list/added-by.js +51 -50
  34. package/build/components/list/added-by.js.map +1 -1
  35. package/build/components/list/table.js +3 -1
  36. package/build/components/list/table.js.map +1 -1
  37. package/build/components/routes/redirect-to-homepage.js +106 -0
  38. package/build/components/routes/redirect-to-homepage.js.map +1 -0
  39. package/build/components/template-part-converter/convert-to-template-part.js +4 -1
  40. package/build/components/template-part-converter/convert-to-template-part.js.map +1 -1
  41. package/build/components/url-query-controller/index.js +1 -38
  42. package/build/components/url-query-controller/index.js.map +1 -1
  43. package/build/index.js +23 -4
  44. package/build/index.js.map +1 -1
  45. package/build/store/actions.js +7 -25
  46. package/build/store/actions.js.map +1 -1
  47. package/build-module/components/add-new-template/new-template-part.js +4 -1
  48. package/build-module/components/add-new-template/new-template-part.js.map +1 -1
  49. package/build-module/components/editor/global-styles-renderer.js +6 -3
  50. package/build-module/components/editor/global-styles-renderer.js.map +1 -1
  51. package/build-module/components/error-boundary/index.js +9 -26
  52. package/build-module/components/error-boundary/index.js.map +1 -1
  53. package/build-module/components/error-boundary/warning.js +60 -0
  54. package/build-module/components/error-boundary/warning.js.map +1 -0
  55. package/build-module/components/global-styles/screen-background-color.js +8 -10
  56. package/build-module/components/global-styles/screen-background-color.js.map +1 -1
  57. package/build-module/components/global-styles/screen-link-color.js +7 -11
  58. package/build-module/components/global-styles/screen-link-color.js.map +1 -1
  59. package/build-module/components/global-styles/screen-text-color.js +7 -11
  60. package/build-module/components/global-styles/screen-text-color.js.map +1 -1
  61. package/build-module/components/header/more-menu/index.js +65 -40
  62. package/build-module/components/header/more-menu/index.js.map +1 -1
  63. package/build-module/{plugins → components/header/more-menu}/site-export.js +0 -0
  64. package/build-module/components/header/more-menu/site-export.js.map +1 -0
  65. package/build-module/{plugins → components/header/more-menu}/welcome-guide-menu-item.js +1 -1
  66. package/build-module/components/header/more-menu/welcome-guide-menu-item.js.map +1 -0
  67. package/build-module/components/header/tools-more-menu-group/index.js +2 -5
  68. package/build-module/components/header/tools-more-menu-group/index.js.map +1 -1
  69. package/build-module/components/keyboard-shortcut-help-modal/config.js +36 -0
  70. package/build-module/components/keyboard-shortcut-help-modal/config.js.map +1 -0
  71. package/build-module/components/keyboard-shortcut-help-modal/dynamic-shortcut.js +44 -0
  72. package/build-module/components/keyboard-shortcut-help-modal/dynamic-shortcut.js.map +1 -0
  73. package/build-module/components/keyboard-shortcut-help-modal/index.js +120 -0
  74. package/build-module/components/keyboard-shortcut-help-modal/index.js.map +1 -0
  75. package/build-module/components/keyboard-shortcut-help-modal/shortcut.js +58 -0
  76. package/build-module/components/keyboard-shortcut-help-modal/shortcut.js.map +1 -0
  77. package/build-module/components/keyboard-shortcuts/index.js +9 -0
  78. package/build-module/components/keyboard-shortcuts/index.js.map +1 -1
  79. package/build-module/components/list/added-by.js +52 -51
  80. package/build-module/components/list/added-by.js.map +1 -1
  81. package/build-module/components/list/table.js +2 -1
  82. package/build-module/components/list/table.js.map +1 -1
  83. package/build-module/components/routes/redirect-to-homepage.js +94 -0
  84. package/build-module/components/routes/redirect-to-homepage.js.map +1 -0
  85. package/build-module/components/template-part-converter/convert-to-template-part.js +4 -1
  86. package/build-module/components/template-part-converter/convert-to-template-part.js.map +1 -1
  87. package/build-module/components/url-query-controller/index.js +3 -40
  88. package/build-module/components/url-query-controller/index.js.map +1 -1
  89. package/build-module/index.js +20 -3
  90. package/build-module/index.js.map +1 -1
  91. package/build-module/store/actions.js +7 -23
  92. package/build-module/store/actions.js.map +1 -1
  93. package/build-style/style-rtl.css +51 -0
  94. package/build-style/style.css +51 -0
  95. package/package.json +13 -13
  96. package/src/components/add-new-template/new-template-part.js +7 -1
  97. package/src/components/editor/global-styles-renderer.js +7 -1
  98. package/src/components/error-boundary/index.js +11 -28
  99. package/src/components/error-boundary/warning.js +59 -0
  100. package/src/components/global-styles/screen-background-color.js +6 -9
  101. package/src/components/global-styles/screen-link-color.js +6 -14
  102. package/src/components/global-styles/screen-text-color.js +6 -14
  103. package/src/components/header/more-menu/index.js +103 -44
  104. package/src/{plugins → components/header/more-menu}/site-export.js +0 -0
  105. package/src/{plugins → components/header/more-menu}/welcome-guide-menu-item.js +1 -1
  106. package/src/components/header/tools-more-menu-group/index.js +2 -7
  107. package/src/components/keyboard-shortcut-help-modal/config.js +27 -0
  108. package/src/components/keyboard-shortcut-help-modal/dynamic-shortcut.js +41 -0
  109. package/src/components/keyboard-shortcut-help-modal/index.js +135 -0
  110. package/src/components/keyboard-shortcut-help-modal/shortcut.js +73 -0
  111. package/src/components/keyboard-shortcut-help-modal/style.scss +66 -0
  112. package/src/components/keyboard-shortcuts/index.js +10 -0
  113. package/src/components/list/added-by.js +57 -63
  114. package/src/components/list/table.js +5 -2
  115. package/src/components/routes/redirect-to-homepage.js +94 -0
  116. package/src/components/template-part-converter/convert-to-template-part.js +6 -1
  117. package/src/components/url-query-controller/index.js +3 -35
  118. package/src/index.js +25 -2
  119. package/src/store/actions.js +7 -35
  120. package/src/store/test/actions.js +0 -90
  121. package/src/style.scss +1 -0
  122. package/build/plugins/index.js +0 -28
  123. package/build/plugins/index.js.map +0 -1
  124. package/build/plugins/site-export.js.map +0 -1
  125. package/build/plugins/welcome-guide-menu-item.js.map +0 -1
  126. package/build-module/plugins/index.js +0 -20
  127. package/build-module/plugins/index.js.map +0 -1
  128. package/build-module/plugins/site-export.js.map +0 -1
  129. package/build-module/plugins/welcome-guide-menu-item.js.map +0 -1
  130. package/src/plugins/index.js +0 -24
@@ -0,0 +1,135 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import classnames from 'classnames';
5
+ import { isString } from 'lodash';
6
+
7
+ /**
8
+ * WordPress dependencies
9
+ */
10
+ import { Modal } from '@wordpress/components';
11
+ import { __ } from '@wordpress/i18n';
12
+ import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts';
13
+ import { useSelect } from '@wordpress/data';
14
+
15
+ /**
16
+ * Internal dependencies
17
+ */
18
+ import { textFormattingShortcuts } from './config';
19
+ import Shortcut from './shortcut';
20
+ import DynamicShortcut from './dynamic-shortcut';
21
+
22
+ const ShortcutList = ( { shortcuts } ) => (
23
+ /*
24
+ * Disable reason: The `list` ARIA role is redundant but
25
+ * Safari+VoiceOver won't announce the list otherwise.
26
+ */
27
+ /* eslint-disable jsx-a11y/no-redundant-roles */
28
+ <ul
29
+ className="edit-site-keyboard-shortcut-help-modal__shortcut-list"
30
+ role="list"
31
+ >
32
+ { shortcuts.map( ( shortcut, index ) => (
33
+ <li
34
+ className="edit-site-keyboard-shortcut-help-modal__shortcut"
35
+ key={ index }
36
+ >
37
+ { isString( shortcut ) ? (
38
+ <DynamicShortcut name={ shortcut } />
39
+ ) : (
40
+ <Shortcut { ...shortcut } />
41
+ ) }
42
+ </li>
43
+ ) ) }
44
+ </ul>
45
+ /* eslint-enable jsx-a11y/no-redundant-roles */
46
+ );
47
+
48
+ const ShortcutSection = ( { title, shortcuts, className } ) => (
49
+ <section
50
+ className={ classnames(
51
+ 'edit-site-keyboard-shortcut-help-modal__section',
52
+ className
53
+ ) }
54
+ >
55
+ { !! title && (
56
+ <h2 className="edit-site-keyboard-shortcut-help-modal__section-title">
57
+ { title }
58
+ </h2>
59
+ ) }
60
+ <ShortcutList shortcuts={ shortcuts } />
61
+ </section>
62
+ );
63
+
64
+ const ShortcutCategorySection = ( {
65
+ title,
66
+ categoryName,
67
+ additionalShortcuts = [],
68
+ } ) => {
69
+ const categoryShortcuts = useSelect(
70
+ ( select ) => {
71
+ return select( keyboardShortcutsStore ).getCategoryShortcuts(
72
+ categoryName
73
+ );
74
+ },
75
+ [ categoryName ]
76
+ );
77
+
78
+ return (
79
+ <ShortcutSection
80
+ title={ title }
81
+ shortcuts={ categoryShortcuts.concat( additionalShortcuts ) }
82
+ />
83
+ );
84
+ };
85
+
86
+ export default function KeyboardShortcutHelpModal( {
87
+ isModalActive,
88
+ toggleModal,
89
+ } ) {
90
+ if ( ! isModalActive ) {
91
+ return null;
92
+ }
93
+
94
+ return (
95
+ <Modal
96
+ className="edit-site-keyboard-shortcut-help-modal"
97
+ title={ __( 'Keyboard shortcuts' ) }
98
+ closeLabel={ __( 'Close' ) }
99
+ onRequestClose={ toggleModal }
100
+ >
101
+ <ShortcutSection
102
+ className="edit-site-keyboard-shortcut-help-modal__main-shortcuts"
103
+ shortcuts={ [ 'core/edit-site/keyboard-shortcuts' ] }
104
+ />
105
+ <ShortcutCategorySection
106
+ title={ __( 'Global shortcuts' ) }
107
+ categoryName="global"
108
+ />
109
+
110
+ <ShortcutCategorySection
111
+ title={ __( 'Selection shortcuts' ) }
112
+ categoryName="selection"
113
+ />
114
+
115
+ <ShortcutCategorySection
116
+ title={ __( 'Block shortcuts' ) }
117
+ categoryName="block"
118
+ additionalShortcuts={ [
119
+ {
120
+ keyCombination: { character: '/' },
121
+ description: __(
122
+ 'Change the block type after adding a new paragraph.'
123
+ ),
124
+ /* translators: The forward-slash character. e.g. '/'. */
125
+ ariaLabel: __( 'Forward-slash' ),
126
+ },
127
+ ] }
128
+ />
129
+ <ShortcutSection
130
+ title={ __( 'Text formatting' ) }
131
+ shortcuts={ textFormattingShortcuts }
132
+ />
133
+ </Modal>
134
+ );
135
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { castArray } from 'lodash';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { Fragment } from '@wordpress/element';
10
+ import { displayShortcutList, shortcutAriaLabel } from '@wordpress/keycodes';
11
+
12
+ function KeyCombination( { keyCombination, forceAriaLabel } ) {
13
+ const shortcut = keyCombination.modifier
14
+ ? displayShortcutList[ keyCombination.modifier ](
15
+ keyCombination.character
16
+ )
17
+ : keyCombination.character;
18
+ const ariaLabel = keyCombination.modifier
19
+ ? shortcutAriaLabel[ keyCombination.modifier ](
20
+ keyCombination.character
21
+ )
22
+ : keyCombination.character;
23
+
24
+ return (
25
+ <kbd
26
+ className="edit-site-keyboard-shortcut-help-modal__shortcut-key-combination"
27
+ aria-label={ forceAriaLabel || ariaLabel }
28
+ >
29
+ { castArray( shortcut ).map( ( character, index ) => {
30
+ if ( character === '+' ) {
31
+ return <Fragment key={ index }>{ character }</Fragment>;
32
+ }
33
+
34
+ return (
35
+ <kbd
36
+ key={ index }
37
+ className="edit-site-keyboard-shortcut-help-modal__shortcut-key"
38
+ >
39
+ { character }
40
+ </kbd>
41
+ );
42
+ } ) }
43
+ </kbd>
44
+ );
45
+ }
46
+
47
+ export default function Shortcut( {
48
+ description,
49
+ keyCombination,
50
+ aliases = [],
51
+ ariaLabel,
52
+ } ) {
53
+ return (
54
+ <>
55
+ <div className="edit-site-keyboard-shortcut-help-modal__shortcut-description">
56
+ { description }
57
+ </div>
58
+ <div className="edit-site-keyboard-shortcut-help-modal__shortcut-term">
59
+ <KeyCombination
60
+ keyCombination={ keyCombination }
61
+ forceAriaLabel={ ariaLabel }
62
+ />
63
+ { aliases.map( ( alias, index ) => (
64
+ <KeyCombination
65
+ keyCombination={ alias }
66
+ forceAriaLabel={ ariaLabel }
67
+ key={ index }
68
+ />
69
+ ) ) }
70
+ </div>
71
+ </>
72
+ );
73
+ }
@@ -0,0 +1,66 @@
1
+ .edit-site-keyboard-shortcut-help-modal {
2
+ &__section {
3
+ margin: 0 0 2rem 0;
4
+ }
5
+
6
+ &__main-shortcuts .edit-site-keyboard-shortcut-help-modal__shortcut-list {
7
+ // Push the shortcut to be flush with top modal header.
8
+ margin-top: -$grid-unit-30 -$border-width;
9
+ }
10
+
11
+ &__section-title {
12
+ font-size: 0.9rem;
13
+ font-weight: 600;
14
+ }
15
+
16
+ &__shortcut {
17
+ display: flex;
18
+ align-items: baseline;
19
+ padding: 0.6rem 0;
20
+ border-top: 1px solid $gray-300;
21
+ margin-bottom: 0;
22
+
23
+ &:last-child {
24
+ border-bottom: 1px solid $gray-300;
25
+ }
26
+
27
+ &:empty {
28
+ display: none;
29
+ }
30
+ }
31
+
32
+ &__shortcut-term {
33
+ font-weight: 600;
34
+ margin: 0 0 0 1rem;
35
+ text-align: right;
36
+ }
37
+
38
+ &__shortcut-description {
39
+ flex: 1;
40
+ margin: 0;
41
+
42
+ // IE 11 flex item fix - ensure the item does not collapse.
43
+ flex-basis: auto;
44
+ }
45
+
46
+ &__shortcut-key-combination {
47
+ display: block;
48
+ background: none;
49
+ margin: 0;
50
+ padding: 0;
51
+
52
+ & + .edit-site-keyboard-shortcut-help-modal__shortcut-key-combination {
53
+ margin-top: 10px;
54
+ }
55
+ }
56
+
57
+ &__shortcut-key {
58
+ padding: 0.25rem 0.5rem;
59
+ border-radius: 8%;
60
+ margin: 0 0.2rem 0 0.2rem;
61
+
62
+ &:last-child {
63
+ margin: 0 0 0 0.2rem;
64
+ }
65
+ }
66
+ }
@@ -137,6 +137,16 @@ function KeyboardShortcutsRegister() {
137
137
  },
138
138
  } );
139
139
 
140
+ registerShortcut( {
141
+ name: 'core/edit-site/keyboard-shortcuts',
142
+ category: 'main',
143
+ description: __( 'Display these keyboard shortcuts.' ),
144
+ keyCombination: {
145
+ modifier: 'access',
146
+ character: 'h',
147
+ },
148
+ } );
149
+
140
150
  registerShortcut( {
141
151
  name: 'core/edit-site/next-region',
142
152
  category: 'global',
@@ -18,6 +18,7 @@ import {
18
18
  commentAuthorAvatar as authorIcon,
19
19
  layout as themeIcon,
20
20
  plugins as pluginIcon,
21
+ globe as globeIcon,
21
22
  } from '@wordpress/icons';
22
23
  import { __ } from '@wordpress/i18n';
23
24
 
@@ -35,6 +36,45 @@ function CustomizedTooltip( { isCustomized, children } ) {
35
36
  );
36
37
  }
37
38
 
39
+ function BaseAddedBy( { text, icon, imageUrl, isCustomized } ) {
40
+ const [ isImageLoaded, setIsImageLoaded ] = useState( false );
41
+
42
+ return (
43
+ <HStack alignment="left">
44
+ <CustomizedTooltip isCustomized={ isCustomized }>
45
+ { imageUrl ? (
46
+ <div
47
+ className={ classnames(
48
+ 'edit-site-list-added-by__avatar',
49
+ {
50
+ 'is-loaded': isImageLoaded,
51
+ }
52
+ ) }
53
+ >
54
+ <img
55
+ onLoad={ () => setIsImageLoaded( true ) }
56
+ alt=""
57
+ src={ imageUrl }
58
+ />
59
+ </div>
60
+ ) : (
61
+ <div
62
+ className={ classnames(
63
+ 'edit-site-list-added-by__icon',
64
+ {
65
+ 'is-customized': isCustomized,
66
+ }
67
+ ) }
68
+ >
69
+ <Icon icon={ icon } />
70
+ </div>
71
+ ) }
72
+ </CustomizedTooltip>
73
+ <span>{ text }</span>
74
+ </HStack>
75
+ );
76
+ }
77
+
38
78
  function AddedByTheme( { slug, isCustomized } ) {
39
79
  const theme = useSelect(
40
80
  ( select ) => select( coreStore ).getTheme( slug ),
@@ -42,18 +82,11 @@ function AddedByTheme( { slug, isCustomized } ) {
42
82
  );
43
83
 
44
84
  return (
45
- <HStack alignment="left">
46
- <CustomizedTooltip isCustomized={ isCustomized }>
47
- <div
48
- className={ classnames( 'edit-site-list-added-by__icon', {
49
- 'is-customized': isCustomized,
50
- } ) }
51
- >
52
- <Icon icon={ themeIcon } />
53
- </div>
54
- </CustomizedTooltip>
55
- <span>{ theme?.name?.rendered || slug }</span>
56
- </HStack>
85
+ <BaseAddedBy
86
+ icon={ themeIcon }
87
+ text={ theme?.name?.rendered || slug }
88
+ isCustomized={ isCustomized }
89
+ />
57
90
  );
58
91
  }
59
92
 
@@ -64,14 +97,11 @@ function AddedByPlugin( { slug, isCustomized } ) {
64
97
  );
65
98
 
66
99
  return (
67
- <HStack alignment="left">
68
- <CustomizedTooltip isCustomized={ isCustomized }>
69
- <div className="edit-site-list-added-by__icon">
70
- <Icon icon={ pluginIcon } />
71
- </div>
72
- </CustomizedTooltip>
73
- <span>{ plugin?.name || slug }</span>
74
- </HStack>
100
+ <BaseAddedBy
101
+ icon={ pluginIcon }
102
+ text={ plugin?.name || slug }
103
+ isCustomized={ isCustomized }
104
+ />
75
105
  );
76
106
  }
77
107
 
@@ -79,35 +109,13 @@ function AddedByAuthor( { id } ) {
79
109
  const user = useSelect( ( select ) => select( coreStore ).getUser( id ), [
80
110
  id,
81
111
  ] );
82
- const [ isImageLoaded, setIsImageLoaded ] = useState( false );
83
-
84
- const avatarURL = user?.avatar_urls?.[ 48 ];
85
- const hasAvatar = !! avatarURL;
86
112
 
87
113
  return (
88
- <HStack alignment="left">
89
- <div
90
- className={ classnames(
91
- hasAvatar
92
- ? 'edit-site-list-added-by__avatar'
93
- : 'edit-site-list-added-by__icon',
94
- {
95
- 'is-loaded': isImageLoaded,
96
- }
97
- ) }
98
- >
99
- { hasAvatar ? (
100
- <img
101
- onLoad={ () => setIsImageLoaded( true ) }
102
- alt=""
103
- src={ avatarURL }
104
- />
105
- ) : (
106
- <Icon icon={ authorIcon } />
107
- ) }
108
- </div>
109
- <span>{ user?.nickname }</span>
110
- </HStack>
114
+ <BaseAddedBy
115
+ icon={ authorIcon }
116
+ imageUrl={ user?.avatar_urls?.[ 48 ] }
117
+ text={ user?.nickname }
118
+ />
111
119
  );
112
120
  }
113
121
 
@@ -117,29 +125,15 @@ function AddedBySite() {
117
125
  const siteData = getEntityRecord( 'root', '__unstableBase' );
118
126
 
119
127
  return {
120
- name: siteData.name,
128
+ name: siteData?.name,
121
129
  logoURL: siteData?.site_logo
122
130
  ? getMedia( siteData.site_logo )?.source_url
123
131
  : undefined,
124
132
  };
125
133
  }, [] );
126
- const [ isImageLoaded, setIsImageLoaded ] = useState( false );
127
134
 
128
135
  return (
129
- <HStack alignment="left">
130
- <div
131
- className={ classnames( 'edit-site-list-added-by__avatar', {
132
- 'is-loaded': isImageLoaded,
133
- } ) }
134
- >
135
- <img
136
- onLoad={ () => setIsImageLoaded( true ) }
137
- alt=""
138
- src={ logoURL }
139
- />
140
- </div>
141
- <span>{ name }</span>
142
- </HStack>
136
+ <BaseAddedBy icon={ globeIcon } imageUrl={ logoURL } text={ name } />
143
137
  );
144
138
  }
145
139
 
@@ -8,6 +8,7 @@ import {
8
8
  VisuallyHidden,
9
9
  __experimentalHeading as Heading,
10
10
  } from '@wordpress/components';
11
+ import { decodeEntities } from '@wordpress/html-entities';
11
12
 
12
13
  /**
13
14
  * Internal dependencies
@@ -98,8 +99,10 @@ export default function Table( { templateType } ) {
98
99
  postType: template.type,
99
100
  } }
100
101
  >
101
- { template.title?.rendered ||
102
- template.slug }
102
+ { decodeEntities(
103
+ template.title?.rendered ||
104
+ template.slug
105
+ ) }
103
106
  </Link>
104
107
  </Heading>
105
108
  { template.description }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import apiFetch from '@wordpress/api-fetch';
5
+ import { addQueryArgs } from '@wordpress/url';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import history from '../../utils/history';
11
+ import getIsListPage from '../../utils/get-is-list-page';
12
+
13
+ function getNeedsHomepageRedirect( params ) {
14
+ const { postType } = params;
15
+ return (
16
+ ! getIsListPage( params ) &&
17
+ ! [ 'post', 'page', 'wp_template', 'wp_template_part' ].includes(
18
+ postType
19
+ )
20
+ );
21
+ }
22
+
23
+ /**
24
+ * Returns the postType and postId of the default homepage.
25
+ *
26
+ * @param {string} siteUrl The URL of the site.
27
+ * @return {Object} An object containing the postType and postId properties
28
+ * or `undefined` if a homepage could not be found.
29
+ */
30
+ async function getHomepageParams( siteUrl ) {
31
+ const siteSettings = await apiFetch( { path: '/wp/v2/settings' } );
32
+ if ( ! siteSettings ) {
33
+ throw new Error( '`getHomepageParams`: unable to load site settings.' );
34
+ }
35
+
36
+ const {
37
+ show_on_front: showOnFront,
38
+ page_on_front: frontpageId,
39
+ } = siteSettings;
40
+
41
+ // If the user has set a page as the homepage, use those details.
42
+ if ( showOnFront === 'page' ) {
43
+ return {
44
+ postType: 'page',
45
+ postId: frontpageId,
46
+ };
47
+ }
48
+
49
+ // Else get the home template.
50
+ // This matches the logic in `__experimentalGetTemplateForLink`.
51
+ // (packages/core-data/src/resolvers.js)
52
+ const template = await window
53
+ .fetch( addQueryArgs( siteUrl, { '_wp-find-template': true } ) )
54
+ .then( ( response ) => {
55
+ if ( ! response.ok ) {
56
+ throw new Error(
57
+ `\`getHomepageParams\`: HTTP status error, ${ response.status } ${ response.statusText }`
58
+ );
59
+ }
60
+
61
+ return response.json();
62
+ } )
63
+ .then( ( { data } ) => {
64
+ if ( data.message ) {
65
+ throw new Error(
66
+ `\`getHomepageParams\`: REST API error, ${ data.message }`
67
+ );
68
+ }
69
+
70
+ return data;
71
+ } );
72
+
73
+ if ( ! template?.id ) {
74
+ throw new Error( '`getHomepageParams`: unable to find home template.' );
75
+ }
76
+
77
+ return {
78
+ postType: 'wp_template',
79
+ postId: template.id,
80
+ };
81
+ }
82
+
83
+ export default async function redirectToHomepage( siteUrl ) {
84
+ const searchParams = new URLSearchParams( history.location.search );
85
+ const params = Object.fromEntries( searchParams.entries() );
86
+
87
+ if ( getNeedsHomepageRedirect( params ) ) {
88
+ const homepageParams = await getHomepageParams( siteUrl );
89
+
90
+ if ( homepageParams ) {
91
+ history.replace( homepageParams );
92
+ }
93
+ }
94
+ }
@@ -30,11 +30,16 @@ export default function ConvertToTemplatePart( { clientIds, blocks } ) {
30
30
  const { createSuccessNotice } = useDispatch( noticesStore );
31
31
 
32
32
  const onConvert = async ( { title, area } ) => {
33
+ // Currently template parts only allow latin chars.
34
+ // Fallback slug will receive suffix by default.
35
+ const cleanSlug =
36
+ kebabCase( title ).replace( /[^\w-]+/g, '' ) || 'wp-custom-part';
37
+
33
38
  const templatePart = await saveEntityRecord(
34
39
  'postType',
35
40
  'wp_template_part',
36
41
  {
37
- slug: kebabCase( title ),
42
+ slug: cleanSlug,
38
43
  title,
39
44
  content: serialize( blocks ),
40
45
  area,
@@ -2,63 +2,31 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { useEffect } from '@wordpress/element';
5
- import { useDispatch, useSelect } from '@wordpress/data';
5
+ import { useDispatch } from '@wordpress/data';
6
6
 
7
7
  /**
8
8
  * Internal dependencies
9
9
  */
10
- import { useLocation, useHistory } from '../routes';
10
+ import { useLocation } from '../routes';
11
11
  import { store as editSiteStore } from '../../store';
12
12
 
13
13
  export default function URLQueryController() {
14
- const { setTemplate, setTemplatePart, showHomepage, setPage } = useDispatch(
14
+ const { setTemplate, setTemplatePart, setPage } = useDispatch(
15
15
  editSiteStore
16
16
  );
17
- const history = useHistory();
18
17
  const {
19
18
  params: { postId, postType },
20
19
  } = useLocation();
21
- const { getPage, getEditedPostId, getEditedPostType } = useSelect(
22
- editSiteStore
23
- );
24
20
 
25
21
  // Set correct entity on page navigation.
26
22
  useEffect( () => {
27
- let isMounted = true;
28
-
29
23
  if ( 'page' === postType || 'post' === postType ) {
30
24
  setPage( { context: { postType, postId } } ); // Resolves correct template based on ID.
31
25
  } else if ( 'wp_template' === postType ) {
32
26
  setTemplate( postId );
33
27
  } else if ( 'wp_template_part' === postType ) {
34
28
  setTemplatePart( postId );
35
- } else {
36
- showHomepage().then( () => {
37
- if ( ! isMounted ) {
38
- return;
39
- }
40
-
41
- const page = getPage();
42
- const editedPostId = getEditedPostId();
43
- const editedPostType = getEditedPostType();
44
-
45
- if ( page?.context?.postId && page?.context?.postType ) {
46
- history.replace( {
47
- postId: page.context.postId,
48
- postType: page.context.postType,
49
- } );
50
- } else if ( editedPostId && editedPostType ) {
51
- history.replace( {
52
- postId: editedPostId,
53
- postType: editedPostType,
54
- } );
55
- }
56
- } );
57
29
  }
58
-
59
- return () => {
60
- isMounted = false;
61
- };
62
30
  }, [ postId, postType ] );
63
31
 
64
32
  return null;