If you’re building a custom dropdown menu for a hierarchical taxonomy in WordPress — for example, letting users choose a role or category — you might want to:
- Show parent terms as group labels (like
<optgroup>) - Show **child terms as selectable
<option>s - Include terms that aren’t attached to any posts
- Avoid running SQL queries inside loops
Seems simple, right? But it’s trickier than it looks.
Let me show you the cleanest way to build it — no unnecessary queries, no missing terms, and no over-complicated logic.
The Issue
If you use get_terms() and loop through the results, it’s tempting to grab each parent and then call get_terms() again to fetch its children.
$parents = get_terms([... 'parent' => 0 ...]);
foreach ($parents as $parent) {
$children = get_terms([... 'parent' => $parent->term_id ...]); // Inefficient
}
This works — but it creates a new SQL query for every parent term. That’s a classic performance problem, especially on larger sites.
The Efficient Solution
Instead, just call get_terms() once — and group the results in PHP.
Here’s the 10-line approach that avoids all the extra queries:
$grouped_terms = [];
$terms = get_terms(['taxonomy' => 'your_taxonomy', 'hide_empty' => false]);
if ($terms) {
foreach ($terms as $term) {
if ($term->parent == 0) {
$grouped_terms[$term->term_id]['name'] = $term->name;
} else {
$grouped_terms[$term->parent]['children'][] = $term;
}
}
}
Its better way
- Only one query to fetch all terms (parents + children)
- No need to pre-sort the results
- If a child term’s parent wasn’t processed yet, that’s okay — it’ll still get grouped
- Even unused terms (not attached to posts) are included thanks to
'hide_empty' => false
Rendering the Select Dropdown
Now that you’ve grouped your terms, render the dropdown with <optgroup> for parents and <option> for children:
echo '<select name="your_field_name">';
foreach ($grouped_terms as $group) {
if (empty($group['children'])) continue;
$label = $group['name'] ?? 'Other';
echo '<optgroup label="' . esc_html($label) . '">';
foreach ($group['children'] as $child) {
echo '<option value="' . esc_attr($child->term_id) . '">' . esc_html($child->name) . '</option>';
}
echo '</optgroup>';
}
echo '</select>';
This gives you a clean, user-friendly dropdown grouped by parent terms.
Use Cases
- Admin filters in meta boxes
- Frontend submission forms
- Custom post type selectors (e.g. “Job Roles”, “Product Categories”)
- Anywhere you want a taxonomy-based grouped select
When working with WordPress taxonomies, efficiency matters. Avoiding unnecessary SQL calls can make your plugins or themes faster, lighter, and more scalable.
This technique helps you build a clean, scalable dropdown for any hierarchical taxonomy — with zero extra queries, no missing terms, and just 10 lines of code.



