@wordpress/block-library 9.30.1-next.a730c9c8c.0 → 9.31.1-next.233ccab9b.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 (232) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/accordion/edit.js +6 -5
  3. package/build/accordion/edit.js.map +1 -1
  4. package/build/accordion/index.js +39 -4
  5. package/build/accordion/index.js.map +1 -1
  6. package/build/accordion/save.js +2 -19
  7. package/build/accordion/save.js.map +1 -1
  8. package/build/accordion/view.js +50 -16
  9. package/build/accordion/view.js.map +1 -1
  10. package/build/accordion-content/index.js +17 -3
  11. package/build/accordion-content/index.js.map +1 -1
  12. package/build/accordion-content/save.js +5 -7
  13. package/build/accordion-content/save.js.map +1 -1
  14. package/build/accordion-header/edit.js +13 -47
  15. package/build/accordion-header/edit.js.map +1 -1
  16. package/build/accordion-header/index.js +6 -11
  17. package/build/accordion-header/index.js.map +1 -1
  18. package/build/accordion-header/save.js +11 -44
  19. package/build/accordion-header/save.js.map +1 -1
  20. package/build/accordion-panel/edit.js +2 -1
  21. package/build/accordion-panel/edit.js.map +1 -1
  22. package/build/accordion-panel/index.js +3 -3
  23. package/build/accordion-panel/index.js.map +1 -1
  24. package/build/accordion-panel/save.js +3 -1
  25. package/build/accordion-panel/save.js.map +1 -1
  26. package/build/avatar/hooks.js +7 -17
  27. package/build/avatar/hooks.js.map +1 -1
  28. package/build/group/variations.js +3 -4
  29. package/build/group/variations.js.map +1 -1
  30. package/build/navigation/edit/leaf-more-menu.js +6 -1
  31. package/build/navigation/edit/leaf-more-menu.js.map +1 -1
  32. package/build/navigation/index.js +2 -1
  33. package/build/navigation/index.js.map +1 -1
  34. package/build/navigation-link/index.js +2 -1
  35. package/build/navigation-link/index.js.map +1 -1
  36. package/build/navigation-submenu/edit.js +2 -4
  37. package/build/navigation-submenu/edit.js.map +1 -1
  38. package/build/navigation-submenu/index.js +2 -1
  39. package/build/navigation-submenu/index.js.map +1 -1
  40. package/build/page-list/index.js +2 -1
  41. package/build/page-list/index.js.map +1 -1
  42. package/build/post-author/edit.js +7 -6
  43. package/build/post-author/edit.js.map +1 -1
  44. package/build/post-date/edit.js +16 -3
  45. package/build/post-date/edit.js.map +1 -1
  46. package/build/post-time-to-read/edit.js +111 -11
  47. package/build/post-time-to-read/edit.js.map +1 -1
  48. package/build/post-time-to-read/index.js +17 -1
  49. package/build/post-time-to-read/index.js.map +1 -1
  50. package/build/table-of-contents/index.js +1 -0
  51. package/build/table-of-contents/index.js.map +1 -1
  52. package/build/term-description/edit.js +18 -2
  53. package/build/term-description/edit.js.map +1 -1
  54. package/build/term-description/index.js +1 -0
  55. package/build/term-description/index.js.map +1 -1
  56. package/build/term-description/use-term-description.js +85 -0
  57. package/build/term-description/use-term-description.js.map +1 -0
  58. package/build/term-template/edit.js +11 -7
  59. package/build/term-template/edit.js.map +1 -1
  60. package/build/term-template/index.js +1 -1
  61. package/build/terms-query/index.js +8 -2
  62. package/build/terms-query/index.js.map +1 -1
  63. package/build/terms-query/inspector-controls/advanced-controls.js +51 -0
  64. package/build/terms-query/inspector-controls/advanced-controls.js.map +1 -0
  65. package/build/terms-query/inspector-controls/display-options.js +87 -0
  66. package/build/terms-query/inspector-controls/display-options.js.map +1 -0
  67. package/build/terms-query/inspector-controls/empty-terms-control.js +38 -0
  68. package/build/terms-query/inspector-controls/empty-terms-control.js.map +1 -0
  69. package/build/terms-query/inspector-controls/hierarchy-control.js +40 -0
  70. package/build/terms-query/inspector-controls/hierarchy-control.js.map +1 -0
  71. package/build/terms-query/inspector-controls/index.js +127 -0
  72. package/build/terms-query/inspector-controls/index.js.map +1 -0
  73. package/build/terms-query/inspector-controls/max-terms-control.js +50 -0
  74. package/build/terms-query/inspector-controls/max-terms-control.js.map +1 -0
  75. package/build/terms-query/inspector-controls/ordering-controls.js +57 -0
  76. package/build/terms-query/inspector-controls/ordering-controls.js.map +1 -0
  77. package/build/terms-query/inspector-controls/taxonomy-control.js +52 -0
  78. package/build/terms-query/inspector-controls/taxonomy-control.js.map +1 -0
  79. package/build/utils/hooks.js +15 -0
  80. package/build/utils/hooks.js.map +1 -1
  81. package/build-module/accordion/edit.js +6 -5
  82. package/build-module/accordion/edit.js.map +1 -1
  83. package/build-module/accordion/index.js +40 -4
  84. package/build-module/accordion/index.js.map +1 -1
  85. package/build-module/accordion/save.js +2 -17
  86. package/build-module/accordion/save.js.map +1 -1
  87. package/build-module/accordion/view.js +51 -17
  88. package/build-module/accordion/view.js.map +1 -1
  89. package/build-module/accordion-content/index.js +17 -3
  90. package/build-module/accordion-content/index.js.map +1 -1
  91. package/build-module/accordion-content/save.js +5 -7
  92. package/build-module/accordion-content/save.js.map +1 -1
  93. package/build-module/accordion-header/edit.js +14 -45
  94. package/build-module/accordion-header/edit.js.map +1 -1
  95. package/build-module/accordion-header/index.js +6 -11
  96. package/build-module/accordion-header/index.js.map +1 -1
  97. package/build-module/accordion-header/save.js +12 -42
  98. package/build-module/accordion-header/save.js.map +1 -1
  99. package/build-module/accordion-panel/edit.js +2 -1
  100. package/build-module/accordion-panel/edit.js.map +1 -1
  101. package/build-module/accordion-panel/index.js +3 -3
  102. package/build-module/accordion-panel/index.js.map +1 -1
  103. package/build-module/accordion-panel/save.js +3 -1
  104. package/build-module/accordion-panel/save.js.map +1 -1
  105. package/build-module/avatar/hooks.js +5 -15
  106. package/build-module/avatar/hooks.js.map +1 -1
  107. package/build-module/group/variations.js +3 -4
  108. package/build-module/group/variations.js.map +1 -1
  109. package/build-module/navigation/edit/leaf-more-menu.js +6 -1
  110. package/build-module/navigation/edit/leaf-more-menu.js.map +1 -1
  111. package/build-module/navigation/index.js +2 -1
  112. package/build-module/navigation/index.js.map +1 -1
  113. package/build-module/navigation-link/index.js +2 -1
  114. package/build-module/navigation-link/index.js.map +1 -1
  115. package/build-module/navigation-submenu/edit.js +1 -3
  116. package/build-module/navigation-submenu/edit.js.map +1 -1
  117. package/build-module/navigation-submenu/index.js +2 -1
  118. package/build-module/navigation-submenu/index.js.map +1 -1
  119. package/build-module/page-list/index.js +2 -1
  120. package/build-module/page-list/index.js.map +1 -1
  121. package/build-module/post-author/edit.js +8 -7
  122. package/build-module/post-author/edit.js.map +1 -1
  123. package/build-module/post-date/edit.js +17 -4
  124. package/build-module/post-date/edit.js.map +1 -1
  125. package/build-module/post-time-to-read/edit.js +112 -14
  126. package/build-module/post-time-to-read/edit.js.map +1 -1
  127. package/build-module/post-time-to-read/index.js +17 -1
  128. package/build-module/post-time-to-read/index.js.map +1 -1
  129. package/build-module/table-of-contents/index.js +1 -0
  130. package/build-module/table-of-contents/index.js.map +1 -1
  131. package/build-module/term-description/edit.js +18 -2
  132. package/build-module/term-description/edit.js.map +1 -1
  133. package/build-module/term-description/index.js +1 -0
  134. package/build-module/term-description/index.js.map +1 -1
  135. package/build-module/term-description/use-term-description.js +79 -0
  136. package/build-module/term-description/use-term-description.js.map +1 -0
  137. package/build-module/term-template/edit.js +11 -7
  138. package/build-module/term-template/edit.js.map +1 -1
  139. package/build-module/term-template/index.js +1 -1
  140. package/build-module/terms-query/index.js +8 -2
  141. package/build-module/terms-query/index.js.map +1 -1
  142. package/build-module/terms-query/inspector-controls/advanced-controls.js +44 -0
  143. package/build-module/terms-query/inspector-controls/advanced-controls.js.map +1 -0
  144. package/build-module/terms-query/inspector-controls/display-options.js +80 -0
  145. package/build-module/terms-query/inspector-controls/display-options.js.map +1 -0
  146. package/build-module/terms-query/inspector-controls/empty-terms-control.js +31 -0
  147. package/build-module/terms-query/inspector-controls/empty-terms-control.js.map +1 -0
  148. package/build-module/terms-query/inspector-controls/hierarchy-control.js +33 -0
  149. package/build-module/terms-query/inspector-controls/hierarchy-control.js.map +1 -0
  150. package/build-module/terms-query/inspector-controls/index.js +119 -0
  151. package/build-module/terms-query/inspector-controls/index.js.map +1 -0
  152. package/build-module/terms-query/inspector-controls/max-terms-control.js +43 -0
  153. package/build-module/terms-query/inspector-controls/max-terms-control.js.map +1 -0
  154. package/build-module/terms-query/inspector-controls/ordering-controls.js +50 -0
  155. package/build-module/terms-query/inspector-controls/ordering-controls.js.map +1 -0
  156. package/build-module/terms-query/inspector-controls/taxonomy-control.js +45 -0
  157. package/build-module/terms-query/inspector-controls/taxonomy-control.js.map +1 -0
  158. package/build-module/utils/hooks.js +14 -0
  159. package/build-module/utils/hooks.js.map +1 -1
  160. package/build-style/accordion-content/style-rtl.css +155 -0
  161. package/build-style/accordion-content/style.css +155 -0
  162. package/build-style/{accordion → accordion-header}/style-rtl.css +12 -51
  163. package/build-style/{accordion → accordion-header}/style.css +12 -51
  164. package/build-style/accordion-panel/style-rtl.css +140 -0
  165. package/build-style/accordion-panel/style.css +140 -0
  166. package/build-style/style-rtl.css +25 -38
  167. package/build-style/style.css +25 -38
  168. package/package.json +35 -35
  169. package/src/accordion/block.json +16 -3
  170. package/src/accordion/edit.js +39 -34
  171. package/src/accordion/index.js +35 -1
  172. package/src/accordion/index.php +3 -19
  173. package/src/accordion/save.js +2 -16
  174. package/src/accordion/view.js +64 -15
  175. package/src/accordion-content/block.json +17 -3
  176. package/src/accordion-content/index.php +3 -2
  177. package/src/accordion-content/save.js +4 -10
  178. package/src/accordion-content/style.scss +21 -0
  179. package/src/accordion-header/block.json +6 -11
  180. package/src/accordion-header/edit.js +17 -61
  181. package/src/accordion-header/save.js +24 -54
  182. package/src/accordion-header/style.scss +39 -0
  183. package/src/accordion-panel/block.json +3 -3
  184. package/src/accordion-panel/edit.js +1 -0
  185. package/src/accordion-panel/save.js +3 -1
  186. package/src/accordion-panel/style.scss +8 -0
  187. package/src/avatar/hooks.js +5 -10
  188. package/src/comments/index.php +2 -2
  189. package/src/group/variations.js +3 -14
  190. package/src/navigation/block.json +2 -1
  191. package/src/navigation/edit/leaf-more-menu.js +9 -1
  192. package/src/navigation/index.php +2 -2
  193. package/src/navigation-link/block.json +2 -1
  194. package/src/navigation-submenu/block.json +2 -1
  195. package/src/navigation-submenu/edit.js +1 -4
  196. package/src/page-list/block.json +2 -1
  197. package/src/post-author/edit.js +16 -7
  198. package/src/post-date/edit.js +16 -16
  199. package/src/post-time-to-read/block.json +17 -1
  200. package/src/post-time-to-read/edit.js +167 -20
  201. package/src/post-time-to-read/index.php +47 -15
  202. package/src/social-link/index.php +2 -2
  203. package/src/style.scss +3 -1
  204. package/src/table-of-contents/block.json +1 -0
  205. package/src/table-of-contents/index.php +44 -0
  206. package/src/term-description/block.json +1 -0
  207. package/src/term-description/edit.js +18 -3
  208. package/src/term-description/use-term-description.js +109 -0
  209. package/src/term-template/block.json +1 -1
  210. package/src/term-template/edit.js +11 -6
  211. package/src/term-template/index.php +13 -7
  212. package/src/terms-query/block.json +8 -2
  213. package/src/terms-query/inspector-controls/advanced-controls.js +37 -0
  214. package/src/terms-query/inspector-controls/display-options.js +87 -0
  215. package/src/terms-query/inspector-controls/empty-terms-control.js +30 -0
  216. package/src/terms-query/inspector-controls/hierarchy-control.js +30 -0
  217. package/src/terms-query/inspector-controls/index.js +137 -0
  218. package/src/terms-query/inspector-controls/max-terms-control.js +44 -0
  219. package/src/terms-query/inspector-controls/ordering-controls.js +55 -0
  220. package/src/terms-query/inspector-controls/taxonomy-control.js +41 -0
  221. package/src/utils/hooks.js +9 -0
  222. package/build/accordion-content/icons.js +0 -30
  223. package/build/accordion-content/icons.js.map +0 -1
  224. package/build/terms-query/inspector-controls.js +0 -231
  225. package/build/terms-query/inspector-controls.js.map +0 -1
  226. package/build-module/accordion-content/icons.js +0 -22
  227. package/build-module/accordion-content/icons.js.map +0 -1
  228. package/build-module/terms-query/inspector-controls.js +0 -224
  229. package/build-module/terms-query/inspector-controls.js.map +0 -1
  230. package/src/accordion/style.scss +0 -82
  231. package/src/accordion-content/icons.js +0 -23
  232. package/src/terms-query/inspector-controls.js +0 -239
