import { useState, useEffect } from '@wordpress/element'; import { Button, CheckboxControl, Spinner, TextControl, } from '@wordpress/components'; import apiFetch from '@wordpress/api-fetch'; export default function TaxonomySelector( { blockConfig, objectType, endpoint, onChange } ) { const [ availableTaxonomies, setAvailableTaxonomies ] = useState( [] ); const [ termsCache, setTermsCache ] = useState( {} ); const [ loadingTax, setLoadingTax ] = useState( false ); const [ loadingTerms, setLoadingTerms ] = useState( {} ); const [ search, setSearch ] = useState( '' ); const taxonomies = blockConfig.taxonomies || {}; const taxObjectType = objectType || blockConfig.post_type || 'post'; useEffect( () => { setLoadingTax( true ); const path = endpoint ? `wlconduit/v1/ext/${ endpoint }` : `wlconduit/v1/taxonomies?object_type=${ taxObjectType }`; apiFetch( { path } ) .then( ( data ) => setAvailableTaxonomies( data || [] ) ) .catch( () => setAvailableTaxonomies( [] ) ) .finally( () => setLoadingTax( false ) ); }, [ endpoint, taxObjectType ] ); function loadTerms( taxonomy, refresh = false ) { if ( termsCache[ taxonomy ] && ! refresh ) { return; } setLoadingTerms( ( prev ) => ( { ...prev, [ taxonomy ]: true } ) ); const refreshParam = refresh ? '&refresh=1' : ''; apiFetch( { path: `wlconduit/v1/terms?taxonomy=${ taxonomy }${ refreshParam }` } ) .then( ( data ) => { setTermsCache( ( prev ) => ( { ...prev, [ taxonomy ]: data || [] } ) ); } ) .catch( () => {} ) .finally( () => { setLoadingTerms( ( prev ) => ( { ...prev, [ taxonomy ]: false } ) ); } ); } function toggleTaxonomy( taxSlug ) { const updated = { ...taxonomies }; if ( updated[ taxSlug ] ) { delete updated[ taxSlug ]; } else { updated[ taxSlug ] = { as_field: true, as_filter: false, terms: [], }; loadTerms( taxSlug ); } onChange( updated ); } function updateTaxConfig( taxSlug, partial ) { const updated = { ...taxonomies, [ taxSlug ]: { ...taxonomies[ taxSlug ], ...partial }, }; // Load terms when enabling as filter. if ( partial.as_filter && ! termsCache[ taxSlug ] ) { loadTerms( taxSlug ); } onChange( updated ); } function toggleTerm( taxSlug, termSlug ) { const currentTerms = taxonomies[ taxSlug ]?.terms || []; const updatedTerms = currentTerms.includes( termSlug ) ? currentTerms.filter( ( t ) => t !== termSlug ) : [ ...currentTerms, termSlug ]; updateTaxConfig( taxSlug, { terms: updatedTerms } ); } if ( loadingTax ) { return ; } return (

Select taxonomies to include as data or expose as filters. When used as a filter, pick which terms the AI can filter by.

{ availableTaxonomies.length > 0 && ( ) } { availableTaxonomies.length === 0 ? (

No taxonomies found for this post type.

) : ( availableTaxonomies.filter( ( tax ) => { if ( ! search ) { return true; } const term = search.toLowerCase(); return ( tax.name || '' ).toLowerCase().includes( term ) || ( tax.label || '' ).toLowerCase().includes( term ); } ).map( ( tax ) => { const isSelected = !! taxonomies[ tax.name ]; const isInternal = tax.internal || false; const config = taxonomies[ tax.name ] || {}; const terms = termsCache[ tax.name ] || []; const isLoadingTerms = loadingTerms[ tax.name ]; return (
toggleTaxonomy( tax.name ) } /> { isSelected && (
updateTaxConfig( tax.name, { as_field: val } ) } /> updateTaxConfig( tax.name, { as_filter: val } ) } /> { config.as_filter && (
{ isLoadingTerms ? ( ) : terms.length === 0 ? (

No terms found.

) : ( terms.map( ( term ) => ( toggleTerm( tax.name, term.slug ) } /> ) ) ) }
) }
) }
); } ) ) }
); }