@wordpress/block-library 9.33.1-next.ff1cebbba.0 → 9.33.1

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 (164) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +1 -1
  3. package/build/breadcrumbs/block.json +8 -2
  4. package/build/breadcrumbs/edit.js +113 -12
  5. package/build/breadcrumbs/edit.js.map +2 -2
  6. package/build/buttons/transforms.js +7 -7
  7. package/build/buttons/transforms.js.map +2 -2
  8. package/build/code/transforms.js +19 -15
  9. package/build/code/transforms.js.map +2 -2
  10. package/build/heading/index.js +1 -3
  11. package/build/heading/index.js.map +3 -3
  12. package/build/heading/transforms.js +22 -20
  13. package/build/heading/transforms.js.map +2 -2
  14. package/build/index.js +5 -3
  15. package/build/index.js.map +2 -2
  16. package/build/math/block.json +21 -0
  17. package/build/math/edit.js +132 -0
  18. package/build/math/edit.js.map +7 -0
  19. package/build/math/index.js +63 -0
  20. package/build/math/index.js.map +7 -0
  21. package/build/math/init.js +35 -0
  22. package/build/math/init.js.map +7 -0
  23. package/build/math/save.js +40 -0
  24. package/build/math/save.js.map +7 -0
  25. package/build/navigation/edit/menu-inspector-controls.js +3 -3
  26. package/build/navigation/edit/menu-inspector-controls.js.map +2 -2
  27. package/build/navigation-link/edit.js +6 -3
  28. package/build/navigation-link/edit.js.map +2 -2
  29. package/build/navigation-link/link-ui/index.js +1 -1
  30. package/build/navigation-link/link-ui/index.js.map +2 -2
  31. package/build/navigation-link/shared/controls.js +4 -1
  32. package/build/navigation-link/shared/controls.js.map +3 -3
  33. package/build/navigation-link/shared/index.js +2 -0
  34. package/build/navigation-link/shared/index.js.map +2 -2
  35. package/build/navigation-link/shared/update-attributes.js +3 -1
  36. package/build/navigation-link/shared/update-attributes.js.map +2 -2
  37. package/build/navigation-link/shared/use-entity-binding.js +46 -13
  38. package/build/navigation-link/shared/use-entity-binding.js.map +2 -2
  39. package/build/navigation-submenu/edit.js +6 -3
  40. package/build/navigation-submenu/edit.js.map +2 -2
  41. package/build/page-list/use-convert-to-navigation-links.js +6 -1
  42. package/build/page-list/use-convert-to-navigation-links.js.map +2 -2
  43. package/build/paragraph/index.js +1 -3
  44. package/build/paragraph/index.js.map +3 -3
  45. package/build/post-date/deprecated.js +98 -2
  46. package/build/post-date/deprecated.js.map +2 -2
  47. package/build/post-date/edit.js +1 -1
  48. package/build/post-date/edit.js.map +1 -1
  49. package/build/post-date/variations.js +4 -4
  50. package/build/post-date/variations.js.map +2 -2
  51. package/build/term-template/block.json +0 -1
  52. package/build/term-template/edit.js +4 -1
  53. package/build/term-template/edit.js.map +2 -2
  54. package/build/terms-query/block.json +0 -1
  55. package/build/utils/get-transformed-attributes.js +82 -0
  56. package/build/utils/get-transformed-attributes.js.map +7 -0
  57. package/build-module/breadcrumbs/block.json +8 -2
  58. package/build-module/breadcrumbs/edit.js +117 -14
  59. package/build-module/breadcrumbs/edit.js.map +2 -2
  60. package/build-module/buttons/transforms.js +7 -7
  61. package/build-module/buttons/transforms.js.map +2 -2
  62. package/build-module/code/transforms.js +19 -15
  63. package/build-module/code/transforms.js.map +2 -2
  64. package/build-module/heading/index.js +1 -3
  65. package/build-module/heading/index.js.map +2 -2
  66. package/build-module/heading/transforms.js +22 -20
  67. package/build-module/heading/transforms.js.map +2 -2
  68. package/build-module/index.js +5 -3
  69. package/build-module/index.js.map +2 -2
  70. package/build-module/math/block.json +21 -0
  71. package/build-module/math/edit.js +110 -0
  72. package/build-module/math/edit.js.map +7 -0
  73. package/build-module/math/index.js +26 -0
  74. package/build-module/math/index.js.map +7 -0
  75. package/build-module/math/init.js +8 -0
  76. package/build-module/math/init.js.map +7 -0
  77. package/build-module/math/save.js +20 -0
  78. package/build-module/math/save.js.map +7 -0
  79. package/build-module/navigation/edit/menu-inspector-controls.js +3 -3
  80. package/build-module/navigation/edit/menu-inspector-controls.js.map +2 -2
  81. package/build-module/navigation-link/edit.js +6 -3
  82. package/build-module/navigation-link/edit.js.map +2 -2
  83. package/build-module/navigation-link/link-ui/index.js +1 -1
  84. package/build-module/navigation-link/link-ui/index.js.map +2 -2
  85. package/build-module/navigation-link/shared/controls.js +4 -1
  86. package/build-module/navigation-link/shared/controls.js.map +2 -2
  87. package/build-module/navigation-link/shared/index.js +5 -1
  88. package/build-module/navigation-link/shared/index.js.map +2 -2
  89. package/build-module/navigation-link/shared/update-attributes.js +3 -1
  90. package/build-module/navigation-link/shared/update-attributes.js.map +2 -2
  91. package/build-module/navigation-link/shared/use-entity-binding.js +45 -13
  92. package/build-module/navigation-link/shared/use-entity-binding.js.map +2 -2
  93. package/build-module/navigation-submenu/edit.js +6 -3
  94. package/build-module/navigation-submenu/edit.js.map +2 -2
  95. package/build-module/page-list/use-convert-to-navigation-links.js +6 -1
  96. package/build-module/page-list/use-convert-to-navigation-links.js.map +2 -2
  97. package/build-module/paragraph/index.js +1 -3
  98. package/build-module/paragraph/index.js.map +2 -2
  99. package/build-module/post-date/deprecated.js +98 -2
  100. package/build-module/post-date/deprecated.js.map +2 -2
  101. package/build-module/post-date/edit.js +1 -1
  102. package/build-module/post-date/edit.js.map +1 -1
  103. package/build-module/post-date/variations.js +4 -4
  104. package/build-module/post-date/variations.js.map +2 -2
  105. package/build-module/term-template/block.json +0 -1
  106. package/build-module/term-template/edit.js +4 -1
  107. package/build-module/term-template/edit.js.map +2 -2
  108. package/build-module/terms-query/block.json +0 -1
  109. package/build-module/utils/get-transformed-attributes.js +58 -0
  110. package/build-module/utils/get-transformed-attributes.js.map +7 -0
  111. package/package.json +61 -36
  112. package/src/breadcrumbs/block.json +8 -2
  113. package/src/breadcrumbs/edit.js +163 -18
  114. package/src/breadcrumbs/index.php +118 -16
  115. package/src/buttons/transforms.js +6 -6
  116. package/src/code/transforms.js +16 -14
  117. package/src/heading/index.js +0 -2
  118. package/src/heading/transforms.js +25 -24
  119. package/src/index.js +5 -3
  120. package/src/math/block.json +21 -0
  121. package/src/math/edit.js +123 -0
  122. package/src/math/index.js +31 -0
  123. package/src/math/init.js +4 -0
  124. package/src/math/save.js +20 -0
  125. package/src/navigation/edit/menu-inspector-controls.js +8 -7
  126. package/src/navigation-link/edit.js +6 -3
  127. package/src/navigation-link/index.php +4 -18
  128. package/src/navigation-link/link-ui/index.js +4 -2
  129. package/src/navigation-link/shared/controls.js +12 -3
  130. package/src/navigation-link/shared/index.js +4 -1
  131. package/src/navigation-link/shared/test/update-attributes.test.js +8 -0
  132. package/src/navigation-link/shared/test/use-entity-binding.js +132 -17
  133. package/src/navigation-link/shared/update-attributes.js +1 -0
  134. package/src/navigation-link/shared/use-entity-binding.js +74 -19
  135. package/src/navigation-submenu/edit.js +6 -3
  136. package/src/navigation-submenu/index.php +3 -17
  137. package/src/page-list/test/{convert-to-links-modal.js → convert-to-navigation-links.js} +67 -0
  138. package/src/page-list/use-convert-to-navigation-links.js +11 -1
  139. package/src/paragraph/index.js +0 -2
  140. package/src/post-date/deprecated.js +100 -2
  141. package/src/post-date/edit.js +1 -1
  142. package/src/post-date/index.php +3 -3
  143. package/src/post-date/variations.js +5 -4
  144. package/src/term-template/block.json +0 -1
  145. package/src/term-template/edit.js +4 -1
  146. package/src/term-template/index.php +4 -6
  147. package/src/terms-query/block.json +0 -1
  148. package/src/utils/get-transformed-attributes.js +98 -0
  149. package/tsconfig.json +1 -0
  150. package/build/heading/variations.js +0 -48
  151. package/build/heading/variations.js.map +0 -7
  152. package/build/paragraph/variations.js +0 -48
  153. package/build/paragraph/variations.js.map +0 -7
  154. package/build/utils/get-transformed-metadata.js +0 -65
  155. package/build/utils/get-transformed-metadata.js.map +0 -7
  156. package/build-module/heading/variations.js +0 -28
  157. package/build-module/heading/variations.js.map +0 -7
  158. package/build-module/paragraph/variations.js +0 -28
  159. package/build-module/paragraph/variations.js.map +0 -7
  160. package/build-module/utils/get-transformed-metadata.js +0 -41
  161. package/build-module/utils/get-transformed-metadata.js.map +0 -7
  162. package/src/heading/variations.js +0 -29
  163. package/src/paragraph/variations.js +0 -29
  164. package/src/utils/get-transformed-metadata.js +0 -69