@@ -0,0 +1,44 @@
1
+ <?php
2
+ /**
3
+ * Server-side rendering of the `core/table-of-contents` block.
4
+ *
5
+ * @package WordPress
6
+ */
7
+
8
+ /**
9
+ * Adds an aria-label to the table of contents block content.
10
+ *
11
+ * @param array $attributes Attributes of the block being rendered.
12
+ * @param string $content Content of the block being rendered.
13
+ *
14
+ * @return string The content of the block being rendered.
15
+ */
16
+ function block_core_table_of_contents_render( $attributes, $content ) {
17
+ if ( ! $content ) {
18
+ return $content;
19
+ }
20
+
21
+ // Get the aria-label from block attributes, or fallback to localized default.
22
+ $aria_label = empty( $attributes['ariaLabel'] ) ? __( 'Table of Contents' ) : wp_strip_all_tags( $attributes['ariaLabel'] );
23
+
24
+ $p = new WP_HTML_Tag_Processor( $content );
25
+
26
+ if ( $p->next_tag( 'nav' ) ) {
27
+ $p->set_attribute( 'aria-label', $aria_label );
28
+ }
29
+
30
+ return $p->get_updated_html();
31
+ }
32
+
33
+ /**
34
+ * Registers the `core/table-of-contents` block on the server.
35
+ */
36
+ function register_block_core_table_of_contents() {
37
+ register_block_type_from_metadata(
38
+ __DIR__ . '/table-of-contents',
39
+ array(
40
+ 'render_callback' => 'block_core_table_of_contents_render',
41
+ )
42
+ );
43
+ }
44
+ add_action( 'init', 'register_block_core_table_of_contents' );
@@ -6,6 +6,7 @@
6
6
  "category": "theme",
