@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
@@ -7,7 +7,7 @@ import { create, toHTMLString } from '@wordpress/rich-text';
7
7
  /**
8
8
  * Internal dependencies
9
9
  */
10
- import { getTransformedMetadata } from '../utils/get-transformed-metadata';
10
+ import { getTransformedAttributes } from '../utils/get-transformed-attributes';
11
11
 
12
12
  const transforms = {
13
13
  from: [
@@ -19,21 +19,24 @@ const transforms = {
19
19
  {
20
20
  type: 'block',
21
21
  blocks: [ 'core/paragraph' ],
22
- transform: ( { content, metadata } ) =>
23
- createBlock( 'core/code', {
22
+ transform: ( attributes ) => {
23
+ const { content } = attributes;
24
+ return createBlock( 'core/code', {
25
+ ...getTransformedAttributes( attributes, 'core/code' ),
24
26
  content,
25
- metadata: getTransformedMetadata( metadata, 'core/code' ),
26
- } ),
27
+ } );
28
+ },
27
29
  },
28
30
  {
29
31
  type: 'block',
30
32
  blocks: [ 'core/html' ],
31
- transform: ( { content: text, metadata } ) => {
33
+ transform: ( attributes ) => {
34
+ const { content: text } = attributes;
32
35
  return createBlock( 'core/code', {
36
+ ...getTransformedAttributes( attributes, 'core/code' ),
33
37
  // The HTML is plain text (with plain line breaks), so
34
38
  // convert it to rich text.
35
39
  content: toHTMLString( { value: create( { text } ) } ),
36
- metadata: getTransformedMetadata( metadata, 'core/code' ),
37
40
  } );
38
41
  },
39
42
  },
@@ -60,14 +63,13 @@ const transforms = {
60
63
  {
61
64
  type: 'block',
62
65
  blocks: [ 'core/paragraph' ],
63
- transform: ( { content, metadata } ) =>
64
- createBlock( 'core/paragraph', {
66
+ transform: ( attributes ) => {
67
+ const { content } = attributes;
68
+ return createBlock( 'core/paragraph', {
69
+ ...getTransformedAttributes( attributes, 'core/paragraph' ),
65
70
  content,
66
- metadata: getTransformedMetadata(
67
- metadata,
68
- 'core/paragraph'
69
- ),
70
- } ),
71
+ } );
72
+ },
71
73
  },
72
74
  ],
73
75
  };
@@ -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
 
@@ -66,7 +65,6 @@ export const settings = {
66
65
  },
67
66
  edit,
68
67
  save,
69
- variations,
70
68
  };
71
69
 
72
70
  export const init = () => initBlock( { name, metadata, settings } );
@@ -7,7 +7,7 @@ import { createBlock, getBlockAttributes } from '@wordpress/blocks';
7
7
  * Internal dependencies
8
8
  */
9
9
  import { getLevelFromHeadingNodeName } from './shared';
10
- import { getTransformedMetadata } from '../utils/get-transformed-metadata';
10
+ import { getTransformedAttributes } from '../utils/get-transformed-attributes';
11
11
 
12
12
  const transforms = {
13
13
  from: [
@@ -16,21 +16,21 @@ const transforms = {
16
16
  isMultiBlock: true,
17
17
  blocks: [ 'core/paragraph' ],
18
18
  transform: ( attributes ) =>
19
- attributes.map(
20
- ( { content, anchor, align: textAlign, metadata } ) =>
21
- createBlock( 'core/heading', {
22
- content,
23
- anchor,
24
- textAlign,
25
- metadata: getTransformedMetadata(
26
- metadata,
27
- 'core/heading',
28
- ( { content: contentBinding } ) => ( {
29
- content: contentBinding,
30
- } )
31
- ),
32
- } )
33
- ),
19
+ attributes.map( ( _attributes ) => {
20
+ const { content, anchor, align: textAlign } = _attributes;
21
+ return createBlock( 'core/heading', {
22
+ ...getTransformedAttributes(
23
+ _attributes,
24
+ 'core/heading',
25
+ ( { content: contentBinding } ) => ( {
26
+ content: contentBinding,
27
+ } )
28
+ ),
29
+ content,
30
+ anchor,
31
+ textAlign,
32
+ } );
33
+ } ),
34
34
  },
35
35
  {
36
36
  type: 'raw',
@@ -91,19 +91,20 @@ const transforms = {
91
91
  isMultiBlock: true,
92
92
  blocks: [ 'core/paragraph' ],
93
93
  transform: ( attributes ) =>
94
- attributes.map( ( { content, textAlign: align, metadata } ) =>
95
- createBlock( 'core/paragraph', {
96
- content,
97
- align,
98
- metadata: getTransformedMetadata(
99
- metadata,
94
+ attributes.map( ( _attributes ) => {
95
+ const { content, textAlign: align } = _attributes;
96
+ return createBlock( 'core/paragraph', {
97
+ ...getTransformedAttributes(
98
+ _attributes,
100
99
  'core/paragraph',
101
100
  ( { content: contentBinding } ) => ( {
102
101
  content: contentBinding,
103
102
  } )
104
103
  ),
105
- } )
106
- ),
104
+ content,
105
+ align,
106
+ } );
107
+ } ),
107
108
  },
108
109
  ],
109
110
  };
package/src/index.js CHANGED
@@ -72,6 +72,7 @@ import * as image from './image';
72
72
  import * as latestComments from './latest-comments';
73
73
  import * as latestPosts from './latest-posts';
74
74
  import * as list from './list';
75
+ import * as math from './math';
75
76
  import * as listItem from './list-item';
76
77
  import * as logInOut from './loginout';
77
78
  import * as mediaText from './media-text';
@@ -163,7 +164,6 @@ const getAllBlocks = () => {
163
164
  accordionPanel,
164
165
  archives,
165
166
  audio,
166
- breadcrumbs,
167
167
  button,
168
168
  buttons,
169
169
  calendar,
@@ -178,6 +178,7 @@ const getAllBlocks = () => {
178
178
  file,
179
179
  group,
180
180
  html,
181
+ math,
181
182
  latestComments,
182
183
  latestPosts,
183
184
  mediaText,
@@ -254,13 +255,14 @@ const getAllBlocks = () => {
254
255
  termCount,
255
256
  termDescription,
256
257
  termName,
258
+ termsQuery,
259
+ termTemplate,
257
260
  queryTitle,
258
261
  postAuthorBiography,
259
262
  ];
260
263
 
261
264
  if ( window?.__experimentalEnableBlockExperiments ) {
262
- blocks.push( termsQuery );
263
- blocks.push( termTemplate );
265
+ blocks.push( breadcrumbs );
264
266
  }
265
267
 
266
268
  if ( window?.__experimentalEnableFormBlocks ) {
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "https://schemas.wp.org/trunk/block.json",
3
+ "apiVersion": 3,
4
+ "name": "core/math",
5
+ "title": "Math",
6
+ "category": "text",
7
+ "description": "Display mathematical notation using LaTeX.",
8
+ "keywords": [ "equation", "formula", "latex", "mathematics" ],
9
+ "textdomain": "default",
10
+ "attributes": {
11
+ "latex": {
12
+ "type": "string",
13
+ "role": "content"
14
+ },
15
+ "mathML": {
16
+ "type": "string",
17
+ "source": "html",
18
+ "selector": "math"
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,123 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+ import {
6
+ useBlockProps,
7
+ store as blockEditorStore,
8
+ } from '@wordpress/block-editor';
9
+ import {
10
+ TextareaControl,
11
+ Popover,
12
+ __experimentalVStack as VStack,
13
+ privateApis as componentsPrivateApis,
14
+ } from '@wordpress/components';
15
+ import { useState, useEffect, useRef } from '@wordpress/element';
16
+ import { useDispatch } from '@wordpress/data';
17
+
18
+ /**
19
+ * Internal dependencies
20
+ */
21
+ import { unlock } from '../lock-unlock';
22
+
23
+ const { Badge } = unlock( componentsPrivateApis );
24
+
25
+ export default function MathEdit( { attributes, setAttributes, isSelected } ) {
26
+ const { latex } = attributes;
27
+ const [ blockRef, setBlockRef ] = useState();
28
+ const [ error, setError ] = useState( null );
29
+ const [ latexToMathML, setLatexToMathML ] = useState();
30
+ const initialLatex = useRef( attributes.latex );
31
+ const { __unstableMarkNextChangeAsNotPersistent } =
32
+ useDispatch( blockEditorStore );
33
+
34
+ useEffect( () => {
35
+ import( '@wordpress/latex-to-mathml' ).then( ( module ) => {
36
+ setLatexToMathML( () => module.default );
37
+ if ( initialLatex.current ) {
38
+ __unstableMarkNextChangeAsNotPersistent();
39
+ setAttributes( {
40
+ mathML: module.default( initialLatex.current, {
41
+ displayMode: true,
42
+ } ),
43
+ } );
44
+ }
45
+ } );
46
+ }, [
47
+ initialLatex,
48
+ setAttributes,
49
+ __unstableMarkNextChangeAsNotPersistent,
50
+ ] );
51
+
52
+ const blockProps = useBlockProps( {
53
+ ref: setBlockRef,
54
+ position: 'relative',
55
+ } );
56
+
57
+ return (
58
+ <div { ...blockProps }>
59
+ { attributes.mathML ? (
60
+ <math
61
+ // We can't spread block props on the math element because
62
+ // it only supports a limited amount of global attributes.
63
+ // For example, draggable will have no effect.
64
+ display="block"
65
+ dangerouslySetInnerHTML={ { __html: attributes.mathML } }
66
+ />
67
+ ) : (
68
+ '\u200B'
69
+ ) }
70
+ { isSelected && (
71
+ <Popover
72
+ placement="bottom-start"
73
+ offset={ 8 }
74
+ anchor={ blockRef }
75
+ focusOnMount="firstContentElement"
76
+ >
77
+ <div style={ { padding: '4px', minWidth: '300px' } }>
78
+ <VStack spacing={ 1 }>
79
+ <TextareaControl
80
+ __nextHasNoMarginBottom
81
+ __next40pxDefaultSize
82
+ label={ __( 'LaTeX math syntax' ) }
83
+ hideLabelFromVision
84
+ value={ latex }
85
+ onChange={ ( newLatex ) => {
86
+ if ( ! latexToMathML ) {
87
+ setAttributes( { latex: newLatex } );
88
+ return;
89
+ }
90
+ let mathML = '';
91
+ try {
92
+ mathML = latexToMathML( newLatex, {
93
+ displayMode: true,
94
+ } );
95
+ setError( null );
96
+ } catch ( err ) {
97
+ setError( err.message );
98
+ }
99
+ setAttributes( {
100
+ mathML,
101
+ latex: newLatex,
102
+ } );
103
+ } }
104
+ placeholder={ __( 'e.g., x^2, \\frac{a}{b}' ) }
105
+ />
106
+ { error && (
107
+ <>
108
+ <Badge
109
+ intent="error"
110
+ className="wp-block-math__error"
111
+ >
112
+ { error }
113
+ </Badge>
114
+ <style children=".wp-block-math__error .components-badge__content{white-space:normal}" />
115
+ </>
116
+ ) }
117
+ </VStack>
118
+ </div>
119
+ </Popover>
120
+ ) }
121
+ </div>
122
+ );
123
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { math as icon } from '@wordpress/icons';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import initBlock from '../utils/init-block';
10
+ import edit from './edit';
11
+ import metadata from './block.json';
12
+ import save from './save';
13
+
14
+ const { name } = metadata;
15
+
16
+ export { metadata, name };
17
+
18
+ export const settings = {
19
+ icon,
20
+ example: {
21
+ attributes: {
22
+ latex: 'x = \\frac{-b \\pm \\sqrt{b^2-4ac}}{2a}',
23
+ mathML: '<semantics><mrow><mi>x</mi><mo>=</mo><mfrac><mrow><mo lspace="0em" rspace="0em">−</mo><mi>b</mi><mo>±</mo><msqrt><mrow><msup><mi>b</mi><mn>2</mn></msup><mo>−</mo><mn>4</mn><mi>a</mi><mi>c</mi></mrow></msqrt></mrow><mrow><mn>2</mn><mi>a</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">x = \\frac{-b \\pm \\sqrt{b^2-4ac}}{2a}</annotation></semantics>',
24
+ },
25
+ viewportWidth: 300,
26
+ },
27
+ edit,
28
+ save,
29
+ };
30
+
31
+ export const init = () => initBlock( { name, metadata, settings } );
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ export { init, metadata, name, settings } from './index';
@@ -0,0 +1,20 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useBlockProps } from '@wordpress/block-editor';
5
+
6
+ export default function save( { attributes } ) {
7
+ const { latex, mathML } = attributes;
8
+
9
+ if ( ! latex ) {
10
+ return null;
11
+ }
12
+
13
+ return (
14
+ <math
15
+ { ...useBlockProps.save() }
16
+ display="block"
17
+ dangerouslySetInnerHTML={ { __html: mathML } }
18
+ />
19
+ );
20
+ }
@@ -111,19 +111,20 @@ function AdditionalBlockContent( { block, insertedBlock, setInsertedBlock } ) {
111
111
  } }
112
112
  onChange={ ( updatedValue ) => {
113
113
  // updateAttributes determines the final state and returns metadata
114
- const { isEntityLink } = updateAttributes(
115
- updatedValue,
116
- setInsertedBlockAttributes( insertedBlock?.clientId ),
117
- insertedBlock?.attributes
118
- );
114
+ const { isEntityLink, attributes: updatedAttributes } =
115
+ updateAttributes(
116
+ updatedValue,
117
+ setInsertedBlockAttributes( insertedBlock?.clientId ),
118
+ insertedBlock?.attributes
119
+ );
119
120
 
120
121
  // Handle URL binding based on the final computed state
121
122
  // Only create bindings for entity links (posts, pages, taxonomies)
122
123
  // Never create bindings for custom links (manual URLs)
123
124
  if ( isEntityLink ) {
124
- createBinding();
125
+ createBinding( updatedAttributes );
125
126
  } else {
126
- clearBinding();
127
+ clearBinding( updatedAttributes );
127
128
  }
128
129
 
129
130
  setInsertedBlock( null );
@@ -543,7 +543,10 @@ export default function NavigationLinkEdit( {
543
543
  anchor={ popoverAnchor }
544
544
  onRemove={ removeLink }
545
545
  onChange={ ( updatedValue ) => {
546
- const { isEntityLink } = updateAttributes(
546
+ const {
547
+ isEntityLink,
548
+ attributes: updatedAttributes,
549
+ } = updateAttributes(
547
550
  updatedValue,
548
551
  setAttributes,
549
552
  attributes
@@ -553,9 +556,9 @@ export default function NavigationLinkEdit( {
553
556
  // Only create bindings for entity links (posts, pages, taxonomies)
554
557
  // Never create bindings for custom links (manual URLs)
555
558
  if ( isEntityLink ) {
556
- createBinding();
559
+ createBinding( updatedAttributes );
557
560
  } else {
558
- clearBinding();
561
+ clearBinding( updatedAttributes );
559
562
  }
560
563
  } }
561
564
  />
@@ -202,20 +202,6 @@ function render_block_core_navigation_link( $attributes, $content, $block ) {
202
202
  return '';
203
203
  }
204
204
 
205
- // Resolve URL binding if present
206
- $url = $attributes['url'] ?? '';
207
- if ( isset( $attributes['metadata']['bindings']['url']['source'] ) ) {
208
- $binding = $attributes['metadata']['bindings']['url'];
209
- $source = get_block_bindings_source( $binding['source'] );
210
- if ( $source ) {
211
- $source_args = $binding['args'] ?? array();
212
- $resolved_url = $source->get_value( $source_args, $block, 'url' );
213
- if ( $resolved_url ) {
214
- $url = $resolved_url;
215
- }
216
- }
217
- }
218
-
219
205
  $font_sizes = block_core_navigation_link_build_css_font_sizes( $block->context );
220
206
  $classes = array_merge(
221
207
  $font_sizes['css_classes']
@@ -227,9 +213,9 @@ function render_block_core_navigation_link( $attributes, $content, $block ) {
227
213
  $kind = empty( $attributes['kind'] ) ? 'post_type' : str_replace( '-', '_', $attributes['kind'] );
228
214
  $is_active = ! empty( $attributes['id'] ) && get_queried_object_id() === (int) $attributes['id'] && ! empty( get_queried_object()->$kind );
229
215
 
230
- if ( is_post_type_archive() && ! empty( $url ) ) {
216
+ if ( is_post_type_archive() && ! empty( $attributes['url'] ) ) {
231
217
  $queried_archive_link = get_post_type_archive_link( get_queried_object()->name );
232
- if ( $url === $queried_archive_link ) {
218
+ if ( $attributes['url'] === $queried_archive_link ) {
233
219
  $is_active = true;
234
220
  }
235
221
  }
@@ -245,8 +231,8 @@ function render_block_core_navigation_link( $attributes, $content, $block ) {
245
231
  '<a class="wp-block-navigation-item__content" ';
246
232
 
247
233
  // Start appending HTML attributes to anchor tag.
248
- if ( ! empty( $url ) ) {
249
- $html .= ' href="' . esc_url( block_core_navigation_link_maybe_urldecode( $url ) ) . '"';
234
+ if ( isset( $attributes['url'] ) ) {
235
+ $html .= ' href="' . esc_url( block_core_navigation_link_maybe_urldecode( $attributes['url'] ) ) . '"';
250
236
  }
251
237
 
252
238
  if ( $is_active ) {
@@ -78,10 +78,12 @@ function UnforwardedLinkUI( props, ref ) {
78
78
  name: postType,
79
79
  } );
80
80
 
81
- // Check if there's a URL binding with the core/entity source
81
+ // Check if there's a URL binding with the new binding sources
82
82
  // Only enable handleEntities when there's actually a binding present
83
83
  const hasUrlBinding =
84
- metadata?.bindings?.url?.source === 'core/entity' && !! id;
84
+ ( metadata?.bindings?.url?.source === 'core/post-data' ||
85
+ metadata?.bindings?.url?.source === 'core/term-data' ) &&
86
+ !! id;
85
87
 
86
88
  // Memoize link value to avoid overriding the LinkControl's internal state.
87
89
  // This is a temporary fix. See https://github.com/WordPress/gutenberg/issues/50976#issuecomment-1568226407.
@@ -16,6 +16,8 @@ import { useInstanceId } from '@wordpress/compose';
16
16
  import { safeDecodeURI } from '@wordpress/url';
17
17
  import { __unstableStripHTML as stripHTML } from '@wordpress/dom';
18
18
  import { linkOff as unlinkIcon } from '@wordpress/icons';
19
+ import { useDispatch } from '@wordpress/data';
20
+ import { store as blockEditorStore } from '@wordpress/block-editor';
19
21
 
20
22
  /**
21
23
  * Internal dependencies
@@ -79,12 +81,19 @@ export function Controls( { attributes, setAttributes, clientId } ) {
79
81
  attributes,
80
82
  } );
81
83
 
84
+ // Get direct store dispatch to bypass setBoundAttributes wrapper
85
+ const { updateBlockAttributes } = useDispatch( blockEditorStore );
86
+
82
87
  const editBoundLink = () => {
83
- // Remove the binding
88
+ // Clear the binding first
84
89
  clearBinding();
85
90
 
86
- // Clear url and id to allow picking a new entity (keep type and kind)
87
- setAttributes( { url: undefined, id: undefined } );
91
+ // Use direct store dispatch to bypass block bindings safeguards
92
+ // which prevent updates to bound attributes when calling setAttributes.
93
+ // setAttributes is actually setBoundAttributes, a wrapper function that
94
+ // processes attributes through the binding system.
95
+ // See: packages/block-editor/src/components/block-edit/edit.js
96
+ updateBlockAttributes( clientId, { url: '', id: undefined } );
88
97
  };
89
98
 
90
99
  return (
@@ -7,5 +7,8 @@
7
7
 
8
8
  export { Controls } from './controls';
9
9
  export { updateAttributes } from './update-attributes';
10
- export { useEntityBinding } from './use-entity-binding';
10
+ export {
11
+ useEntityBinding,
12
+ buildNavigationLinkEntityBinding,
13
+ } from './use-entity-binding';
11
14
  export { LinkUI } from '../link-ui';
@@ -1153,6 +1153,7 @@ describe( 'updateAttributes', () => {
1153
1153
 
1154
1154
  expect( result ).toEqual( {
1155
1155
  isEntityLink: true,
1156
+ attributes: expect.any( Object ),
1156
1157
  } );
1157
1158
  } );
1158
1159
 
@@ -1173,6 +1174,7 @@ describe( 'updateAttributes', () => {
1173
1174
 
1174
1175
  expect( result ).toEqual( {
1175
1176
  isEntityLink: false,
1177
+ attributes: expect.any( Object ),
1176
1178
  } );
1177
1179
  } );
1178
1180
 
@@ -1190,6 +1192,7 @@ describe( 'updateAttributes', () => {
1190
1192
 
1191
1193
  expect( result ).toEqual( {
1192
1194
  isEntityLink: false,
1195
+ attributes: expect.any( Object ),
1193
1196
  } );
1194
1197
  } );
1195
1198
 
@@ -1215,6 +1218,7 @@ describe( 'updateAttributes', () => {
1215
1218
  // Should return false because the link was severed and converted to custom
1216
1219
  expect( result ).toEqual( {
1217
1220
  isEntityLink: false,
1221
+ attributes: expect.any( Object ),
1218
1222
  } );
1219
1223
  } );
1220
1224
 
@@ -1240,6 +1244,7 @@ describe( 'updateAttributes', () => {
1240
1244
  // Should return true because entity link is preserved
1241
1245
  expect( result ).toEqual( {
1242
1246
  isEntityLink: true,
1247
+ attributes: expect.any( Object ),
1243
1248
  } );
1244
1249
  } );
1245
1250
 
@@ -1260,6 +1265,7 @@ describe( 'updateAttributes', () => {
1260
1265
  // mailto links have kind: 'custom', so isEntityLink should be false
1261
1266
  expect( result ).toEqual( {
1262
1267
  isEntityLink: false,
1268
+ attributes: expect.any( Object ),
1263
1269
  } );
1264
1270
  } );
1265
1271
 
@@ -1280,6 +1286,7 @@ describe( 'updateAttributes', () => {
1280
1286
  // tel links have kind: 'custom', so isEntityLink should be false
1281
1287
  expect( result ).toEqual( {
1282
1288
  isEntityLink: false,
1289
+ attributes: expect.any( Object ),
1283
1290
  } );
1284
1291
  } );
1285
1292
 
@@ -1300,6 +1307,7 @@ describe( 'updateAttributes', () => {
1300
1307
 
1301
1308
  expect( result ).toEqual( {
1302
1309
  isEntityLink: true,
1310
+ attributes: expect.any( Object ),
1303
1311
  } );
1304
1312
  } );
1305
1313
  } );