In this blog post, we’ll dive deep into the creation of a customizable, searchable dropdown component for selecting terms from custom taxonomies in a WordPress Gutenberg block. This component is particularly useful for projects that require users to filter or select terms dynamically, enhancing the user experience and making content management more intuitive.
Overview of the TaxonomyDropDown Component
The TaxonomyDropDown component allows users to search and select terms from a specified taxonomy. It utilizes WordPress’s built-in data store, hooks, and components to create a responsive and efficient UI.
Key Features
- Searchable Dropdown: Users can type to filter terms quickly.
- Dynamic Loading: Loads terms in pages, reducing initial load time and improving performance.
- Checkbox Control: Allows for multiple selections.
- Error Handling: Displays user-friendly error messages when fetching terms fails.
Component Breakdown
Let’s break down the code and explore how each part of the component works.
Import Statements
import { useSelect } from '@wordpress/data';
import { useEffect, useState } from '@wordpress/element';
import { Button, CheckboxControl, Spinner, TextControl } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
useSelect: A hook from the@wordpress/datapackage that allows us to select data from the WordPress store.- React Hooks:
useStateanduseEffecthelp manage state and side effects. - Components:
Button,CheckboxControl,Spinner, andTextControlare prebuilt components from the WordPress UI library. - Localization: Functions
__andsprintfare used for translating text.
Component Props
The TaxonomyDropDown component receives the following props:
taxonomy: The name of the taxonomy from which to fetch terms.values: An array of currently selected terms.onChange: A callback function that updates the parent component when the selection changes.placeholder: Placeholder text for the search input.label: Label text for the dropdown.
State Management:
Here, we define several pieces of state:
termsList: An array to hold the terms fetched from the API.page: The current page of terms being displayed.searchQuery: The current input value for the search.loading: A boolean to indicate if terms are being loaded.hasMore: A flag to check if there are more terms to load.error: To capture and display any errors that occur during fetching.
Fetching Terms
The fetching of terms is handled by the useSelect hook:
const terms = useSelect((select) => {
try {
const { getEntityRecords } = select('core');
const query = {
per_page: 5,
page,
search: searchQuery,
};
const termsData = getEntityRecords('taxonomy', taxonomy, query);
if (!termsData || termsData.length === 0) {
return [];
}
return termsData;
} catch (err) {
setError(sprintf('%1$s(%2$s) : %3$s', __('Unable to fetch taxonomy', 'movie-library'), taxonomy, err?.message));
return [];
}
}, [page, taxonomy, searchQuery]);
getEntityRecords: This function fetches records for the specified taxonomy based on the current page and search query.- The
try-catchblock captures any errors during fetching and updates the error state.
Updating Terms List
The useEffect hook is used to update the terms list and manage pagination:
useEffect(() => {
if (terms) {
setTermsList((prev) => [...new Set([...prev, ...terms])]);
setHasMore(terms.length === 5); // Check if there are more terms
setLoading(false);
}
}, [terms]);
- This effect runs whenever the
termsarray changes, updating thetermsListwith newly fetched terms and checking if more terms can be loaded.
Handling Search Query Changes
Another useEffect is used to reset the state when the search query changes:
useEffect(() => {
if (searchQuery) {
setLoading(true);
setTermsList([]); // Reset terms on new search
setPage(1); // Reset to the first page
}
}, [searchQuery]);
- When the user types in the search box, it resets the terms list and pagination.
Event Handlers
We define several event handler functions to manage user interactions:
- Input Change: Updates the search query.
const handleOnInputChange = (input) => {
setSearchQuery(input);
};
Term Change: Toggles term selection and updates the parent component.
const onTermChange = (term) => {
const newValues = values.some(value => value.id === term.id)
? values.filter(value => value.id !== term.id)
: [...values, term];
const transformedValues = newValues.map(value => ({
id: value.id,
name: value.name,
slug: value.slug
}));
onChange(transformedValues);
};
Load More Terms: Increments the page number to fetch more terms.
const loadMoreTerms = () => {
if (hasMore) {
setPage((prev) => prev + 1);
}
};
Rendering the Component
Finally, we render the component, including the search input, loading spinner, checkboxes for the terms, a load more button, and error messages:
return (
<>
<TextControl
label={label}
value={searchQuery}
onChange={handleOnInputChange}
placeholder={placeholder}
/>
{loading && <Spinner />}
<div>
{termsList.map(term => (
<CheckboxControl
key={term.id}
label={term.name}
checked={values.some(value => value.id === term.id)}
onChange={() => onTermChange(term)}
/>
))}
</div>
{hasMore && (
<div className={"load-center"}>
<Button onClick={loadMoreTerms} variant={"tertiary"}>
{__('Load more', 'movie-library')}
</Button>
</div>
)}
{error && <div id="error-message" className="error">{error}</div>}
</>
);
- TextControl: For user input to search terms.
- Spinner: Displays while loading terms.
- CheckboxControl: For displaying and selecting terms.
- Button: To load more terms if available.
- Error Message: Displays if an error occurs.
Conclusion
The TaxonomyDropDown component is a powerful addition to any WordPress Gutenberg block, providing a user-friendly interface for selecting terms from custom taxonomies. By leveraging WordPress’s built-in data management tools and UI components, we create a seamless experience for content creators.
This component can be easily adapted for various taxonomies and extended with additional features such as improved error handling, loading animations, or custom styling. As you build and enhance your WordPress projects, consider how components like this can streamline user interactions and improve overall usability.
Thank you for reading through the post… More will be added.
by ~Leaveitblank (Mayank Tripathi)