7
7
  "description": "Display the description of categories, tags and custom taxonomies when viewing an archive.",
8
8
  "textdomain": "default",
9
+ "usesContext": [ "termId", "taxonomy" ],
9
10
  "attributes": {
10
11
  "textAlign": {
11
12
  "type": "string"
@@ -13,18 +13,27 @@ import {
13
13
  AlignmentControl,
14
14
  } from '@wordpress/block-editor';
15
15
 
16
+ /**
17
+ * Internal dependencies
18
+ */
19
+ import { useTermDescription } from './use-term-description';
20
+
16
21
  export default function TermDescriptionEdit( {
17
22
  attributes,
18
23
  setAttributes,
19
24
  mergedStyle,
25
+ context: { termId, taxonomy },
20
26
  } ) {
21
27
  const { textAlign } = attributes;
28
+ const { termDescription } = useTermDescription( termId, taxonomy );
29
+
22
30
  const blockProps = useBlockProps( {
23
31
  className: clsx( {
24
32
  [ `has-text-align-${ textAlign }` ]: textAlign,
25
33
  } ),
26
34
  style: mergedStyle,
27
35
  } );
36
+
28
37
  return (
29
38
  <>
30
39
  <BlockControls group="block">
@@ -36,9 +45,15 @@ export default function TermDescriptionEdit( {
36
45
  />
37
46
  </BlockControls>
38
47
  <div { ...blockProps }>
39
- <div className="wp-block-term-description__placeholder">
40
- <span>{ __( 'Term Description' ) }</span>
41
- </div>
48
+ { termDescription ? (
49
+ <div
50
+ dangerouslySetInnerHTML={ { __html: termDescription } }
51
+ />
52
+ ) : (
53
+ <div className="wp-block-term-description__placeholder">
54
+ <span>{ __( 'Term Description' ) }</span>
55
+ </div>
56
+ ) }
42
57
  </div>
43
58
  </>
44
59
  );
@@ -0,0 +1,109 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { store as coreStore, useEntityProp } from '@wordpress/core-data';
5
+ import { useSelect } from '@wordpress/data';
6
+
7
+ /**
8
+ * Hook to fetch term description based on context or fallback to template parsing.
9
+ *
10
+ * This hook prioritizes context-provided termId and taxonomy, but falls back to
11
+ * template-based detection when no context is available.
12
+ *
13
+ * @param {string|number} termId The term ID from context
14
+ * @param {string} taxonomy The taxonomy name from context
15
+ */
16
+ export function useTermDescription( termId, taxonomy ) {
17
+ const [ description, setDescription, fullDescription ] = useEntityProp(
18
+ 'taxonomy',
19
+ taxonomy,
20
+ 'description',
21
+ termId
22
+ );
23
+
24
+ // Fallback approach: Parse template slug when no context is available.
25
+ const templateBasedData = useTemplateBasedTermData();
26
+
27
+ const hasContext = Boolean( termId && taxonomy );
28
+
29
+ return {
30
+ hasContext,
31
+ setDescription,
32
+ termDescription: hasContext
33
+ ? fullDescription?.rendered || description || ''
34
+ : templateBasedData,
35
+ };
36
+ }
37
+
38
+ /**
39
+ * Fallback hook to fetch term data from template context (backward compatibility).
40
+ * This maintains the same logic as the original implementation for cases where
41
+ * no termId/taxonomy context is provided.
42
+ */
43
+ function useTemplateBasedTermData() {
44
+ const templateSlug = useSelect( ( select ) => {
45
+ // Access core/editor by string to avoid @wordpress/editor dependency.
46
+ // eslint-disable-next-line @wordpress/data-no-store-string-literals
47
+ const { getCurrentPostId, getCurrentPostType, getCurrentTemplateId } =
48
+ select( 'core/editor' );
49
+ const currentPostType = getCurrentPostType();
50
+ const templateId =
51
+ getCurrentTemplateId() ||
52
+ ( currentPostType === 'wp_template' ? getCurrentPostId() : null );
53
+
54
+ return templateId
55
+ ? select( coreStore ).getEditedEntityRecord(
56
+ 'postType',
57
+ 'wp_template',
58
+ templateId
59
+ )?.slug
60
+ : null;
61
+ }, [] );
62
+
63
+ const taxonomyMatches = templateSlug?.match(
64
+ /^(category|tag|taxonomy-([^-]+))$|^(((category|tag)|taxonomy-([^-]+))-(.+))$/
65
+ );
66
+
67
+ let taxonomy;
68
+ let termSlug;
69
+
70
+ if ( taxonomyMatches ) {
71
+ // If it's for all taxonomies of a type (e.g., category, tag).
72
+ if ( taxonomyMatches[ 1 ] ) {
73
+ taxonomy = taxonomyMatches[ 2 ]
74
+ ? taxonomyMatches[ 2 ]
75
+ : taxonomyMatches[ 1 ];
76
+ }
77
+ // If it's for a specific term (e.g., category-news, tag-featured).
78
+ else if ( taxonomyMatches[ 3 ] ) {
79
+ taxonomy = taxonomyMatches[ 6 ]
80
+ ? taxonomyMatches[ 6 ]
81
+ : taxonomyMatches[ 4 ];
82
+ termSlug = taxonomyMatches[ 7 ];
83
+ }
84
+
85
+ taxonomy = taxonomy === 'tag' ? 'post_tag' : taxonomy;
86
+ }
87
+
88
+ return useSelect(
89
+ ( select ) => {
90
+ if ( ! taxonomy || ! termSlug ) {
91
+ return '';
92
+ }
93
+
94
+ const { getEntityRecords } = select( coreStore );
95
+
96
+ const termRecords = getEntityRecords( 'taxonomy', taxonomy, {
97
+ slug: termSlug,
98
+ per_page: 1,
99
+ } );
100
+
101
+ if ( termRecords && termRecords[ 0 ] ) {
102
+ return termRecords[ 0 ].description || '';
103
+ }
104
+
105
+ return '';
106
+ },
107
+ [ taxonomy, termSlug ]
108
+ );
109
+ }
@@ -8,7 +8,7 @@
8
8
  "ancestor": [ "core/terms-query" ],
9
9
  "description": "Contains the block elements used to render a taxonomy term, like the name, description, and more.",
10
10
  "textdomain": "default",
11
- "usesContext": [ "termQuery" ],
11
+ "usesContext": [ "termQuery", "termsToShow" ],
12
12
  "attributes": {
13
13
  "namespace": {
14
14
  "type": "string"
@@ -191,13 +191,13 @@ export default function TermTemplateEdit( {
191
191
  clientId,
192
192
  setAttributes,
193
193
  context: {
194
+ termsToShow,
194
195
  termQuery: {
195
196
  taxonomy,
196
197
  order,
197
198
  orderBy,
198
199
  hideEmpty,
199
200
  hierarchical,
200
- parent,
201
201
  perPage = 10,
202
202
  } = {},
203
203
  },
@@ -222,13 +222,18 @@ export default function TermTemplateEdit( {
222
222
  queryArgs
223
223
  );
224
224
 
225
- // Filter to show only top-level terms if "Show only top-level terms" is enabled.
226
225
  const filteredTerms = useMemo( () => {
227
- if ( ! terms || parent !== 0 ) {
228
- return terms;
226
+ if ( ! terms ) {
227
+ return [];
229
228
  }
230
- return terms.filter( ( term ) => ! term.parent );
231
- }, [ terms, parent ] );
229
+ if ( termsToShow === 'top-level' ) {
230
+ return terms.filter( ( term ) => ! term.parent );
231
+ }
232
+ if ( termsToShow === 'subterms' ) {
233
+ return terms.filter( ( term ) => term.parent );
234
+ }
235
+ return terms;
236
+ }, [ terms, termsToShow ] );
232
237
 
233
238
  const { blocks, variations, defaultVariation } = useSelect(
234
239
  ( select ) => {
@@ -27,7 +27,8 @@ function render_block_core_term_template( $attributes, $content, $block ) {
27
27
  return '';
28
28
  }
29
29
 
30
- $query = $query_block_context['termQuery'];
30
+ $query = $query_block_context['termQuery'];
31
+ $terms_to_show = $query_block_context['termsToShow'] ?? 'all';
31
32
 
32
33
  $query_args = array(
33
34
  'taxonomy' => $query['taxonomy'] ?? 'category',
@@ -39,13 +40,18 @@ function render_block_core_term_template( $attributes, $content, $block ) {
39
40
  'exclude' => $query['exclude'] ?? array(),
40
41
  );
41
42
 
42
- // Handle parent.
43
- if ( ! empty( $query['hierarchical'] ) && isset( $query['parent'] ) ) {
44
- $query_args['parent'] = $query['parent'];
45
- } elseif ( ! empty( $query['hierarchical'] ) ) {
43
+ // We set parent to 0 only if we show all terms as hierarchical or we show top-level terms.
44
+ if ( ( 'all' === $terms_to_show && ! empty( $query['hierarchical'] ) ) || 'top-level' === $terms_to_show ) {
46
45
  $query_args['parent'] = 0;
47
- } elseif ( isset( $query['parent'] ) ) {
48
- $query_args['parent'] = $query['parent'];
46
+ } elseif ( 'subterms' === $terms_to_show ) {
47
+ // Check if we're in a taxonomy archive context.
48
+ if ( is_tax( $query_args['taxonomy'] ) ) {
49
+ // Get the current term ID from the queried object.
50
+ $current_term_id = get_queried_object_id();
51
+ if ( $current_term_id && $current_term_id > 0 ) {
52
+ $query_args['parent'] = $current_term_id;
53
+ }
54
+ }
49
55
  }
50
56
 
51
57
  $terms_query = new WP_Term_Query( $query_args );
@@ -23,10 +23,15 @@
23
23
  "hideEmpty": true,
24
24
  "include": [],
25
25
  "exclude": [],
26
- "parent": 0,
26
+ "parent": false,
27
27
  "hierarchical": false
28
28
  }
29
29
  },
30
+ "termsToShow": {
31
+ "type": "string",
32
+ "default": "all",
33
+ "enum": [ "all", "top-level", "subterms" ]
34
+ },
30
35
  "tagName": {
31
36
  "type": "string",
32
37
  "default": "div"
@@ -37,7 +42,8 @@
37
42
  },
38
43
  "providesContext": {
39
44
  "termQueryId": "termQueryId",
40
- "termQuery": "termQuery"
45
+ "termQuery": "termQuery",
46
+ "termsToShow": "termsToShow"
41
47
  },
42
48
  "supports": {
43
49
  "align": [ "wide", "full" ],
@@ -0,0 +1,37 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+ import {
6
+ InspectorControls,
7
+ privateApis as blockEditorPrivateApis,
8
+ } from '@wordpress/block-editor';
9
+
10
+ /**
11
+ * Internal dependencies
12
+ */
13
+ import { unlock } from '../../lock-unlock';
14
+
15
+ const { HTMLElementControl } = unlock( blockEditorPrivateApis );
16
+
17
+ export default function AdvancedControls( {
18
+ TagName,
19
+ setAttributes,
20
+ clientId,
21
+ } ) {
22
+ return (
23
+ <InspectorControls group="advanced">
24
+ <HTMLElementControl
25
+ tagName={ TagName }
26
+ onChange={ ( value ) => setAttributes( { tagName: value } ) }
27
+ clientId={ clientId }
28
+ options={ [
29
+ { label: __( 'Default (<div>)' ), value: 'div' },
30
+ { label: '<main>', value: 'main' },
31
+ { label: '<section>', value: 'section' },
32
+ { label: '<aside>', value: 'aside' },
33
+ ] }
34
+ />
35
+ </InspectorControls>
36
+ );
37
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+ import {
6
+ __experimentalToolsPanelItem as ToolsPanelItem,
7
+ RadioControl,
8
+ } from '@wordpress/components';
9
+
10
+ const getOptions = ( displayTopLevelControl, displaySubtermsControl ) => {
11
+ const options = [ { label: __( 'Show all' ), value: 'all' } ];
12
+
13
+ if ( displayTopLevelControl ) {
14
+ options.push( {
15
+ label: __( 'Show only top level terms' ),
16
+ value: 'top-level',
17
+ } );
18
+ }
19
+
20
+ if ( displaySubtermsControl ) {
21
+ options.push( {
22
+ label: __( 'Show subterms only' ),
23
+ value: 'subterms',
24
+ description: __(
25
+ 'Display subterms of the current term. E.g. subcategories of current category.'
26
+ ),
27
+ } );
28
+ }
29
+
30
+ return options;
31
+ };
32
+
33
+ const allTermsQuery = {
34
+ include: [],
35
+ exclude: [],
36
+ parent: false,
37
+ };
38
+
39
+ const topLevelTermsQuery = {
40
+ include: [],
41
+ exclude: [],
42
+ parent: 0,
43
+ hierarchical: false,
44
+ };
45
+
46
+ const getQueryAttributes = ( value ) => {
47
+ if ( value === 'top-level' ) {
48
+ return topLevelTermsQuery;
49
+ }
50
+
51
+ // For 'all' and 'subterms', we fetch all terms and then filter them as the tree is built in Term Template.
52
+ return allTermsQuery;
53
+ };
54
+
55
+ export default function DisplayOptions( {
56
+ attributes,
57
+ displayTopLevelControl,
58
+ displaySubtermsControl,
59
+ setAttributes,
60
+ } ) {
61
+ const { termQuery, termsToShow } = attributes;
62
+
63
+ return (
64
+ <ToolsPanelItem
65
+ hasValue={ () => termsToShow !== 'all' }
66
+ label={ __( 'Terms to show' ) }
67
+ onDeselect={ () => setAttributes( { termsToShow: 'all' } ) }
68
+ isShownByDefault
69
+ >
70
+ <RadioControl
71
+ label={ __( 'Terms to show' ) }
72
+ options={ getOptions(
73
+ displayTopLevelControl,
74
+ displaySubtermsControl
75
+ ) }
76
+ selected={ termsToShow }
77
+ onChange={ ( value ) => {
78
+ const queryAttributes = getQueryAttributes( value );
79
+ setAttributes( {
80
+ termsToShow: value,
81
+ termQuery: { ...termQuery, ...queryAttributes },
82
+ } );
83
+ } }
84
+ />
85
+ </ToolsPanelItem>
86
+ );
87
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+ import {
6
+ __experimentalToolsPanelItem as ToolsPanelItem,
7
+ ToggleControl,
8
+ } from '@wordpress/components';
9
+
10
+ export default function EmptyTermsControl( { attributes, setQuery } ) {
11
+ const { termQuery } = attributes;
12
+
13
+ return (
14
+ <ToolsPanelItem
15
+ hasValue={ () => termQuery.hideEmpty !== true }
16
+ label={ __( 'Show empty terms' ) }
17
+ onDeselect={ () => setQuery( { hideEmpty: true } ) }
18
+ isShownByDefault
19
+ >
20
+ <ToggleControl
21
+ __nextHasNoMarginBottom
22
+ label={ __( 'Show empty terms' ) }
23
+ checked={ ! termQuery.hideEmpty }
24
+ onChange={ ( showEmpty ) =>
25
+ setQuery( { hideEmpty: ! showEmpty } )
26
+ }
27
+ />
28
+ </ToolsPanelItem>
29
+ );
30
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+ import {
6
+ __experimentalToolsPanelItem as ToolsPanelItem,
7
+ ToggleControl,
8
+ } from '@wordpress/components';
9
+
10
+ export default function HierarchyControl( { attributes, setQuery } ) {
11
+ const { termQuery } = attributes;
12
+
13
+ return (
14
+ <ToolsPanelItem
15
+ hasValue={ () => termQuery.hierarchical !== false }
16
+ label={ __( 'Show hierarchy' ) }
17
+ onDeselect={ () => setQuery( { hierarchical: false } ) }
18
+ isShownByDefault
19
+ >
20
+ <ToggleControl
21
+ __nextHasNoMarginBottom
22
+ label={ __( 'Show hierarchy' ) }
23
+ checked={ termQuery.hierarchical }
24
+ onChange={ ( hierarchical ) => {
25
+ setQuery( { hierarchical } );
26
+ } }
27
+ />
28
+ </ToolsPanelItem>
29
+ );
30
+ }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+ import { __experimentalToolsPanel as ToolsPanel } from '@wordpress/components';
6
+ import { InspectorControls } from '@wordpress/block-editor';
7
+ import { store as coreStore } from '@wordpress/core-data';
8
+ import { useSelect } from '@wordpress/data';
9
+ import { useMemo } from '@wordpress/element';
10
+
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import { useToolsPanelDropdownMenuProps } from '../../utils/hooks';
15
+ import TaxonomyControl from './taxonomy-control';
16
+ import OrderingControls from './ordering-controls';
17
+ import DisplayOptions from './display-options';
18
+ import HierarchyControl from './hierarchy-control';
19
+ import EmptyTermsControl from './empty-terms-control';
20
+ import MaxTermsControl from './max-terms-control';
21
+ import AdvancedControls from './advanced-controls';
22
+
23
+ const usePublicTaxonomies = () => {
24
+ const taxonomies = useSelect(
25
+ ( select ) => select( coreStore ).getTaxonomies( { per_page: -1 } ),
26
+ []
27
+ );
28
+ return useMemo( () => {
29
+ return (
30
+ taxonomies?.filter(
31
+ ( { visibility } ) => visibility?.publicly_queryable
32
+ ) || []
33
+ );
34
+ }, [ taxonomies ] );
35
+ };
36
+
37
+ export default function TermsQueryInspectorControls( {
38
+ attributes,
39
+ setQuery,
40
+ setAttributes,
41
+ TagName,
42
+ clientId,
43
+ } ) {
44
+ const { termQuery, termsToShow } = attributes;
45
+ const dropdownMenuProps = useToolsPanelDropdownMenuProps();
46
+ const taxonomies = usePublicTaxonomies();
47
+
48
+ const { templateSlug } = useSelect( ( select ) => {
49
+ // @wordpress/block-library should not depend on @wordpress/editor.
50
+ // Blocks can be loaded into a *non-post* block editor, so to avoid
51
+ // declaring @wordpress/editor as a dependency, we must access its
52
+ // store by string.
53
+ // The solution here is to split WP specific blocks from generic blocks.
54
+ // eslint-disable-next-line @wordpress/data-no-store-string-literals
55
+ const { getEditedPostSlug } = select( 'core/editor' );
56
+ return {
57
+ templateSlug: getEditedPostSlug(),
58
+ };
59
+ }, [] );
60
+
61
+ const taxonomyOptions = taxonomies.map( ( taxonomy ) => ( {
62
+ label: taxonomy.name,
63
+ value: taxonomy.slug,
64
+ } ) );
65
+
66
+ const isTaxonomyHierarchical = taxonomies.find(
67
+ ( taxonomy ) => taxonomy.slug === termQuery.taxonomy
68
+ )?.hierarchical;
69
+
70
+ const isTaxonomyMatchingTemplate =
71
+ typeof templateSlug === 'string' &&
72
+ templateSlug.includes( termQuery.taxonomy );
73
+
74
+ const displaySubtermsControl =
75
+ isTaxonomyHierarchical && isTaxonomyMatchingTemplate;
76
+
77
+ return (
78
+ <>
79
+ <InspectorControls>
80
+ <ToolsPanel
81
+ label={ __( 'Terms Query Settings' ) }
82
+ resetAll={ () => {
83
+ setAttributes( {
84
+ termQuery: {
85
+ taxonomy: 'category',
86
+ order: 'asc',
87
+ orderBy: 'name',
88
+ hideEmpty: true,
89
+ hierarchical: false,
90
+ parent: false,
91
+ perPage: 10,
92
+ },
93
+ termsToShow: 'all',
94
+ } );
95
+ } }
96
+ dropdownMenuProps={ dropdownMenuProps }
97
+ >
98
+ <TaxonomyControl
99
+ attributes={ attributes }
100
+ setQuery={ setQuery }
101
+ setAttributes={ setAttributes }
102
+ taxonomyOptions={ taxonomyOptions }
103
+ />
104
+ <OrderingControls
105
+ attributes={ attributes }
106
+ setQuery={ setQuery }
107
+ />
108
+ <EmptyTermsControl
109
+ attributes={ attributes }
110
+ setQuery={ setQuery }
111
+ />
112
+ <DisplayOptions
113
+ attributes={ attributes }
114
+ setAttributes={ setAttributes }
115
+ displayTopLevelControl={ isTaxonomyHierarchical }
116
+ displaySubtermsControl={ displaySubtermsControl }
117
+ />
118
+ <MaxTermsControl
119
+ attributes={ attributes }
120
+ setQuery={ setQuery }
121
+ />
122
+ { isTaxonomyHierarchical && termsToShow === 'all' && (
123
+ <HierarchyControl
124
+ attributes={ attributes }
125
+ setQuery={ setQuery }
126
+ />
127
+ ) }
128
+ </ToolsPanel>
129
+ </InspectorControls>
130
+ <AdvancedControls
131
+ TagName={ TagName }
132
+ setAttributes={ setAttributes }
133
+ clientId={ clientId }
134
+ />
135
+ </>
136
+ );
137
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+ import {
6
+ __experimentalToolsPanelItem as ToolsPanelItem,
7
+ RangeControl,
8
+ } from '@wordpress/components';
9
+
10
+ export default function MaxTermsControl( { attributes, setQuery } ) {
11
+ const { termQuery } = attributes;
12
+
13
+ // Only show pagination control when not hierarchical.
14
+ if ( termQuery.hierarchical ) {
15
+ return null;
16
+ }
17
+
18
+ return (
19
+ <ToolsPanelItem
20
+ hasValue={ () => termQuery.perPage !== 10 }
21
+ label={ __( 'Max terms' ) }
22
+ onDeselect={ () => setQuery( { perPage: 10 } ) }
23
+ isShownByDefault
24
+ >
25
+ <RangeControl
26
+ __nextHasNoMarginBottom
27
+ __next40pxDefaultSize
28
+ label={ __( 'Max terms' ) }
29
+ value={ termQuery.perPage }
30
+ min={ 0 }
31
+ max={ 100 }
32
+ onChange={ ( perPage ) => {
33
+ // Show all terms (-1) when 0 is selected.
34
+ setQuery( {
35
+ perPage: perPage === 0 ? -1 : perPage,
36
+ } );
37
+ } }
38
+ help={ __(
39
+ 'Limit the number of terms you want to show. To show all terms, use 0 (zero).'
40
+ ) }
41
+ />
42
+ </ToolsPanelItem>
43
+ );
44
+ }