@wordpress/block-library 9.33.2-next.36001005c.0 → 9.34.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 (173) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/accordion/block.json +1 -1
  3. package/build/accordion/edit.js +11 -9
  4. package/build/accordion/edit.js.map +2 -2
  5. package/build/accordion-heading/block.json +1 -1
  6. package/build/accordion-item/block.json +2 -2
  7. package/build/accordion-panel/block.json +1 -1
  8. package/build/breadcrumbs/block.json +3 -4
  9. package/build/breadcrumbs/edit.js +43 -77
  10. package/build/breadcrumbs/edit.js.map +2 -2
  11. package/build/buttons/transforms.js +1 -0
  12. package/build/buttons/transforms.js.map +2 -2
  13. package/build/categories/edit.js +8 -4
  14. package/build/categories/edit.js.map +2 -2
  15. package/build/code/transforms.js +2 -0
  16. package/build/code/transforms.js.map +2 -2
  17. package/build/home-link/block.json +2 -1
  18. package/build/image/view.js +4 -1
  19. package/build/image/view.js.map +2 -2
  20. package/build/latest-comments/block.json +4 -3
  21. package/build/latest-comments/deprecated.js +56 -0
  22. package/build/latest-comments/deprecated.js.map +7 -0
  23. package/build/latest-comments/edit.js +16 -10
  24. package/build/latest-comments/edit.js.map +2 -2
  25. package/build/latest-comments/index.js +3 -1
  26. package/build/latest-comments/index.js.map +3 -3
  27. package/build/math/deprecated.js +54 -0
  28. package/build/math/deprecated.js.map +7 -0
  29. package/build/math/edit.js +1 -0
  30. package/build/math/edit.js.map +2 -2
  31. package/build/math/index.js +3 -1
  32. package/build/math/index.js.map +3 -3
  33. package/build/math/save.js +2 -3
  34. package/build/math/save.js.map +2 -2
  35. package/build/navigation/menu-items-to-blocks.js +8 -3
  36. package/build/navigation/menu-items-to-blocks.js.map +2 -2
  37. package/build/navigation/view.js +2 -2
  38. package/build/navigation/view.js.map +2 -2
  39. package/build/navigation-link/link-ui/page-creator.js +20 -0
  40. package/build/navigation-link/link-ui/page-creator.js.map +3 -3
  41. package/build/post-date/block.json +1 -1
  42. package/build/post-date/edit.js +11 -5
  43. package/build/post-date/edit.js.map +3 -3
  44. package/build/post-date/variations.js +4 -7
  45. package/build/post-date/variations.js.map +2 -2
  46. package/build/post-template/edit.js +13 -1
  47. package/build/post-template/edit.js.map +2 -2
  48. package/build/query/index.js +11 -1
  49. package/build/query/index.js.map +2 -2
  50. package/build/query/variations.js +16 -11
  51. package/build/query/variations.js.map +2 -2
  52. package/build/search/view.js +4 -4
  53. package/build/search/view.js.map +2 -2
  54. package/build/terms-query/edit/inspector-controls/index.js +1 -1
  55. package/build/terms-query/edit/inspector-controls/index.js.map +2 -2
  56. package/build/terms-query/edit/inspector-controls/inherit-control.js +2 -4
  57. package/build/terms-query/edit/inspector-controls/inherit-control.js.map +2 -2
  58. package/build/utils/get-transformed-attributes.js +1 -10
  59. package/build/utils/get-transformed-attributes.js.map +2 -2
  60. package/build-module/accordion/block.json +1 -1
  61. package/build-module/accordion/edit.js +11 -9
  62. package/build-module/accordion/edit.js.map +2 -2
  63. package/build-module/accordion-heading/block.json +1 -1
  64. package/build-module/accordion-item/block.json +2 -2
  65. package/build-module/accordion-panel/block.json +1 -1
  66. package/build-module/breadcrumbs/block.json +3 -4
  67. package/build-module/breadcrumbs/edit.js +44 -78
  68. package/build-module/breadcrumbs/edit.js.map +2 -2
  69. package/build-module/buttons/transforms.js +1 -0
  70. package/build-module/buttons/transforms.js.map +2 -2
  71. package/build-module/categories/edit.js +8 -4
  72. package/build-module/categories/edit.js.map +2 -2
  73. package/build-module/code/transforms.js +2 -0
  74. package/build-module/code/transforms.js.map +2 -2
  75. package/build-module/home-link/block.json +2 -1
  76. package/build-module/image/view.js +4 -1
  77. package/build-module/image/view.js.map +2 -2
  78. package/build-module/latest-comments/block.json +4 -3
  79. package/build-module/latest-comments/deprecated.js +36 -0
  80. package/build-module/latest-comments/deprecated.js.map +7 -0
  81. package/build-module/latest-comments/edit.js +17 -10
  82. package/build-module/latest-comments/edit.js.map +2 -2
  83. package/build-module/latest-comments/index.js +3 -1
  84. package/build-module/latest-comments/index.js.map +2 -2
  85. package/build-module/math/deprecated.js +34 -0
  86. package/build-module/math/deprecated.js.map +7 -0
  87. package/build-module/math/edit.js +1 -0
  88. package/build-module/math/edit.js.map +2 -2
  89. package/build-module/math/index.js +3 -1
  90. package/build-module/math/index.js.map +2 -2
  91. package/build-module/math/save.js +2 -3
  92. package/build-module/math/save.js.map +2 -2
  93. package/build-module/navigation/menu-items-to-blocks.js +8 -3
  94. package/build-module/navigation/menu-items-to-blocks.js.map +2 -2
  95. package/build-module/navigation/view.js +2 -2
  96. package/build-module/navigation/view.js.map +2 -2
  97. package/build-module/navigation-link/link-ui/page-creator.js +21 -1
  98. package/build-module/navigation-link/link-ui/page-creator.js.map +2 -2
  99. package/build-module/post-date/block.json +1 -1
  100. package/build-module/post-date/edit.js +11 -5
  101. package/build-module/post-date/edit.js.map +2 -2
  102. package/build-module/post-date/variations.js +4 -7
  103. package/build-module/post-date/variations.js.map +2 -2
  104. package/build-module/post-template/edit.js +13 -1
  105. package/build-module/post-template/edit.js.map +2 -2
  106. package/build-module/query/index.js +11 -1
  107. package/build-module/query/index.js.map +2 -2
  108. package/build-module/query/variations.js +16 -11
  109. package/build-module/query/variations.js.map +2 -2
  110. package/build-module/search/view.js +4 -4
  111. package/build-module/search/view.js.map +2 -2
  112. package/build-module/terms-query/edit/inspector-controls/index.js +1 -1
  113. package/build-module/terms-query/edit/inspector-controls/index.js.map +2 -2
  114. package/build-module/terms-query/edit/inspector-controls/inherit-control.js +2 -4
  115. package/build-module/terms-query/edit/inspector-controls/inherit-control.js.map +2 -2
  116. package/build-module/utils/get-transformed-attributes.js +1 -10
  117. package/build-module/utils/get-transformed-attributes.js.map +2 -2
  118. package/build-style/editor-rtl.css +5 -0
  119. package/build-style/editor.css +6 -0
  120. package/build-style/math/editor-rtl.css +49 -0
  121. package/build-style/math/editor.css +50 -0
  122. package/build-style/math/style-rtl.css +4 -0
  123. package/build-style/math/style.css +4 -0
  124. package/build-style/style-rtl.css +5 -0
  125. package/build-style/style.css +5 -0
  126. package/package.json +37 -37
  127. package/src/accordion/block.json +1 -1
  128. package/src/accordion/edit.js +16 -16
  129. package/src/accordion-heading/block.json +1 -1
  130. package/src/accordion-item/block.json +2 -2
  131. package/src/accordion-panel/block.json +1 -1
  132. package/src/breadcrumbs/block.json +3 -4
  133. package/src/breadcrumbs/edit.js +96 -132
  134. package/src/breadcrumbs/index.php +203 -50
  135. package/src/buttons/transforms.js +1 -0
  136. package/src/categories/edit.js +10 -6
  137. package/src/categories/index.php +1 -1
  138. package/src/code/transforms.js +2 -0
  139. package/src/editor.scss +1 -0
  140. package/src/home-link/block.json +2 -1
  141. package/src/image/index.php +9 -9
  142. package/src/image/view.js +11 -1
  143. package/src/latest-comments/block.json +4 -3
  144. package/src/latest-comments/deprecated.js +37 -0
  145. package/src/latest-comments/edit.js +17 -10
  146. package/src/latest-comments/index.js +2 -0
  147. package/src/latest-comments/index.php +11 -2
  148. package/src/math/deprecated.js +44 -0
  149. package/src/math/edit.js +1 -0
  150. package/src/math/editor.scss +7 -0
  151. package/src/math/index.js +2 -0
  152. package/src/math/save.js +6 -5
  153. package/src/math/style.scss +4 -0
  154. package/src/navigation/index.php +7 -7
  155. package/src/navigation/menu-items-to-blocks.js +12 -2
  156. package/src/navigation/test/menu-items-to-blocks.js +144 -0
  157. package/src/navigation/view.js +2 -2
  158. package/src/navigation-link/link-ui/page-creator.js +25 -2
  159. package/src/post-date/block.json +1 -1
  160. package/src/post-date/edit.js +15 -10
  161. package/src/post-date/variations.js +2 -5
  162. package/src/post-template/edit.js +13 -1
  163. package/src/query/index.js +10 -0
  164. package/src/query/variations.js +17 -11
  165. package/src/query-pagination-next/index.php +1 -1
  166. package/src/query-pagination-previous/index.php +1 -1
  167. package/src/search/index.php +2 -2
  168. package/src/search/view.js +4 -4
  169. package/src/style.scss +1 -0
  170. package/src/term-template/index.php +8 -2
  171. package/src/terms-query/edit/inspector-controls/index.js +2 -2
  172. package/src/terms-query/edit/inspector-controls/inherit-control.js +1 -3
  173. package/src/utils/get-transformed-attributes.js +5 -16