@@ -10,7 +10,10 @@ import { renderHook, act } from '@testing-library/react';
10
10
  /**
11
11
  * Internal dependencies
12
12
  */
13
- import { useEntityBinding } from '../use-entity-binding';
13
+ import {
14
+ useEntityBinding,
15
+ buildNavigationLinkEntityBinding,
16
+ } from '../use-entity-binding';
14
17
 
15
18
  // Mock the entire @wordpress/block-editor module
16
19
  jest.mock( '@wordpress/block-editor', () => ( {
@@ -49,17 +52,18 @@ describe( 'useEntityBinding', () => {
49
52
  expect( result.current.hasUrlBinding ).toBe( false );
50
53
  } );
51
54
 
52
- it( 'should return true when core/entity binding exists with id', () => {
55
+ it( 'should return true when core/post-data binding exists with id for post-type', () => {
53
56
  const attributes = {
54
57
  metadata: {
55
58
  bindings: {
56
59
  url: {
57
- source: 'core/entity',
58
- args: { key: 'url' },
60
+ source: 'core/post-data',
61
+ args: { field: 'link' },
59
62
  },
60
63
  },
61
64
  },
62
65
  id: 123,
66
+ kind: 'post-type',
63
67
  };
64
68
 
65
69
  const { result } = renderHook( () =>
@@ -72,17 +76,42 @@ describe( 'useEntityBinding', () => {
72
76
  expect( result.current.hasUrlBinding ).toBe( true );
73
77
  } );
74
78
 
75
- it( 'should return false when source is not core/entity', () => {
79
+ it( 'should return true when core/term-data binding exists with id for taxonomy', () => {
80
+ const attributes = {
81
+ metadata: {
82
+ bindings: {
83
+ url: {
84
+ source: 'core/term-data',
85
+ args: { field: 'link' },
86
+ },
87
+ },
88
+ },
89
+ id: 123,
90
+ kind: 'taxonomy',
91
+ };
92
+
93
+ const { result } = renderHook( () =>
94
+ useEntityBinding( {
95
+ clientId: 'test-client-id',
96
+ attributes,
97
+ } )
98
+ );
99
+
100
+ expect( result.current.hasUrlBinding ).toBe( true );
101
+ } );
102
+
103
+ it( 'should return false when source is not core/post-data or core/term-data', () => {
76
104
  const attributes = {
77
105
  metadata: {
78
106
  bindings: {
79
107
  url: {
80
108
  source: 'some-other-source',
81
- args: { key: 'url' },
109
+ args: { field: 'url' },
82
110
  },
83
111
  },
84
112
  },
85
113
  id: 123,
114
+ kind: 'post-type',
86
115
  };
87
116
 
88
117
  const { result } = renderHook( () =>
@@ -95,17 +124,18 @@ describe( 'useEntityBinding', () => {
95
124
  expect( result.current.hasUrlBinding ).toBe( false );
96
125
  } );
97
126
 
98
- it( 'should return false when core/entity binding exists but no id', () => {
127
+ it( 'should return false when core/post-data binding exists but no id', () => {
99
128
  const attributes = {
100
129
  metadata: {
101
130
  bindings: {
102
131
  url: {
103
- source: 'core/entity',
104
- args: { key: 'url' },
132
+ source: 'core/post-data',
133
+ args: { field: 'link' },
105
134
  },
106
135
  },
107
136
  },
108
137
  id: null,
138
+ kind: 'post-type',
109
139
  };
110
140
 
111
141
  const { result } = renderHook( () =>
@@ -147,12 +177,13 @@ describe( 'useEntityBinding', () => {
147
177
  metadata: {
148
178
  bindings: {
149
179
  url: {
150
- source: 'core/entity',
151
- args: { key: 'url' },
180
+ source: 'core/post-data',
181
+ args: { field: 'link' },
152
182
  },
153
183
  },
154
184
  },
155
185
  id: 123,
186
+ kind: 'post-type',
156
187
  };
157
188
 
158
189
  const { result } = renderHook( () =>
@@ -171,7 +202,7 @@ describe( 'useEntityBinding', () => {
171
202
  } );
172
203
  } );
173
204
 
174
- it( 'should NOT clear binding when clearBinding is called and no binding exists', () => {
205
+ it( 'should NOT call updateBlockBindings when clearBinding is called and no binding exists', () => {
175
206
  const attributes = {
176
207
  metadata: {},
177
208
  id: null,
@@ -191,7 +222,7 @@ describe( 'useEntityBinding', () => {
191
222
  expect( mockUpdateBlockBindings ).not.toHaveBeenCalled();
192
223
  } );
193
224
 
194
- it( 'should NOT clear binding when binding metadata exists but source is null', () => {
225
+ it( 'should call updateBlockBindings when clearBinding is called and binding exists even with null source', () => {
195
226
  const attributes = {
196
227
  metadata: {
197
228
  bindings: {
@@ -215,13 +246,16 @@ describe( 'useEntityBinding', () => {
215
246
  result.current.clearBinding();
216
247
  } );
217
248
 
218
- expect( mockUpdateBlockBindings ).not.toHaveBeenCalled();
249
+ expect( mockUpdateBlockBindings ).toHaveBeenCalledWith( {
250
+ url: undefined,
251
+ } );
219
252
  } );
220
253
 
221
- it( 'should create binding when createBinding is called', () => {
254
+ it( 'should create core/post-data binding when createBinding is called for post-type', () => {
222
255
  const attributes = {
223
256
  metadata: {},
224
257
  id: null,
258
+ kind: 'post-type',
225
259
  };
226
260
 
227
261
  const { result } = renderHook( () =>
@@ -237,11 +271,92 @@ describe( 'useEntityBinding', () => {
237
271
 
238
272
  expect( mockUpdateBlockBindings ).toHaveBeenCalledWith( {
239
273
  url: {
240
- source: 'core/entity',
274
+ source: 'core/post-data',
241
275
  args: {
242
- key: 'url',
276
+ field: 'link',
243
277
  },
244
278
  },
245
279
  } );
246
280
  } );
281
+
282
+ describe( 'buildNavigationLinkEntityBinding', () => {
283
+ it( 'returns correct binding for post-type', () => {
284
+ const binding = buildNavigationLinkEntityBinding( 'post-type' );
285
+ expect( binding ).toEqual( {
286
+ url: {
287
+ source: 'core/post-data',
288
+ args: { field: 'link' },
289
+ },
290
+ } );
291
+ } );
292
+
293
+ it( 'returns correct binding for taxonomy', () => {
294
+ const binding = buildNavigationLinkEntityBinding( 'taxonomy' );
295
+ expect( binding ).toEqual( {
296
+ url: {
297
+ source: 'core/term-data',
298
+ args: { field: 'link' },
299
+ },
300
+ } );
301
+ } );
302
+
303
+ it( 'throws error when called without parameter', () => {
304
+ expect( () => {
305
+ buildNavigationLinkEntityBinding();
306
+ } ).toThrow(
307
+ 'buildNavigationLinkEntityBinding requires a kind parameter'
308
+ );
309
+ } );
310
+
311
+ it( 'throws error for invalid kind', () => {
312
+ expect( () => {
313
+ buildNavigationLinkEntityBinding( 'invalid-kind' );
314
+ } ).toThrow( 'Invalid kind "invalid-kind"' );
315
+ } );
316
+
317
+ it( 'throws error for null kind', () => {
318
+ expect( () => {
319
+ buildNavigationLinkEntityBinding( null );
320
+ } ).toThrow( 'Invalid kind "null"' );
321
+ } );
322
+
323
+ it( 'throws error for empty string', () => {
324
+ expect( () => {
325
+ buildNavigationLinkEntityBinding( '' );
326
+ } ).toThrow( 'Invalid kind ""' );
327
+ } );
328
+
329
+ it( 'handles invalid kind gracefully in createBinding', () => {
330
+ const consoleSpy = jest
331
+ .spyOn( console, 'warn' )
332
+ .mockImplementation();
333
+
334
+ const attributes = {
335
+ metadata: {},
336
+ id: null,
337
+ kind: 'invalid-kind',
338
+ };
339
+
340
+ const { result } = renderHook( () =>
341
+ useEntityBinding( {
342
+ clientId: 'test-client-id',
343
+ attributes,
344
+ } )
345
+ );
346
+
347
+ act( () => {
348
+ result.current.createBinding();
349
+ } );
350
+
351
+ expect( consoleSpy ).toHaveBeenCalledWith(
352
+ 'Failed to create entity binding:',
353
+ expect.stringContaining( 'Invalid kind "invalid-kind"' )
354
+ );
355
+
356
+ // Should not call updateBlockBindings when validation fails
357
+ expect( mockUpdateBlockBindings ).not.toHaveBeenCalled();
358
+
359
+ consoleSpy.mockRestore();
360
+ } );
361
+ } );
247
362
  } );
@@ -222,5 +222,6 @@ export const updateAttributes = (
222
222
 
223
223
  return {
224
224
  isEntityLink: !! finalId && finalKind !== 'custom',
225
+ attributes, // Return the computed attributes object
225
226
  };
226
227
  };
@@ -4,6 +4,46 @@
4
4
  import { useCallback } from '@wordpress/element';
5
5
  import { useBlockBindingsUtils } from '@wordpress/block-editor';
6
6
 
7
+ /**
8
+ * Builds entity binding configuration for navigation link URLs.
9
+ * This function generates the structure used to bind navigation link URLs to their entity sources.
10
+ *
11
+ * Using a function instead of a constant allows for future enhancements where the binding
12
+ * might need dynamic data (e.g., entity ID, context-specific arguments).
13
+ *
14
+ * @param {('post-type'|'taxonomy')} kind - The kind of entity. Only 'post-type' and 'taxonomy' are supported.
15
+ * @return {Object} Entity binding configuration object
16
+ * @throws {Error} If kind is not 'post-type' or 'taxonomy'
17
+ */
18
+ export function buildNavigationLinkEntityBinding( kind ) {
19
+ // Validate kind parameter exists
20
+ if ( kind === undefined ) {
21
+ throw new Error(
22
+ 'buildNavigationLinkEntityBinding requires a kind parameter. ' +
23
+ 'Only "post-type" and "taxonomy" are supported.'
24
+ );
25
+ }
26
+
27
+ // Validate kind parameter value
28
+ if ( kind !== 'post-type' && kind !== 'taxonomy' ) {
29
+ throw new Error(
30
+ `Invalid kind "${ kind }" provided to buildNavigationLinkEntityBinding. ` +
31
+ `Only 'post-type' and 'taxonomy' are supported.`
32
+ );
33
+ }
34
+
35
+ const source = kind === 'taxonomy' ? 'core/term-data' : 'core/post-data';
36
+
37
+ return {
38
+ url: {
39
+ source,
40
+ args: {
41
+ field: 'link',
42
+ },
43
+ },
44
+ };
45
+ }
46
+
7
47
  /**
8
48
  * Shared hook for entity binding functionality in Navigation blocks.
9
49
  *
@@ -17,33 +57,48 @@ import { useBlockBindingsUtils } from '@wordpress/block-editor';
17
57
  */
18
58
  export function useEntityBinding( { clientId, attributes } ) {
19
59
  const { updateBlockBindings } = useBlockBindingsUtils( clientId );
20
- const { metadata, id } = attributes;
60
+ const { metadata, id, kind } = attributes;
21
61
 
22
- // Check if there's a URL binding with the core/entity source
23
- const hasUrlBinding =
24
- metadata?.bindings?.url?.source === 'core/entity' && !! id;
62
+ const hasUrlBinding = !! metadata?.bindings?.url && !! id;
63
+ const expectedSource =
64
+ kind === 'post-type' ? 'core/post-data' : 'core/term-data';
65
+ const hasCorrectBinding =
66
+ hasUrlBinding && metadata?.bindings?.url?.source === expectedSource;
25
67
 
26
68
  const clearBinding = useCallback( () => {
27
- // Only clear if there's actually a valid binding to clear
28
69
  if ( hasUrlBinding ) {
29
- // Remove the URL binding by setting it to undefined
30
70
  updateBlockBindings( { url: undefined } );
31
71
  }
32
- }, [ hasUrlBinding, updateBlockBindings ] );
33
-
34
- const createBinding = useCallback( () => {
35
- updateBlockBindings( {
36
- url: {
37
- source: 'core/entity',
38
- args: {
39
- key: 'url',
40
- },
41
- },
42
- } );
43
- }, [ updateBlockBindings ] );
72
+ }, [ updateBlockBindings, hasUrlBinding, metadata, id ] );
73
+
74
+ const createBinding = useCallback(
75
+ ( updatedAttributes ) => {
76
+ // Use updated attributes if provided, otherwise fall back to closure attributes
77
+ // updatedAttributes needed to access the most up-to-date data when called synchronously
78
+ const kindToUse = updatedAttributes?.kind ?? kind;
79
+
80
+ // Avoid creating binding if no kind is provided
81
+ if ( ! kindToUse ) {
82
+ return;
83
+ }
84
+
85
+ try {
86
+ const binding = buildNavigationLinkEntityBinding( kindToUse );
87
+ updateBlockBindings( binding );
88
+ } catch ( error ) {
89
+ // eslint-disable-next-line no-console
90
+ console.warn(
91
+ 'Failed to create entity binding:',
92
+ error.message
93
+ );
94
+ // Don't create binding if validation fails
95
+ }
96
+ },
97
+ [ updateBlockBindings, kind, id ]
98
+ );
44
99
 
45
100
  return {
46
- hasUrlBinding,
101
+ hasUrlBinding: hasCorrectBinding,
47
102
  clearBinding,
48
103
  createBinding,
49
104
  };
@@ -432,7 +432,10 @@ export default function NavigationSubmenuEdit( {
432
432
  } }
433
433
  onChange={ ( updatedValue ) => {
434
434
  // updateAttributes determines the final state and returns metadata
435
- const { isEntityLink } = updateAttributes(
435
+ const {
436
+ isEntityLink,
437
+ attributes: updatedAttributes,
438
+ } = updateAttributes(
436
439
  updatedValue,
437
440
  setAttributes,
438
441
  attributes
@@ -442,9 +445,9 @@ export default function NavigationSubmenuEdit( {
442
445
  // Only create bindings for entity links (posts, pages, taxonomies)
443
446
  // Never create bindings for custom links (manual URLs)
444
447
  if ( isEntityLink ) {
445
- createBinding();
448
+ createBinding( updatedAttributes );
446
449
  } else {
447
- clearBinding();
450
+ clearBinding( updatedAttributes );
448
451
  }
449
452
  } }
450
453
  />
@@ -79,20 +79,6 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) {
79
79
  return '';
80
80
  }
81
81
 
82
- // Resolve URL binding if present
83
- $url = $attributes['url'] ?? '';
84
- if ( isset( $attributes['metadata']['bindings']['url']['source'] ) ) {
85
- $binding = $attributes['metadata']['bindings']['url'];
86
- $source = get_block_bindings_source( $binding['source'] );
87
- if ( $source ) {
88
- $source_args = $binding['args'] ?? array();
89
- $resolved_url = $source->get_value( $source_args, $block, 'url' );
90
- if ( $resolved_url ) {
91
- $url = $resolved_url;
92
- }
93
- }
94
- }
95
-
96
82
  $font_sizes = block_core_navigation_submenu_build_css_font_sizes( $block->context );
97
83
  $style_attribute = $font_sizes['inline_styles'];
98
84
 
@@ -100,9 +86,9 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) {
100
86
  $kind = empty( $attributes['kind'] ) ? 'post_type' : str_replace( '-', '_', $attributes['kind'] );
101
87
  $is_active = ! empty( $attributes['id'] ) && get_queried_object_id() === (int) $attributes['id'] && ! empty( get_queried_object()->$kind );
102
88
 
103
- if ( is_post_type_archive() && ! empty( $url ) ) {
89
+ if ( is_post_type_archive() && ! empty( $attributes['url'] ) ) {
104
90
  $queried_archive_link = get_post_type_archive_link( get_queried_object()->name );
105
- if ( $url === $queried_archive_link ) {
91
+ if ( $attributes['url'] === $queried_archive_link ) {
106
92
  $is_active = true;
107
93
  }
108
94
  }
@@ -156,7 +142,7 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) {
156
142
  // If Submenus open on hover, we render an anchor tag with attributes.
157
143
  // If submenu icons are set to show, we also render a submenu button, so the submenu can be opened on click.
158
144
  if ( ! $open_on_click ) {
159
- $item_url = $url;
145
+ $item_url = isset( $attributes['url'] ) ? $attributes['url'] : '';
160
146
  // Start appending HTML attributes to anchor tag.
161
147
  $html .= '<a class="wp-block-navigation-item__content"';
162
148
 
@@ -4,6 +4,16 @@
4
4
 
5
5
  import { convertToNavigationLinks } from '../use-convert-to-navigation-links';
6
6
 
7
+ // Expected entity binding structure for navigation links
8
+ const EXPECTED_ENTITY_BINDING = {
9
+ url: {
10
+ source: 'core/post-data',
11
+ args: {
12
+ field: 'link',
13
+ },
14
+ },
15
+ };
16
+
7
17
  // Mock createBlock to avoid creating the blocks in test environment
8
18
  // as convertToNavigationLinks calls this method internally.
9
19
  jest.mock( '@wordpress/blocks', () => {
@@ -117,6 +127,9 @@ describe( 'page list convert to links', () => {
117
127
  label: 'Sample Page',
118
128
  type: 'page',
119
129
  url: 'http://wordpress.local/sample-page/',
130
+ metadata: {
131
+ bindings: EXPECTED_ENTITY_BINDING,
132
+ },
120
133
  },
121
134
  innerBlocks: [],
122
135
  name: 'core/navigation-link',
@@ -128,6 +141,9 @@ describe( 'page list convert to links', () => {
128
141
  label: 'About',
129
142
  type: 'page',
130
143
  url: 'http://wordpress.local/about/',
144
+ metadata: {
145
+ bindings: EXPECTED_ENTITY_BINDING,
146
+ },
131
147
  },
132
148
  innerBlocks: [
133
149
  {
@@ -137,6 +153,9 @@ describe( 'page list convert to links', () => {
137
153
  label: 'About Sub 1',
138
154
  type: 'page',
139
155
  url: 'http://wordpress.local/about/about-sub-1/',
156
+ metadata: {
157
+ bindings: EXPECTED_ENTITY_BINDING,
158
+ },
140
159
  },
141
160
  innerBlocks: [],
142
161
  name: 'core/navigation-link',
@@ -148,6 +167,9 @@ describe( 'page list convert to links', () => {
148
167
  label: 'About Sub 2',
149
168
  type: 'page',
150
169
  url: 'http://wordpress.local/about/about-sub-2/',
170
+ metadata: {
171
+ bindings: EXPECTED_ENTITY_BINDING,
172
+ },
151
173
  },
152
174
  innerBlocks: [],
153
175
  name: 'core/navigation-link',
@@ -162,6 +184,9 @@ describe( 'page list convert to links', () => {
162
184
  label: 'Contact Page',
163
185
  type: 'page',
164
186
  url: 'http://wordpress.local/contact-page/',
187
+ metadata: {
188
+ bindings: EXPECTED_ENTITY_BINDING,
189
+ },
165
190
  },
166
191
  innerBlocks: [],
167
192
  name: 'core/navigation-link',
@@ -173,6 +198,9 @@ describe( 'page list convert to links', () => {
173
198
  label: 'Test',
174
199
  type: 'page',
175
200
  url: 'http://wordpress.local/test/',
201
+ metadata: {
202
+ bindings: EXPECTED_ENTITY_BINDING,
203
+ },
176
204
  },
177
205
  innerBlocks: [
178
206
  {
@@ -182,6 +210,9 @@ describe( 'page list convert to links', () => {
182
210
  label: 'Test Sub',
183
211
  type: 'page',
184
212
  url: 'http://wordpress.local/test/test-sub/',
213
+ metadata: {
214
+ bindings: EXPECTED_ENTITY_BINDING,
215
+ },
185
216
  },
186
217
  innerBlocks: [
187
218
  {
@@ -191,6 +222,9 @@ describe( 'page list convert to links', () => {
191
222
  label: 'Test Sub Sub',
192
223
  type: 'page',
193
224
  url: 'http://wordpress.local/test/test-sub/test-sub-sub/',
225
+ metadata: {
226
+ bindings: EXPECTED_ENTITY_BINDING,
227
+ },
194
228
  },
195
229
  innerBlocks: [],
196
230
  name: 'core/navigation-link',
@@ -297,6 +331,9 @@ describe( 'page list convert to links', () => {
297
331
  label: 'Sample Page',
298
332
  type: 'page',
299
333
  url: 'http://wordpress.local/sample-page/',
334
+ metadata: {
335
+ bindings: EXPECTED_ENTITY_BINDING,
336
+ },
300
337
  },
301
338
  innerBlocks: [],
302
339
  name: 'core/navigation-link',
@@ -308,6 +345,9 @@ describe( 'page list convert to links', () => {
308
345
  label: 'About',
309
346
  type: 'page',
310
347
  url: 'http://wordpress.local/about/',
348
+ metadata: {
349
+ bindings: EXPECTED_ENTITY_BINDING,
350
+ },
311
351
  },
312
352
  innerBlocks: [
313
353
  {
@@ -317,6 +357,9 @@ describe( 'page list convert to links', () => {
317
357
  label: 'About Sub 1',
318
358
  type: 'page',
319
359
  url: 'http://wordpress.local/about/about-sub-1/',
360
+ metadata: {
361
+ bindings: EXPECTED_ENTITY_BINDING,
362
+ },
320
363
  },
321
364
  innerBlocks: [],
322
365
  name: 'core/navigation-link',
@@ -328,6 +371,9 @@ describe( 'page list convert to links', () => {
328
371
  label: 'About Sub 2',
329
372
  type: 'page',
330
373
  url: 'http://wordpress.local/about/about-sub-2/',
374
+ metadata: {
375
+ bindings: EXPECTED_ENTITY_BINDING,
376
+ },
331
377
  },
332
378
  innerBlocks: [],
333
379
  name: 'core/navigation-link',
@@ -342,6 +388,9 @@ describe( 'page list convert to links', () => {
342
388
  label: 'Contact Page',
343
389
  type: 'page',
344
390
  url: 'http://wordpress.local/contact-page/',
391
+ metadata: {
392
+ bindings: EXPECTED_ENTITY_BINDING,
393
+ },
345
394
  },
346
395
  innerBlocks: [],
347
396
  name: 'core/navigation-link',
@@ -353,6 +402,9 @@ describe( 'page list convert to links', () => {
353
402
  label: 'Test',
354
403
  type: 'page',
355
404
  url: 'http://wordpress.local/test/',
405
+ metadata: {
406
+ bindings: EXPECTED_ENTITY_BINDING,
407
+ },
356
408
  },
357
409
  innerBlocks: [
358
410
  {
@@ -362,6 +414,9 @@ describe( 'page list convert to links', () => {
362
414
  label: 'Test Sub',
363
415
  type: 'page',
364
416
  url: 'http://wordpress.local/test/test-sub/',
417
+ metadata: {
418
+ bindings: EXPECTED_ENTITY_BINDING,
419
+ },
365
420
  },
366
421
  innerBlocks: [
367
422
  {
@@ -371,6 +426,9 @@ describe( 'page list convert to links', () => {
371
426
  label: 'Test Sub Sub',
372
427
  type: 'page',
373
428
  url: 'http://wordpress.local/test/test-sub/test-sub-sub/',
429
+ metadata: {
430
+ bindings: EXPECTED_ENTITY_BINDING,
431
+ },
374
432
  },
375
433
  innerBlocks: [],
376
434
  name: 'core/navigation-link',
@@ -481,6 +539,9 @@ describe( 'page list convert to links', () => {
481
539
  label: 'About Sub 1',
482
540
  type: 'page',
483
541
  url: 'http://wordpress.local/about/about-sub-1/',
542
+ metadata: {
543
+ bindings: EXPECTED_ENTITY_BINDING,
544
+ },
484
545
  },
485
546
  innerBlocks: [],
486
547
  name: 'core/navigation-link',
@@ -492,6 +553,9 @@ describe( 'page list convert to links', () => {
492
553
  label: 'About Sub 2',
493
554
  type: 'page',
494
555
  url: 'http://wordpress.local/about/about-sub-2/',
556
+ metadata: {
557
+ bindings: EXPECTED_ENTITY_BINDING,
558
+ },
495
559
  },
496
560
  innerBlocks: [],
497
561
  name: 'core/navigation-link',
@@ -511,6 +575,9 @@ describe( 'page list convert to links', () => {
511
575
  label: 'Test Sub Sub',
512
576
  type: 'page',
513
577
  url: 'http://wordpress.local/test/test-sub/test-sub-sub/',
578
+ metadata: {
579
+ bindings: EXPECTED_ENTITY_BINDING,
580
+ },
514
581
  },
515
582
  innerBlocks: [],
516
583
  name: 'core/navigation-link',
@@ -5,6 +5,11 @@ import { createBlock } from '@wordpress/blocks';
5
5
  import { useDispatch } from '@wordpress/data';
6
6
  import { store as blockEditorStore } from '@wordpress/block-editor';
7
7
 
8
+ /**
9
+ * Internal dependencies
10
+ */
11
+ import { buildNavigationLinkEntityBinding } from '../navigation-link/shared';
12
+
8
13
  /**
9
14
  * Converts an array of pages into a nested array of navigation link blocks.
10
15
  *
@@ -13,6 +18,7 @@ import { store as blockEditorStore } from '@wordpress/block-editor';
13
18
  * @return {Array} A nested array of navigation link blocks.
14
19
  */
15
20
  function createNavigationLinks( pages = [] ) {
21
+ const POST_TYPE_KIND = 'post-type';
16
22
  const linkMap = {};
17
23
  const navigationLinks = [];
18
24
  pages.forEach( ( { id, title, link: url, type, parent } ) => {
@@ -25,7 +31,11 @@ function createNavigationLinks( pages = [] ) {
25
31
  label: title.rendered,
26
32
  url,
27
33
  type,
28
- kind: 'post-type',
34
+ kind: POST_TYPE_KIND,
35
+ metadata: {
36
+ bindings:
37
+ buildNavigationLinkEntityBinding( POST_TYPE_KIND ),
38
+ },
29
39
  },
30
40
  innerBlocks
31
41
  );
@@ -13,7 +13,6 @@ import edit from './edit';
13
13
  import metadata from './block.json';
14
14
  import save from './save';
15
15
  import transforms from './transforms';
16
- import variations from './variations';
17
16
 
18
17
  const { name } = metadata;
19
18
 
@@ -55,7 +54,6 @@ export const settings = {
55
54
  },
56
55
  edit,
57
56
  save,
58
- variations,
59
57
  };
60
58
 
61
59
  export const init = () => initBlock( { name, metadata, settings } );