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/data package that allows us to select data from the WordPress store.
  • React Hooks: useState and useEffect help manage state and side effects.
  • Components: Button, CheckboxControl, Spinner, and TextControl are prebuilt components from the WordPress UI library.
  • Localization: Functions __ and sprintf are 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-catch block 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 terms array changes, updating the termsList with 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)