diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index aaa0a9e56eff3e..d14c1d4cca9e92 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -1010,7 +1010,7 @@ An advanced block that allows displaying taxonomy terms based on different query - **Category:** theme - **Allowed Blocks:** core/term-template - **Supports:** align (full, wide), interactivity, ~~html~~ -- **Attributes:** tagName, termQuery, termsToShow +- **Attributes:** tagName, termQuery ## Text Columns (deprecated) diff --git a/packages/block-library/src/term-template/block.json b/packages/block-library/src/term-template/block.json index 80f64e5e4fe357..dcec56e316e885 100644 --- a/packages/block-library/src/term-template/block.json +++ b/packages/block-library/src/term-template/block.json @@ -8,7 +8,7 @@ "ancestor": [ "core/terms-query" ], "description": "Contains the block elements used to render a taxonomy term, like the name, description, and more.", "textdomain": "default", - "usesContext": [ "termQuery", "termsToShow" ], + "usesContext": [ "termQuery" ], "supports": { "reusable": false, "html": false, diff --git a/packages/block-library/src/term-template/edit.js b/packages/block-library/src/term-template/edit.js index 70332605923998..071f39b9b59d59 100644 --- a/packages/block-library/src/term-template/edit.js +++ b/packages/block-library/src/term-template/edit.js @@ -125,79 +125,17 @@ function TermTemplateBlockPreview( { // Prevent re-rendering of the block preview when the terms data changes. const MemoizedTermTemplateBlockPreview = memo( TermTemplateBlockPreview ); -/** - * Builds a hierarchical tree structure from flat terms array. - * - * @param {Array} terms Array of term objects. - * @return {Array} Tree structure with parent/child relationships. - */ -function buildTermsTree( terms ) { - const termsById = {}; - const rootTerms = []; - - terms.forEach( ( term ) => { - termsById[ term.id ] = { - term, - children: [], - }; - } ); - - terms.forEach( ( term ) => { - if ( term.parent && termsById[ term.parent ] ) { - termsById[ term.parent ].children.push( termsById[ term.id ] ); - } else { - rootTerms.push( termsById[ term.id ] ); - } - } ); - - return rootTerms; -} - -/** - * Renders a single term node and its children recursively. - * - * @param {Object} termNode Term node with term object and children. - * @param {Function} renderTerm Function to render individual terms. - * @return {JSX.Element} Rendered term node with children. - */ -function renderTermNode( termNode, renderTerm ) { - return ( -
  • - { renderTerm( termNode.term ) } - { termNode.children.length > 0 && ( - - ) } -
  • - ); -} - -/** - * Checks if a term is the currently active term. - * - * @param {number} termId The term ID to check. - * @param {number} activeBlockContextId The currently active block context ID. - * @param {Array} blockContexts Array of block contexts. - * @return {boolean} True if the term is active, false otherwise. - */ -function isActiveTerm( termId, activeBlockContextId, blockContexts ) { - return termId === ( activeBlockContextId || blockContexts[ 0 ]?.termId ); -} - export default function TermTemplateEdit( { clientId, setAttributes, context: { - termsToShow, termQuery: { taxonomy, order, orderBy, hideEmpty, - hierarchical, + hierarchical = false, + parent = 0, perPage = 10, } = {}, }, @@ -207,15 +145,21 @@ export default function TermTemplateEdit( { const { replaceInnerBlocks } = useDispatch( blockEditorStore ); const queryArgs = { + hide_empty: hideEmpty, order, orderby: orderBy, - hide_empty: hideEmpty, // To preview the data the closest to the frontend, we fetch the largest number of terms // and limit them during rendering. This is because WP_Term_Query fetches data in hierarchical manner, // while in editor we build the hierarchy manually. It also allows us to avoid re-fetching data when max terms changes. per_page: 100, }; + // Nested terms are returned by default from REST API as long as parent is not set. + // If we want to show nested terms, we must not set parent at all. + if ( parent || ! hierarchical ) { + queryArgs.parent = parent || 0; + } + const { records: terms, isResolving } = useEntityRecords( 'taxonomy', taxonomy, @@ -226,14 +170,9 @@ export default function TermTemplateEdit( { if ( ! terms ) { return []; } - if ( termsToShow === 'top-level' ) { - return terms.filter( ( term ) => ! term.parent ); - } - if ( termsToShow === 'subterms' ) { - return terms.filter( ( term ) => term.parent ); - } - return terms; - }, [ terms, termsToShow ] ); + // Limit to the number of terms defined by perPage. + return perPage === 0 ? terms : terms.slice( 0, perPage ); + }, [ terms, perPage ] ); const { blocks, variations, defaultVariation } = useSelect( ( select ) => { @@ -319,77 +258,37 @@ export default function TermTemplateEdit( { return

    { __( 'No terms found.' ) }

    ; } - const renderTerm = ( term ) => { - const blockContext = { - taxonomy, - termId: term.id, - classList: `term-${ term.id }`, - termData: term, - }; - - return ( - - { isActiveTerm( - term.id, - activeBlockContextId, - blockContexts - ) ? ( - - ) : null } - - - ); - }; - return ( <> ); diff --git a/packages/block-library/src/term-template/index.php b/packages/block-library/src/term-template/index.php index 86d21e54defc19..8e9db6f972ff55 100644 --- a/packages/block-library/src/term-template/index.php +++ b/packages/block-library/src/term-template/index.php @@ -27,8 +27,7 @@ function render_block_core_term_template( $attributes, $content, $block ) { return ''; } - $query = $query_block_context['termQuery']; - $terms_to_show = $query_block_context['termsToShow'] ?? 'all'; + $query = $query_block_context['termQuery']; $query_args = array( 'taxonomy' => $query['taxonomy'] ?? 'category', @@ -38,18 +37,23 @@ function render_block_core_term_template( $attributes, $content, $block ) { 'hide_empty' => $query['hideEmpty'] ?? true, ); - // We set parent to 0 only if we show all terms as hierarchical or we show top-level terms. - if ( ( 'all' === $terms_to_show && ! empty( $query['hierarchical'] ) ) || 'top-level' === $terms_to_show ) { + // We set parent only when inheriting from the taxonomy archive context or not + // showing nested terms, otherwise nested terms are not displayed. + if ( + isset( $query['inherit'] ) + && $query['inherit'] + && ( + is_tax( $query_args['taxonomy'] ) + // is_tax() does not detect built-in category or tag archives, only custom taxonomies. + || ( 'category' === $query_args['taxonomy'] && is_category() ) + || ( 'post_tag' === $query_args['taxonomy'] && is_tag() ) + ) + ) { + // Get the current term ID from the queried object. + $current_term_id = get_queried_object_id(); + $query_args['parent'] = $current_term_id; + } elseif ( empty( $query['hierarchical'] ) ) { $query_args['parent'] = 0; - } elseif ( 'subterms' === $terms_to_show ) { - // Check if we're in a taxonomy archive context. - if ( is_tax( $query_args['taxonomy'] ) ) { - // Get the current term ID from the queried object. - $current_term_id = get_queried_object_id(); - if ( $current_term_id && $current_term_id > 0 ) { - $query_args['parent'] = $current_term_id; - } - } } $terms_query = new WP_Term_Query( $query_args ); @@ -59,130 +63,15 @@ function render_block_core_term_template( $attributes, $content, $block ) { return ''; } - // Handle hierarchical list. - $is_hierarchical = ! empty( $query['hierarchical'] ); - - if ( $is_hierarchical ) { - $content = render_block_core_term_template_hierarchical( $terms, $block, $query_args ); - } else { - $content = render_block_core_term_template_flat( $terms, $block ); - } - - $classnames = 'wp-block-term-template'; - - if ( isset( $attributes['style']['elements']['link']['color']['text'] ) ) { - $classnames .= ' has-link-color'; - } - - $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => trim( $classnames ) ) ); - - // Default list layout. - return sprintf( - '', - $wrapper_attributes, - $content - ); -} - -/** - * Renders terms in a flat list structure. - * - * @since 6.9.0 - * - * @param array $terms Array of WP_Term objects. - * @param WP_Block $block Block instance. - * - * @return string HTML content for flat terms list. - */ -function render_block_core_term_template_flat( $terms, $block ) { - $content = ''; - foreach ( $terms as $term ) { - $content .= render_block_core_term_template_single( $term, $block ); - } - return $content; -} - -/** - * Renders terms in a hierarchical structure. - * - * @since 6.9.0 - * - * @param array $terms Array of WP_Term objects. - * @param WP_Block $block Block instance. - * @param array $base_query_args Base query arguments. - * - * @return string HTML content for hierarchical terms list. - */ -function render_block_core_term_template_hierarchical( $terms, $block, $base_query_args ) { $content = ''; - foreach ( $terms as $term ) { - $term_content = render_block_core_term_template_single( $term, $block ); - $children_content = render_block_core_term_template_get_children( $term->term_id, $block, $base_query_args ); + // Get an instance of the current Term Template block. + $block_instance = $block->parsed_block; - if ( ! empty( $children_content ) ) { - $term_content = str_replace( '', '', $term_content ); - } + // Set the block name to one that does not correspond to an existing registered block. + // This ensures that for the inner instances of the Term Template block, we do not render any block supports. + $block_instance['blockName'] = 'core/null'; - $content .= $term_content; - } - - return $content; -} - -/** - * Gets and renders children of a specific term. - * - * @since 6.9.0 - * - * @param int $parent_term_id Parent term ID. - * @param WP_Block $block Block instance. - * @param array $base_query_args Base query arguments. - * - * @return string HTML content for children terms. - */ -function render_block_core_term_template_get_children( $parent_term_id, $block, $base_query_args ) { - $child_query_args = $base_query_args; - $child_query_args['parent'] = $parent_term_id; - - $child_terms_query = new WP_Term_Query( $child_query_args ); - $child_terms = $child_terms_query->get_terms(); - - if ( ! $child_terms || is_wp_error( $child_terms ) ) { - return ''; - } - - $content = ''; - - foreach ( $child_terms as $child_term ) { - $term_content = render_block_core_term_template_single( $child_term, $block ); - $children_content = render_block_core_term_template_get_children( $child_term->term_id, $block, $base_query_args ); - - if ( ! empty( $children_content ) ) { - $term_content = str_replace( '', '', $term_content ); - } - - $content .= $term_content; - } - - return $content; -} - -/** - * Renders a single term with its inner blocks. - * - * @since 6.9.0 - * - * @param WP_Term $term Term object. - * @param WP_Block $block Block instance. - * - * @return string HTML content for a single term. - */ -function render_block_core_term_template_single( $term, $block ) { - $inner_blocks = $block->inner_blocks; - $block_content = ''; - - if ( ! empty( $inner_blocks ) ) { $term_id = $term->term_id; $taxonomy = $term->taxonomy; @@ -192,24 +81,36 @@ function render_block_core_term_template_single( $term, $block ) { return $context; }; + $block_content = ''; + + // Use an early priority to so that other 'render_block_context' filters have access to the values. add_filter( 'render_block_context', $filter_block_context, 1 ); - foreach ( $inner_blocks as $inner_block ) { - if ( method_exists( $inner_block, 'refresh_context_dependents' ) ) { - // WP_Block::refresh_context_dependents() was introduced in WordPress 6.8. - $inner_block->refresh_context_dependents(); - $block_content .= $inner_block->render( array( 'dynamic' => true ) ); - } else { - $block_content = ( new WP_Block( $inner_block->parsed_block ) )->render( array( 'dynamic' => false ) ); - } - } + // Render the inner blocks of the Term Template block with `dynamic` set to `false` to prevent calling + // `render_callback` and ensure that no wrapper markup is included. + $block_content .= ( new WP_Block( $block_instance ) )->render( array( 'dynamic' => false ) ); + remove_filter( 'render_block_context', $filter_block_context, 1 ); + + // Wrap the render inner blocks in a `li` element with the appropriate term classes. + $term_classes = implode( ' ', array( 'wp-block-term', "term-{$term->term_id}", $term->taxonomy, "taxonomy-{$term->taxonomy}" ) ); + + $content .= '
  • ' . $block_content . '
  • '; + } + + $classnames = 'wp-block-term-template'; + + if ( isset( $attributes['style']['elements']['link']['color']['text'] ) ) { + $classnames .= ' has-link-color'; } - $term_classes = implode( ' ', array( 'wp-block-term', 'term-' . $term->term_id ) ); + $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => trim( $classnames ) ) ); - // Default list layout - return '
  • ' . $block_content . '
  • '; + return sprintf( + '', + $wrapper_attributes, + $content + ); } /** diff --git a/packages/block-library/src/terms-query/block.json b/packages/block-library/src/terms-query/block.json index 8061475e661dae..85b06d0a115792 100644 --- a/packages/block-library/src/terms-query/block.json +++ b/packages/block-library/src/terms-query/block.json @@ -18,22 +18,17 @@ "orderBy": "name", "hideEmpty": true, "parent": false, - "hierarchical": false + "hierarchical": false, + "inherit": false } }, - "termsToShow": { - "type": "string", - "default": "all", - "enum": [ "all", "top-level", "subterms" ] - }, "tagName": { "type": "string", "default": "div" } }, "providesContext": { - "termQuery": "termQuery", - "termsToShow": "termsToShow" + "termQuery": "termQuery" }, "supports": { "align": [ "wide", "full" ], diff --git a/packages/block-library/src/terms-query/edit.js b/packages/block-library/src/terms-query/edit/index.js similarity index 100% rename from packages/block-library/src/terms-query/edit.js rename to packages/block-library/src/terms-query/edit/index.js diff --git a/packages/block-library/src/terms-query/inspector-controls/advanced-controls.js b/packages/block-library/src/terms-query/edit/inspector-controls/advanced-controls.js similarity index 94% rename from packages/block-library/src/terms-query/inspector-controls/advanced-controls.js rename to packages/block-library/src/terms-query/edit/inspector-controls/advanced-controls.js index 0e0e5c48a6b43e..4c8e0c40a0b515 100644 --- a/packages/block-library/src/terms-query/inspector-controls/advanced-controls.js +++ b/packages/block-library/src/terms-query/edit/inspector-controls/advanced-controls.js @@ -10,7 +10,7 @@ import { /** * Internal dependencies */ -import { unlock } from '../../lock-unlock'; +import { unlock } from '../../../lock-unlock'; const { HTMLElementControl } = unlock( blockEditorPrivateApis ); diff --git a/packages/block-library/src/terms-query/edit/inspector-controls/empty-terms-control.js b/packages/block-library/src/terms-query/edit/inspector-controls/empty-terms-control.js new file mode 100644 index 00000000000000..2a499674ccb870 --- /dev/null +++ b/packages/block-library/src/terms-query/edit/inspector-controls/empty-terms-control.js @@ -0,0 +1,15 @@ +/** + * WordPress dependencies + */ +import { ToggleControl } from '@wordpress/components'; + +export default function EmptyTermsControl( { value, onChange, ...props } ) { + return ( + onChange( ! showEmpty ) } + { ...props } + /> + ); +} diff --git a/packages/block-library/src/terms-query/edit/inspector-controls/index.js b/packages/block-library/src/terms-query/edit/inspector-controls/index.js new file mode 100644 index 00000000000000..c3d44dc54ba548 --- /dev/null +++ b/packages/block-library/src/terms-query/edit/inspector-controls/index.js @@ -0,0 +1,206 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { + __experimentalToolsPanel as ToolsPanel, + __experimentalToolsPanelItem as ToolsPanelItem, +} from '@wordpress/components'; +import { InspectorControls } from '@wordpress/block-editor'; +import { useSelect } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { useToolsPanelDropdownMenuProps } from '../../../utils/hooks'; +import { usePublicTaxonomies } from '../../utils'; +import TaxonomyControl from './taxonomy-control'; +import OrderControl from './order-control'; +import EmptyTermsControl from './empty-terms-control'; +import NestedTermsControl from './nested-terms-control'; +import InheritControl from './inherit-control'; +import MaxTermsControl from './max-terms-control'; +import AdvancedControls from './advanced-controls'; + +export default function TermsQueryInspectorControls( { + attributes, + setQuery, + setAttributes, + TagName, + clientId, +} ) { + const { termQuery } = attributes; + const { + taxonomy, + orderBy, + order, + hideEmpty, + inherit, + hierarchical, + perPage, + } = termQuery; + const dropdownMenuProps = useToolsPanelDropdownMenuProps(); + + const { templateSlug } = useSelect( ( select ) => { + // @wordpress/block-library should not depend on @wordpress/editor. + // Blocks can be loaded into a *non-post* block editor, so to avoid + // declaring @wordpress/editor as a dependency, we must access its + // store by string. + // The solution here is to split WP specific blocks from generic blocks. + // eslint-disable-next-line @wordpress/data-no-store-string-literals + const { getEditedPostSlug } = select( 'core/editor' ); + return { + templateSlug: getEditedPostSlug(), + }; + }, [] ); + + const taxonomies = usePublicTaxonomies(); + + const isTaxonomyHierarchical = taxonomies.find( + ( _taxonomy ) => _taxonomy.slug === taxonomy + )?.hierarchical; + + const isTaxonomyMatchingTemplate = + typeof templateSlug === 'string' && templateSlug.includes( taxonomy ); + + // Only display the inherit control if the taxonomy is hierarchical and matches the current template. + const displayInheritControl = + isTaxonomyHierarchical && isTaxonomyMatchingTemplate; + + // Only display the hierarchical control if the taxonomy is hierarchical and not inheriting. + const displayHierarchicalControl = + isTaxonomyHierarchical && ! termQuery.inherit; + + // Labels shared between ToolsPanelItem and its child control. + const taxonomyControlLabel = __( 'Taxonomy' ); + const orderByControlLabel = __( 'Order by' ); + const emptyTermsControlLabel = __( 'Show empty terms' ); + const inheritControlLabel = __( 'Inherit parent term from archive' ); + const nestedTermsControlLabel = __( 'Show nested terms' ); + const maxTermsControlLabel = __( 'Max terms' ); + + return ( + <> + + { + setAttributes( { + termQuery: { + taxonomy: 'category', + order: 'asc', + orderBy: 'name', + hideEmpty: true, + hierarchical: false, + parent: false, + perPage: 10, + }, + } ); + } } + dropdownMenuProps={ dropdownMenuProps } + > + taxonomy !== 'category' } + label={ taxonomyControlLabel } + onDeselect={ () => { + setQuery( { taxonomy: 'category' } ); + } } + isShownByDefault + > + + setQuery( { taxonomy: value } ) + } + /> + + orderBy !== 'name' || order !== 'asc' } + label={ orderByControlLabel } + onDeselect={ () => + setQuery( { orderBy: 'name', order: 'asc' } ) + } + isShownByDefault + > + { + setQuery( { + orderBy: newOrderBy, + order: newOrder, + } ); + } } + /> + + hideEmpty !== true } + label={ emptyTermsControlLabel } + onDeselect={ () => setQuery( { hideEmpty: true } ) } + isShownByDefault + > + + setQuery( { hideEmpty: value } ) + } + /> + + { displayInheritControl && ( + inherit !== false } + label={ inheritControlLabel } + onDeselect={ () => setQuery( { inherit: false } ) } + isShownByDefault + > + + + ) } + { displayHierarchicalControl && ( + hierarchical !== false } + label={ nestedTermsControlLabel } + onDeselect={ () => + setQuery( { hierarchical: false } ) + } + isShownByDefault + > + + setQuery( { hierarchical: value } ) + } + /> + + ) } + perPage !== 10 } + label={ maxTermsControlLabel } + onDeselect={ () => setQuery( { perPage: 10 } ) } + isShownByDefault + > + + setQuery( { perPage: value } ) + } + /> + + + + + + ); +} diff --git a/packages/block-library/src/terms-query/edit/inspector-controls/inherit-control.js b/packages/block-library/src/terms-query/edit/inspector-controls/inherit-control.js new file mode 100644 index 00000000000000..4cc8a7a51576c5 --- /dev/null +++ b/packages/block-library/src/terms-query/edit/inspector-controls/inherit-control.js @@ -0,0 +1,21 @@ +/** + * WordPress dependencies + */ +import { ToggleControl } from '@wordpress/components'; + +export default function InheritControl( { value, onChange, ...props } ) { + return ( + + onChange( { + inherit, + // When enabling inherit, hierarchical is not supported. + ...( inherit ? { hierarchical: false } : {} ), + } ) + } + { ...props } + /> + ); +} diff --git a/packages/block-library/src/terms-query/edit/inspector-controls/max-terms-control.js b/packages/block-library/src/terms-query/edit/inspector-controls/max-terms-control.js new file mode 100644 index 00000000000000..81f9246d2d25bf --- /dev/null +++ b/packages/block-library/src/terms-query/edit/inspector-controls/max-terms-control.js @@ -0,0 +1,22 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { RangeControl } from '@wordpress/components'; + +export default function MaxTermsControl( { value, onChange, ...props } ) { + return ( + + ); +} diff --git a/packages/block-library/src/terms-query/edit/inspector-controls/nested-terms-control.js b/packages/block-library/src/terms-query/edit/inspector-controls/nested-terms-control.js new file mode 100644 index 00000000000000..f8778cdbcdb1f4 --- /dev/null +++ b/packages/block-library/src/terms-query/edit/inspector-controls/nested-terms-control.js @@ -0,0 +1,15 @@ +/** + * WordPress dependencies + */ +import { ToggleControl } from '@wordpress/components'; + +export default function NestedTermsControl( { value, onChange, ...props } ) { + return ( + + ); +} diff --git a/packages/block-library/src/terms-query/edit/inspector-controls/order-control.js b/packages/block-library/src/terms-query/edit/inspector-controls/order-control.js new file mode 100644 index 00000000000000..b429422bcdaf6a --- /dev/null +++ b/packages/block-library/src/terms-query/edit/inspector-controls/order-control.js @@ -0,0 +1,38 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { SelectControl } from '@wordpress/components'; + +export default function OrderControl( { orderBy, order, onChange, ...props } ) { + return ( + { + const [ newOrderBy, newOrder ] = value.split( '/' ); + onChange( newOrderBy, newOrder ); + } } + { ...props } + /> + ); +} diff --git a/packages/block-library/src/terms-query/edit/inspector-controls/taxonomy-control.js b/packages/block-library/src/terms-query/edit/inspector-controls/taxonomy-control.js new file mode 100644 index 00000000000000..cfdc61a7c884a5 --- /dev/null +++ b/packages/block-library/src/terms-query/edit/inspector-controls/taxonomy-control.js @@ -0,0 +1,28 @@ +/** + * WordPress dependencies + */ +import { SelectControl } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import { usePublicTaxonomies } from '../../utils'; + +export default function TaxonomyControl( { value, onChange, ...props } ) { + const taxonomies = usePublicTaxonomies(); + const taxonomyOptions = taxonomies.map( ( taxonomy ) => ( { + label: taxonomy.name, + value: taxonomy.slug, + } ) ); + + return ( + + ); +} diff --git a/packages/block-library/src/terms-query/inspector-controls/display-options.js b/packages/block-library/src/terms-query/inspector-controls/display-options.js deleted file mode 100644 index 031cd6c50fe951..00000000000000 --- a/packages/block-library/src/terms-query/inspector-controls/display-options.js +++ /dev/null @@ -1,79 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { - __experimentalToolsPanelItem as ToolsPanelItem, - RadioControl, -} from '@wordpress/components'; - -const getOptions = ( displayTopLevelControl, displaySubtermsControl ) => { - const options = [ { label: __( 'Show all' ), value: 'all' } ]; - - if ( displayTopLevelControl ) { - options.push( { - label: __( 'Show only top level terms' ), - value: 'top-level', - } ); - } - - if ( displaySubtermsControl ) { - options.push( { - label: __( 'Show subterms only' ), - value: 'subterms', - description: __( - 'Display subterms of the current term. E.g. subcategories of current category.' - ), - } ); - } - - return options; -}; - -const getQueryAttributes = ( value ) => { - if ( value === 'top-level' ) { - return { - parent: 0, - hierarchical: false, - }; - } - - // For 'all' and 'subterms', we fetch all terms and then filter them as the tree is built in Term Template. - return { - parent: false, - }; -}; - -export default function DisplayOptions( { - attributes, - displayTopLevelControl, - displaySubtermsControl, - setAttributes, -} ) { - const { termQuery, termsToShow } = attributes; - - return ( - termsToShow !== 'all' } - label={ __( 'Terms to show' ) } - onDeselect={ () => setAttributes( { termsToShow: 'all' } ) } - isShownByDefault - > - { - const queryAttributes = getQueryAttributes( value ); - setAttributes( { - termsToShow: value, - termQuery: { ...termQuery, ...queryAttributes }, - } ); - } } - /> - - ); -} diff --git a/packages/block-library/src/terms-query/inspector-controls/empty-terms-control.js b/packages/block-library/src/terms-query/inspector-controls/empty-terms-control.js deleted file mode 100644 index d5589d73bab936..00000000000000 --- a/packages/block-library/src/terms-query/inspector-controls/empty-terms-control.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { - __experimentalToolsPanelItem as ToolsPanelItem, - ToggleControl, -} from '@wordpress/components'; - -export default function EmptyTermsControl( { attributes, setQuery } ) { - const { termQuery } = attributes; - - return ( - termQuery.hideEmpty !== true } - label={ __( 'Show empty terms' ) } - onDeselect={ () => setQuery( { hideEmpty: true } ) } - isShownByDefault - > - - setQuery( { hideEmpty: ! showEmpty } ) - } - /> - - ); -} diff --git a/packages/block-library/src/terms-query/inspector-controls/hierarchy-control.js b/packages/block-library/src/terms-query/inspector-controls/hierarchy-control.js deleted file mode 100644 index a81114c534b307..00000000000000 --- a/packages/block-library/src/terms-query/inspector-controls/hierarchy-control.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { - __experimentalToolsPanelItem as ToolsPanelItem, - ToggleControl, -} from '@wordpress/components'; - -export default function HierarchyControl( { attributes, setQuery } ) { - const { termQuery } = attributes; - - return ( - termQuery.hierarchical !== false } - label={ __( 'Show hierarchy' ) } - onDeselect={ () => setQuery( { hierarchical: false } ) } - isShownByDefault - > - { - setQuery( { hierarchical } ); - } } - /> - - ); -} diff --git a/packages/block-library/src/terms-query/inspector-controls/index.js b/packages/block-library/src/terms-query/inspector-controls/index.js deleted file mode 100644 index 4c8e6b43c75f30..00000000000000 --- a/packages/block-library/src/terms-query/inspector-controls/index.js +++ /dev/null @@ -1,137 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { __experimentalToolsPanel as ToolsPanel } from '@wordpress/components'; -import { InspectorControls } from '@wordpress/block-editor'; -import { store as coreStore } from '@wordpress/core-data'; -import { useSelect } from '@wordpress/data'; -import { useMemo } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import { useToolsPanelDropdownMenuProps } from '../../utils/hooks'; -import TaxonomyControl from './taxonomy-control'; -import OrderingControls from './ordering-controls'; -import DisplayOptions from './display-options'; -import HierarchyControl from './hierarchy-control'; -import EmptyTermsControl from './empty-terms-control'; -import MaxTermsControl from './max-terms-control'; -import AdvancedControls from './advanced-controls'; - -const usePublicTaxonomies = () => { - const taxonomies = useSelect( - ( select ) => select( coreStore ).getTaxonomies( { per_page: -1 } ), - [] - ); - return useMemo( () => { - return ( - taxonomies?.filter( - ( { visibility } ) => visibility?.publicly_queryable - ) || [] - ); - }, [ taxonomies ] ); -}; - -export default function TermsQueryInspectorControls( { - attributes, - setQuery, - setAttributes, - TagName, - clientId, -} ) { - const { termQuery, termsToShow } = attributes; - const dropdownMenuProps = useToolsPanelDropdownMenuProps(); - const taxonomies = usePublicTaxonomies(); - - const { templateSlug } = useSelect( ( select ) => { - // @wordpress/block-library should not depend on @wordpress/editor. - // Blocks can be loaded into a *non-post* block editor, so to avoid - // declaring @wordpress/editor as a dependency, we must access its - // store by string. - // The solution here is to split WP specific blocks from generic blocks. - // eslint-disable-next-line @wordpress/data-no-store-string-literals - const { getEditedPostSlug } = select( 'core/editor' ); - return { - templateSlug: getEditedPostSlug(), - }; - }, [] ); - - const taxonomyOptions = taxonomies.map( ( taxonomy ) => ( { - label: taxonomy.name, - value: taxonomy.slug, - } ) ); - - const isTaxonomyHierarchical = taxonomies.find( - ( taxonomy ) => taxonomy.slug === termQuery.taxonomy - )?.hierarchical; - - const isTaxonomyMatchingTemplate = - typeof templateSlug === 'string' && - templateSlug.includes( termQuery.taxonomy ); - - const displaySubtermsControl = - isTaxonomyHierarchical && isTaxonomyMatchingTemplate; - - return ( - <> - - { - setAttributes( { - termQuery: { - taxonomy: 'category', - order: 'asc', - orderBy: 'name', - hideEmpty: true, - hierarchical: false, - parent: false, - perPage: 10, - }, - termsToShow: 'all', - } ); - } } - dropdownMenuProps={ dropdownMenuProps } - > - - - - - - { isTaxonomyHierarchical && termsToShow === 'all' && ( - - ) } - - - - - ); -} diff --git a/packages/block-library/src/terms-query/inspector-controls/max-terms-control.js b/packages/block-library/src/terms-query/inspector-controls/max-terms-control.js deleted file mode 100644 index d1328870b1e22c..00000000000000 --- a/packages/block-library/src/terms-query/inspector-controls/max-terms-control.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { - __experimentalToolsPanelItem as ToolsPanelItem, - RangeControl, -} from '@wordpress/components'; - -export default function MaxTermsControl( { attributes, setQuery } ) { - const { termQuery } = attributes; - - // Only show pagination control when not hierarchical. - if ( termQuery.hierarchical ) { - return null; - } - - return ( - termQuery.perPage !== 10 } - label={ __( 'Max terms' ) } - onDeselect={ () => setQuery( { perPage: 10 } ) } - isShownByDefault - > - { - // Show all terms (-1) when 0 is selected. - setQuery( { - perPage: perPage === 0 ? -1 : perPage, - } ); - } } - help={ __( - 'Limit the number of terms you want to show. To show all terms, use 0 (zero).' - ) } - /> - - ); -} diff --git a/packages/block-library/src/terms-query/inspector-controls/ordering-controls.js b/packages/block-library/src/terms-query/inspector-controls/ordering-controls.js deleted file mode 100644 index 260c07d9d42946..00000000000000 --- a/packages/block-library/src/terms-query/inspector-controls/ordering-controls.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { - __experimentalToolsPanelItem as ToolsPanelItem, - SelectControl, -} from '@wordpress/components'; - -export default function OrderingControls( { attributes, setQuery } ) { - const { termQuery } = attributes; - - return ( - - termQuery.orderBy !== 'name' || termQuery.order !== 'asc' - } - label={ __( 'Order by' ) } - onDeselect={ () => setQuery( { orderBy: 'name', order: 'asc' } ) } - isShownByDefault - > - { - const [ newOrderBy, newOrder ] = orderBy.split( '/' ); - setQuery( { - orderBy: newOrderBy, - order: newOrder, - } ); - } } - /> - - ); -} diff --git a/packages/block-library/src/terms-query/inspector-controls/taxonomy-control.js b/packages/block-library/src/terms-query/inspector-controls/taxonomy-control.js deleted file mode 100644 index 0847b2ff7821fd..00000000000000 --- a/packages/block-library/src/terms-query/inspector-controls/taxonomy-control.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { - __experimentalToolsPanelItem as ToolsPanelItem, - SelectControl, -} from '@wordpress/components'; - -export default function TaxonomyControl( { - attributes, - setQuery, - setAttributes, - taxonomyOptions, -} ) { - const { termQuery } = attributes; - - return ( - termQuery.taxonomy !== 'category' } - label={ __( 'Taxonomy' ) } - onDeselect={ () => { - setQuery( { taxonomy: 'category' } ); - setAttributes( { termsToShow: 'all' } ); - } } - isShownByDefault - > - { - setQuery( { taxonomy: selectedTaxonomy } ); - setAttributes( { termsToShow: 'all' } ); - } } - /> - - ); -} diff --git a/packages/block-library/src/terms-query/utils.js b/packages/block-library/src/terms-query/utils.js new file mode 100644 index 00000000000000..f18c129b7b2ce7 --- /dev/null +++ b/packages/block-library/src/terms-query/utils.js @@ -0,0 +1,25 @@ +/** + * WordPress dependencies + */ +import { store as coreStore } from '@wordpress/core-data'; +import { useSelect } from '@wordpress/data'; +import { useMemo } from '@wordpress/element'; + +/** + * Retrieve publicly-queryable taxonomies. + * + * @return {Object[]} Array of public taxonomy objects. + */ +export function usePublicTaxonomies() { + const taxonomies = useSelect( + ( select ) => select( coreStore ).getTaxonomies( { per_page: -1 } ), + [] + ); + return useMemo( () => { + return ( + taxonomies?.filter( + ( { visibility } ) => visibility?.publicly_queryable + ) || [] + ); + }, [ taxonomies ] ); +}