@@ -6,7 +6,7 @@ import { InspectorControls, useBlockProps } from '@wordpress/block-editor';
6
6
  import {
7
7
  ToggleControl,
8
8
  TextControl,
9
- SelectControl,
9
+ CheckboxControl,
10
10
  __experimentalToolsPanel as ToolsPanel,
11
11
  __experimentalToolsPanelItem as ToolsPanelItem,
12
12
  Spinner,
@@ -22,87 +22,72 @@ import { useServerSideRender } from '@wordpress/server-side-render';
22
22
  import { useToolsPanelDropdownMenuProps } from '../utils/hooks';
23
23
 
24
24
  const separatorDefaultValue = '/';
25
- const typeDefaultValue = 'auto';
26
-
27
- const BREADCRUMB_TYPES = {
28
- auto: {
29
- help: __(
30
- 'Try to automatically determine the best type of breadcrumb for the template.'
31
- ),
32
- },
33
- postWithAncestors: {
34
- help: __(
35
- 'Shows breadcrumbs based on post hierarchy. Only works for hierarchical post types.'
36
- ),
37
- placeholderItems: [ __( 'Ancestor' ), __( 'Parent' ) ],
38
- },
39
- postWithTerms: {
40
- help: __(
41
- 'Shows breadcrumbs based on taxonomy terms. Chooses the first taxonomy with assigned terms and includes ancestors if the taxonomy is hierarchical.'
42
- ),
43
- placeholderItems: [ __( 'Category' ) ],
44
- },
45
- };
46
25
 
47
26
  export default function BreadcrumbEdit( {
48
27
  attributes,
49
28
  setAttributes,
50
29
  context: { postId, postType, templateSlug },
51
30
  } ) {
52
- const { separator, showHomeLink, type } = attributes;
53
- const { post, isPostTypeHierarchical, hasTermsAssigned, isLoading } =
54
- useSelect(
55
- ( select ) => {
56
- if ( ! postType ) {
57
- return {};
58
- }
59
- const _post = select( coreStore ).getEntityRecord(
60
- 'postType',
61
- postType,
62
- postId
63
- );
64
- const postTypeObject =
65
- select( coreStore ).getPostType( postType );
66
- const postTypeHasTaxonomies =
67
- postTypeObject && postTypeObject.taxonomies.length;
68
- let taxonomies;
69
- if ( postTypeHasTaxonomies ) {
70
- taxonomies = select( coreStore ).getTaxonomies( {
71
- type: postType,
72
- per_page: -1,
73
- } );
74
- }
75
- return {
76
- post: _post,
77
- isPostTypeHierarchical: postTypeObject?.hierarchical,
78
- hasTermsAssigned:
79
- _post &&
80
- ( taxonomies || [] )
81
- .filter(
82
- ( { visibility } ) =>
83
- visibility?.publicly_queryable
84
- )
85
- .some( ( taxonomy ) => {
86
- return !! _post[ taxonomy.rest_base ]?.length;
87
- } ),
88
- isLoading:
89
- ! _post ||
90
- ! postTypeObject ||
91
- ( postTypeHasTaxonomies && ! taxonomies ),
92
- };
93
- },
94
- [ postType, postId ]
95
- );
31
+ const { separator, showHomeLink, prefersTaxonomy } = attributes;
32
+ const {
33
+ post,
34
+ isPostTypeHierarchical,
35
+ postTypeHasTaxonomies,
36
+ hasTermsAssigned,
37
+ isLoading,
38
+ } = useSelect(
39
+ ( select ) => {
40
+ if ( ! postType ) {
41
+ return {};
42
+ }
43
+ const _post = select( coreStore ).getEntityRecord(
44
+ 'postType',
45
+ postType,
46
+ postId
47
+ );
48
+ const postTypeObject = select( coreStore ).getPostType( postType );
49
+ const _postTypeHasTaxonomies =
50
+ postTypeObject && postTypeObject.taxonomies.length;
51
+ let taxonomies;
52
+ if ( _postTypeHasTaxonomies ) {
53
+ taxonomies = select( coreStore ).getTaxonomies( {
54
+ type: postType,
55
+ per_page: -1,
56
+ } );
57
+ }
58
+ return {
59
+ post: _post,
60
+ isPostTypeHierarchical: postTypeObject?.hierarchical,
61
+ postTypeHasTaxonomies: _postTypeHasTaxonomies,
62
+ hasTermsAssigned:
63
+ _post &&
64
+ ( taxonomies || [] )
65
+ .filter(
66
+ ( { visibility } ) => visibility?.publicly_queryable
67
+ )
68
+ .some( ( taxonomy ) => {
69
+ return !! _post[ taxonomy.rest_base ]?.length;
70
+ } ),
71
+ isLoading:
72
+ ( postId && ! _post ) ||
73
+ ! postTypeObject ||
74
+ ( _postTypeHasTaxonomies && ! taxonomies ),
75
+ };
76
+ },
77
+ [ postType, postId ]
78
+ );
96
79
 
97
- // Counter used to cache-bust `useServerSideRender`
98
- //
99
- // This is a catch-all signal to re-render the block when a post's title,
100
- // parent ID, or terms change.
101
- //
102
- // This is fundamentally imperfect, because there are other entities which
103
- // could change in the meantime (the titles of ancestor posts, or the
104
- // labels of taxonomy terms), hence the choice to re-render systematically
105
- // upon saving.
80
+ /**
81
+ * Counter used to cache-bust `useServerSideRender`.
82
+ *
83
+ * This is a catch-all signal to re-render the block when a post's title,
84
+ * parent ID, or terms change.
85
+ *
86
+ * This is fundamentally imperfect, because there are other entities which
87
+ * could change in the meantime (the titles of ancestor posts, or the
88
+ * labels of taxonomy terms), hence the choice to re-render systematically
89
+ * upon saving.
90
+ */
106
91
  const [ invalidationKey, setInvalidationKey ] = useState( 0 );
107
92
  useEffect( () => {
108
93
  setInvalidationKey( ( c ) => c + 1 );
@@ -124,18 +109,17 @@ export default function BreadcrumbEdit( {
124
109
  </div>
125
110
  );
126
111
  }
127
- // TODO: this should be handled better when we add more types.
128
- let breadcrumbsType;
129
- const isSpecificSupportedTypeSet = [
130
- 'postWithAncestors',
131
- 'postWithTerms',
132
- ].includes( type );
133
- if ( isSpecificSupportedTypeSet ) {
134
- breadcrumbsType = type;
112
+
113
+ // Determine breadcrumb type for accurate previews (matching PHP logic).
114
+ let _showTerms;
115
+ if ( ! isPostTypeHierarchical ) {
116
+ _showTerms = true;
117
+ } else if ( ! postTypeHasTaxonomies ) {
118
+ // Hierarchical post type without taxonomies can only use ancestors.
119
+ _showTerms = false;
135
120
  } else {
136
- breadcrumbsType = isPostTypeHierarchical
137
- ? 'postWithAncestors'
138
- : 'postWithTerms';
121
+ // For hierarchical post types with taxonomies, use the attribute.
122
+ _showTerms = prefersTaxonomy;
139
123
  }
140
124
  let placeholder = null;
141
125
  // This is fragile because this block is server side rendered and we'll have to
@@ -147,17 +131,20 @@ export default function BreadcrumbEdit( {
147
131
  // This is needed because when we are showing the template in post editor we
148
132
  // want to show the real breadcrumbs if we have the post type.
149
133
  ( templateSlug && ! postType ) ||
150
- ( breadcrumbsType === 'postWithAncestors' &&
151
- ! isPostTypeHierarchical ) ||
152
- ( breadcrumbsType === 'postWithTerms' && ! hasTermsAssigned );
134
+ ( ! _showTerms && ! isPostTypeHierarchical ) ||
135
+ ( _showTerms && ! hasTermsAssigned );
153
136
  if ( showPlaceholder ) {
154
- const placeholderItems = [
155
- showHomeLink && __( 'Home' ),
156
- // For now if we are adding this in a template show a generic placeholder.
157
- ...( templateSlug && ! isSpecificSupportedTypeSet
158
- ? [ __( 'Page' ) ]
159
- : BREADCRUMB_TYPES[ breadcrumbsType ].placeholderItems ),
160
- ].filter( Boolean );
137
+ const placeholderItems = [];
138
+ if ( showHomeLink ) {
139
+ placeholderItems.push( __( 'Home' ) );
140
+ }
141
+ if ( templateSlug && ! postId ) {
142
+ placeholderItems.push( __( 'Page' ) );
143
+ } else if ( _showTerms ) {
144
+ placeholderItems.push( __( 'Category' ) );
145
+ } else {
146
+ placeholderItems.push( __( 'Ancestor' ), __( 'Parent' ) );
147
+ }
161
148
  placeholder = (
162
149
  <nav
163
150
  style={ {
@@ -189,46 +176,10 @@ export default function BreadcrumbEdit( {
189
176
  setAttributes( {
190
177
  separator: separatorDefaultValue,
191
178
  showHomeLink: true,
192
- type: typeDefaultValue,
193
179
  } );
194
180
  } }
195
181
  dropdownMenuProps={ dropdownMenuProps }
196
182
  >
197
- <ToolsPanelItem
198
- label={ __( 'Type' ) }
199
- isShownByDefault
200
- hasValue={ () => type !== typeDefaultValue }
201
- onDeselect={ () =>
202
- setAttributes( {
203
- type: typeDefaultValue,
204
- } )
205
- }
206
- >
207
- <SelectControl
208
- __nextHasNoMarginBottom
209
- __next40pxDefaultSize
210
- label={ __( 'Type' ) }
211
- value={ type }
212
- onChange={ ( value ) =>
213
- setAttributes( { type: value } )
214
- }
215
- options={ [
216
- {
217
- label: __( 'Auto' ),
218
- value: 'auto',
219
- },
220
- {
221
- label: __( 'Post with ancestors' ),
222
- value: 'postWithAncestors',
223
- },
224
- {
225
- label: __( 'Post with terms' ),
226
- value: 'postWithTerms',
227
- },
228
- ] }
229
- help={ BREADCRUMB_TYPES[ type ].help }
230
- />
231
- </ToolsPanelItem>
232
183
  <ToolsPanelItem
233
184
  label={ __( 'Show home link' ) }
234
185
  isShownByDefault
@@ -278,6 +229,19 @@ export default function BreadcrumbEdit( {
278
229
  </ToolsPanelItem>
279
230
  </ToolsPanel>
280
231
  </InspectorControls>
232
+ <InspectorControls group="advanced">
233
+ <CheckboxControl
234
+ __nextHasNoMarginBottom
235
+ label={ __( 'Prefer taxonomy terms' ) }
236
+ checked={ prefersTaxonomy }
237
+ onChange={ ( value ) =>
238
+ setAttributes( { prefersTaxonomy: value } )
239
+ }
240
+ help={ __(
241
+ 'The exact type of breadcrumbs shown will vary automatically depending on the page in which this block is displayed. In the specific case of a hierarchical post type with taxonomies, the breadcrumbs can either reflect its post hierarchy (default) or the hierarchy of its assigned taxonomy terms.'
242
+ ) }
243
+ />
244
+ </InspectorControls>
281
245
  <div { ...blockProps }>
282
246
  { showPlaceholder ? (
283
247
  placeholder
@@ -17,25 +17,14 @@
17
17
  * @return string Returns the post breadcrumb for hierarchical post types.
18
18
  */
19
19
  function render_block_core_breadcrumbs( $attributes, $content, $block ) {
20
- // Exclude breadcrumbs from special contexts like archives, search, 404, etc.
20
+ // Exclude breadcrumbs from special contexts like search, 404, etc.
21
21
  // until they are explicitly supported.
22
- if ( is_archive() || is_search() || is_404() || is_home() || is_front_page() ) {
23
- return '';
24
- }
25
- if ( ! isset( $block->context['postId'] ) || ! isset( $block->context['postType'] ) ) {
22
+ if ( is_search() || is_404() || is_home() || is_front_page() ) {
26
23
  return '';
27
24
  }
28
25
 
29
- $post_id = $block->context['postId'];
30
- $post_type = $block->context['postType'];
31
-
32
- $post = get_post( $post_id );
33
- if ( ! $post ) {
34
- return '';
35
- }
36
-
37
- $type = $attributes['type'];
38
26
  $breadcrumb_items = array();
27
+
39
28
  if ( $attributes['showHomeLink'] ) {
40
29
  $breadcrumb_items[] = sprintf(
41
30
  '<a href="%s">%s</a>',
@@ -43,16 +32,52 @@ function render_block_core_breadcrumbs( $attributes, $content, $block ) {
43
32
  esc_html__( 'Home' )
44
33
  );
45
34
  }
46
- $supported_types = array( 'postWithAncestors', 'postWithTerms' );
47
- // If `type` is not set to a specific breadcrumb type, determine it based on the block's default heuristics.
48
- $breadcrumbs_type = in_array( $type, $supported_types, true ) ? $type : block_core_breadcrumbs_get_breadcrumbs_type( $post_type );
49
- if ( 'postWithAncestors' === $breadcrumbs_type ) {
50
- $breadcrumb_items = array_merge( $breadcrumb_items, block_core_breadcrumbs_get_hierarchical_post_type_breadcrumbs( $post_id ) );
35
+
36
+ // Handle archive pages (taxonomy, post type, date, author archives).
37
+ if ( is_archive() ) {
38
+ $archive_breadcrumbs = block_core_breadcrumbs_get_archive_breadcrumbs();
39
+ if ( ! empty( $archive_breadcrumbs ) ) {
40
+ $breadcrumb_items = array_merge( $breadcrumb_items, $archive_breadcrumbs );
41
+ }
51
42
  } else {
52
- $breadcrumb_items = array_merge( $breadcrumb_items, block_core_breadcrumbs_get_terms_breadcrumbs( $post_id, $post_type ) );
43
+ // Handle single post/page breadcrumbs.
44
+ if ( ! isset( $block->context['postId'] ) || ! isset( $block->context['postType'] ) ) {
45
+ return '';
46
+ }
47
+
48
+ $post_id = $block->context['postId'];
49
+ $post_type = $block->context['postType'];
50
+
51
+ $post = get_post( $post_id );
52
+ if ( ! $post ) {
53
+ return '';
54
+ }
55
+
56
+ // Determine breadcrumb type for accurate rendering (matching JavaScript logic).
57
+ $show_terms = false;
58
+ if ( ! is_post_type_hierarchical( $post_type ) ) {
59
+ $show_terms = true;
60
+ } elseif ( empty( get_object_taxonomies( $post_type, 'objects' ) ) ) {
61
+ // Hierarchical post type without taxonomies can only use ancestors.
62
+ $show_terms = false;
63
+ } else {
64
+ // For hierarchical post types with taxonomies, use the attribute.
65
+ $show_terms = $attributes['prefersTaxonomy'];
66
+ }
67
+
68
+ if ( ! $show_terms ) {
69
+ $breadcrumb_items = array_merge( $breadcrumb_items, block_core_breadcrumbs_get_hierarchical_post_type_breadcrumbs( $post_id ) );
70
+ } else {
71
+ $breadcrumb_items = array_merge( $breadcrumb_items, block_core_breadcrumbs_get_terms_breadcrumbs( $post_id, $post_type ) );
72
+ }
73
+ // Add current post title (not linked).
74
+ $breadcrumb_items[] = sprintf( '<span aria-current="page">%s</span>', get_the_title( $post ) );
75
+ }
76
+
77
+ if ( empty( $breadcrumb_items ) ) {
78
+ return '';
53
79
  }
54
- // Add current post title (not linked).
55
- $breadcrumb_items[] = sprintf( '<span aria-current="page">%s</span>', get_the_title( $post ) );
80
+
56
81
  $wrapper_attributes = get_block_wrapper_attributes(
57
82
  array(
58
83
  'style' => '--separator: "' . addcslashes( $attributes['separator'], '\\"' ) . '";',
@@ -77,19 +102,6 @@ function render_block_core_breadcrumbs( $attributes, $content, $block ) {
77
102
  return $breadcrumb_html;
78
103
  }
79
104
 
80
- /**
81
- * Determines the breadcrumb type based on the block's default heuristics.
82
- *
83
- * @since 6.9.0
84
- *
85
- * @param string $post_type The post type name.
86
- *
87
- * @return string The breadcrumb type.
88
- */
89
- function block_core_breadcrumbs_get_breadcrumbs_type( $post_type ) {
90
- return is_post_type_hierarchical( $post_type ) ? 'postWithAncestors' : 'postWithTerms';
91
- }
92
-
93
105
  /**
94
106
  * Generates breadcrumb items from hierarchical post type ancestors.
95
107
  *
@@ -114,6 +126,157 @@ function block_core_breadcrumbs_get_hierarchical_post_type_breadcrumbs( $post_id
114
126
  return $breadcrumb_items;
115
127
  }
116
128
 
129
+ /**
130
+ * Generates breadcrumb items for hierarchical term ancestors.
131
+ *
132
+ * For hierarchical taxonomies, retrieves and formats ancestor terms as breadcrumb links.
133
+ *
134
+ * @since 6.9.0
135
+ *
136
+ * @param int $term_id The term ID.
137
+ * @param string $taxonomy The taxonomy name.
138
+ *
139
+ * @return array Array of breadcrumb HTML items for ancestors.
140
+ */
141
+ function block_core_breadcrumbs_get_term_ancestors_items( $term_id, $taxonomy ) {
142
+ $breadcrumb_items = array();
143
+
144
+ // Check if taxonomy is hierarchical and add ancestor term links.
145
+ if ( is_taxonomy_hierarchical( $taxonomy ) ) {
146
+ $term_ancestors = get_ancestors( $term_id, $taxonomy, 'taxonomy' );
147
+ $term_ancestors = array_reverse( $term_ancestors );
148
+ foreach ( $term_ancestors as $ancestor_id ) {
149
+ $ancestor_term = get_term( $ancestor_id, $taxonomy );
150
+ if ( $ancestor_term && ! is_wp_error( $ancestor_term ) ) {
151
+ $breadcrumb_items[] = sprintf(
152
+ '<a href="%s">%s</a>',
153
+ esc_url( get_term_link( $ancestor_term ) ),
154
+ esc_html( $ancestor_term->name )
155
+ );
156
+ }
157
+ }
158
+ }
159
+
160
+ return $breadcrumb_items;
161
+ }
162
+
163
+ /**
164
+ * Generates breadcrumb items for archive pages.
165
+ *
166
+ * Handles taxonomy archives, post type archives, date archives, and author archives.
167
+ * For hierarchical taxonomies, includes ancestor terms in the breadcrumb trail.
168
+ *
169
+ * @since 6.9.0
170
+ *
171
+ * @return array Array of breadcrumb HTML items.
172
+ */
173
+ function block_core_breadcrumbs_get_archive_breadcrumbs() {
174
+ $breadcrumb_items = array();
175
+
176
+ // Date archive (check first since it doesn't have a queried object).
177
+ if ( is_date() ) {
178
+ $year = get_query_var( 'year' );
179
+ $month = get_query_var( 'monthnum' );
180
+ $day = get_query_var( 'day' );
181
+
182
+ // Fallback to 'm' query var for plain permalinks.
183
+ // Plain permalinks use ?m=YYYYMMDD format instead of separate query vars.
184
+ if ( ! $year ) {
185
+ $m = get_query_var( 'm' );
186
+ if ( $m ) {
187
+ $year = substr( $m, 0, 4 );
188
+ $month = substr( $m, 4, 2 );
189
+ $day = (int) substr( $m, 6, 2 );
190
+ }
191
+ }
192
+
193
+ if ( $year ) {
194
+ if ( $month ) {
195
+ // Year is linked if we have month.
196
+ $breadcrumb_items[] = sprintf(
197
+ '<a href="%s">%s</a>',
198
+ esc_url( get_year_link( $year ) ),
199
+ esc_html( $year )
200
+ );
201
+
202
+ if ( $day ) {
203
+ // Month is linked if we have day.
204
+ $breadcrumb_items[] = sprintf(
205
+ '<a href="%s">%s</a>',
206
+ esc_url( get_month_link( $year, $month ) ),
207
+ esc_html( date_i18n( 'F', mktime( 0, 0, 0, $month, 1, $year ) ) )
208
+ );
209
+ // Current day.
210
+ $breadcrumb_items[] = sprintf(
211
+ '<span aria-current="page">%s</span>',
212
+ esc_html( $day )
213
+ );
214
+ } else {
215
+ // Current month.
216
+ $breadcrumb_items[] = sprintf(
217
+ '<span aria-current="page">%s</span>',
218
+ esc_html( date_i18n( 'F', mktime( 0, 0, 0, $month, 1, $year ) ) )
219
+ );
220
+ }
221
+ } else {
222
+ // Current year only.
223
+ $breadcrumb_items[] = sprintf(
224
+ '<span aria-current="page">%s</span>',
225
+ esc_html( $year )
226
+ );
227
+ }
228
+ }
229
+
230
+ return $breadcrumb_items;
231
+ }
232
+
233
+ // For other archive types, we need a queried object.
234
+ $queried_object = get_queried_object();
235
+
236
+ if ( ! $queried_object ) {
237
+ return array();
238
+ }
239
+
240
+ // Taxonomy archive (category, tag, custom taxonomy).
241
+ if ( $queried_object instanceof WP_Term ) {
242
+ $term = $queried_object;
243
+ $taxonomy = $term->taxonomy;
244
+
245
+ // Add hierarchical term ancestors if applicable.
246
+ $breadcrumb_items = array_merge(
247
+ $breadcrumb_items,
248
+ block_core_breadcrumbs_get_term_ancestors_items( $term->term_id, $taxonomy )
249
+ );
250
+
251
+ // Add current term.
252
+ $breadcrumb_items[] = sprintf(
253
+ '<span aria-current="page">%s</span>',
254
+ esc_html( $term->name )
255
+ );
256
+ } elseif ( is_post_type_archive() ) {
257
+ // Post type archive.
258
+ $post_type = get_query_var( 'post_type' );
259
+ if ( is_array( $post_type ) ) {
260
+ $post_type = reset( $post_type );
261
+ }
262
+ $post_type_object = get_post_type_object( $post_type );
263
+ if ( $post_type_object ) {
264
+ $breadcrumb_items[] = sprintf(
265
+ '<span aria-current="page">%s</span>',
266
+ esc_html( $post_type_object->labels->name )
267
+ );
268
+ }
269
+ } elseif ( is_author() ) {
270
+ // Author archive.
271
+ $author = $queried_object;
272
+ $breadcrumb_items[] = sprintf(
273
+ '<span aria-current="page">%s</span>',
274
+ esc_html( $author->display_name )
275
+ );
276
+ }
277
+
278
+ return $breadcrumb_items;
279
+ }
117
280
 
118
281
  /**
119
282
  * Generates breadcrumb items from taxonomy terms.
@@ -158,21 +321,11 @@ function block_core_breadcrumbs_get_terms_breadcrumbs( $post_id, $post_type ) {
158
321
  if ( ! empty( $terms ) ) {
159
322
  // Use the first term (if multiple are assigned).
160
323
  $term = reset( $terms );
161
- // Check if taxonomy is hierarchical also add ancestor term links
162
- if ( is_taxonomy_hierarchical( $taxonomy_name ) ) {
163
- $term_ancestors = get_ancestors( $term->term_id, $taxonomy_name, 'taxonomy' );
164
- $term_ancestors = array_reverse( $term_ancestors );
165
- foreach ( $term_ancestors as $ancestor_id ) {
166
- $ancestor_term = get_term( $ancestor_id, $taxonomy_name );
167
- if ( $ancestor_term && ! is_wp_error( $ancestor_term ) ) {
168
- $breadcrumb_items[] = sprintf(
169
- '<a href="%s">%s</a>',
170
- esc_url( get_term_link( $ancestor_term ) ),
171
- esc_html( $ancestor_term->name )
172
- );
173
- }
174
- }
175
- }
324
+ // Add hierarchical term ancestors if applicable.
325
+ $breadcrumb_items = array_merge(
326
+ $breadcrumb_items,
327
+ block_core_breadcrumbs_get_term_ancestors_items( $term->term_id, $taxonomy_name )
328
+ );
176
329
  $breadcrumb_items[] = sprintf(
177
330
  '<a href="%s">%s</a>',
178
331
  esc_url( get_term_link( $term ) ),
@@ -47,6 +47,7 @@ const transforms = {
47
47
  const url = link?.getAttribute( 'href' );
48
48
  // Create singular button in the buttons block.
49
49
  return createBlock( 'core/button', {
50
+ ...attributes,
50
51
  ...getTransformedAttributes(
51
52
  attributes,
52
53
  'core/button',
@@ -189,12 +189,16 @@ export default function CategoriesEdit( {
189
189
  ? 'ul'
190
190
  : 'div';
191
191
 
192
- const classes = clsx( className, {
193
- 'wp-block-categories-list':
194
- !! categories?.length && ! displayAsDropdown && ! isResolving,
195
- 'wp-block-categories-dropdown':
196
- !! categories?.length && displayAsDropdown && ! isResolving,
197
- } );
192
+ const classes = clsx(
193
+ className,
194
+ `wp-block-categories-taxonomy-${ taxonomySlug }`,
195
+ {
196
+ 'wp-block-categories-list':
197
+ !! categories?.length && ! displayAsDropdown && ! isResolving,
198
+ 'wp-block-categories-dropdown':
199
+ !! categories?.length && displayAsDropdown && ! isResolving,
200
+ }
201
+ );
198
202
 
199
203
  const blockProps = useBlockProps( {
200
204
  className: classes,
@@ -79,7 +79,7 @@ function render_block_core_categories( $attributes, $content, $block ) {
79
79
  }
80
80
  }
81
81
 
82
- $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => "wp-block-categories-{$type}" ) );
82
+ $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => "wp-block-categories-{$type} wp-block-categories-taxonomy-{$attributes['taxonomy']}" ) );
83
83
 
84
84
  return sprintf(
85
85
  $wrapper_markup,
@@ -22,6 +22,7 @@ const transforms = {
22
22
  transform: ( attributes ) => {
23
23
  const { content } = attributes;
24
24
  return createBlock( 'core/code', {
25
+ ...attributes,
25
26
  ...getTransformedAttributes( attributes, 'core/code' ),
26
27
  content,
27
28
  } );
@@ -33,6 +34,7 @@ const transforms = {
33
34
  transform: ( attributes ) => {
34
35
  const { content: text } = attributes;
35
36
  return createBlock( 'core/code', {
37
+ ...attributes,
36
38
  ...getTransformedAttributes( attributes, 'core/code' ),
37
39
  // The HTML is plain text (with plain line breaks), so
38
40
  // convert it to rich text.
package/src/editor.scss CHANGED
@@ -24,6 +24,7 @@
24
24
  @use "./html/editor.scss" as *;
25
25
  @use "./image/editor.scss" as *;
26
26
  @use "./latest-posts/editor.scss" as *;
27
+ @use "./math/editor.scss" as *;
27
28
  @use "./media-text/editor.scss" as *;
28
29
  @use "./more/editor.scss" as *;
29
30
  @use "./navigation/editor.scss" as *;
@@ -9,7 +9,8 @@
9
9
  "textdomain": "default",
10
10
  "attributes": {
11
11
  "label": {
12
- "type": "string"
12
+ "type": "string",
13
+ "role": "content"
13
14
  }
14
15
  },
15
16
  "usesContext": [