[wp-trac] [WordPress Trac] #64991: New param "allow_multiple_terms" in `register_taxonomy` for single term restriction

WordPress Trac noreply at wordpress.org
Fri Apr 24 18:12:04 UTC 2026


#64991: New param "allow_multiple_terms" in `register_taxonomy` for single term
restriction
-------------------------------------------------+-------------------------
 Reporter:  bastho                               |       Owner:  (none)
     Type:  feature request                      |      Status:  new
 Priority:  normal                               |   Milestone:  Awaiting
                                                 |  Review
Component:  Taxonomy                             |     Version:
 Severity:  normal                               |  Resolution:
 Keywords:  has-patch has-unit-tests needs-      |     Focuses:  ui
  testing                                        |
-------------------------------------------------+-------------------------
Changes (by abhishekfdd):

 * keywords:   => has-patch has-unit-tests needs-testing


Comment:

 Thanks for opening this, @bastho. Attaching a first patch (64991.diff)
 that covers the feature end-to-end, along with the reasoning behind a few
 decisions that came up while writing it. Happy to iterate on any of them.
 What the patch changes

 WP_Taxonomy — adds an $allow_multiple_terms property (default true) and
 accepts it in set_props(). When false and no custom meta_box_cb is
 supplied, the default meta box callback is switched to a new
 post_single_term_meta_box() and the sanitize callback to a new
 taxonomy_meta_box_sanitize_cb_single_term().
 register_taxonomy() docblock — documents the new argument and a new @since
 7.1.0 tag for the arg introduction.
 post_single_term_meta_box() (new, in wp-admin/includes/meta-boxes.php) —
 renders radio buttons for hierarchical taxonomies and a <select> (via
 wp_dropdown_categories()) for non-hierarchical ones. A "None" option is
 offered when no default_term is configured.
 taxonomy_meta_box_sanitize_cb_single_term() (new, in wp-
 admin/includes/post.php) — normalizes the submitted array to at most one
 term ID.
 wp_set_object_terms() — enforces the cap at the shared assignment path, so
 REST, WP-CLI, and any direct caller honor the constraint — not just the
 admin UI. When $append is passed for a single-term taxonomy, the append is
 downgraded to a replace to avoid quietly stacking terms.
 Quick Edit (WP_Posts_List_Table) — for hierarchical taxonomies, renders a
 radio list instead of wp_terms_checklist(); for non-hierarchical, renders
 a dropdown instead of the tags <textarea>. Bulk Edit already excludes per-
 taxonomy controls for non-category taxonomies, so the server-side cap in
 (5) is what protects bulk operations.

 Design decisions worth flagging
 Argument name: allow_multiple_terms. I kept the name you proposed.
 single_value reads cleanly as a property but pairs awkwardly with a
 default of true ('single_value' => true to mean "allow many" is a double
 negative). A meta_box_style enum was tempting for extensibility, but it
 conflates UI shape with cardinality — the server-side cap has to happen
 regardless of which UI is used, so a boolean flag that governs both
 defaults matches the semantics better.
 Default is true. Every existing register_taxonomy() call is unaffected.
 Enforcement lives in wp_set_object_terms(), not just the metabox
 sanitizer. This was the biggest design call. The alternative — only
 capping in the sanitize callback — would leave REST (POST /wp/v2/posts
 with a tax array of many IDs), WP-CLI, and any plugin calling
 wp_set_post_terms() free to bypass the constraint. Centralizing it at the
 assignment path matches how default_term and other taxonomy-level
 semantics are enforced, and keeps the contract consistent for API
 consumers.
 "Last value wins" when multiple terms are submitted. This matches post-
 format semantics and means that if a form somehow submits two radio values
 (e.g. a custom client), the most recent one wins. Open to a stricter
 WP_Error instead if that's preferred.
 Custom meta_box_cb precedence. If a caller supplies their own meta_box_cb,
 we don't override it even when allow_multiple_terms => false — the custom
 UI is assumed to know what it's doing. The server-side cap still applies,
 so a misbehaving custom UI can't save multiple terms.
 Gutenberg / block editor. Out of scope for Core Trac — belongs in the
 gutenberg repo. The useEntityProp-backed PostTaxonomies component would
 need to read allow_multiple_terms (ideally exposed via the taxonomies REST
 schema) and render a <RadioControl> / <SelectControl> in place of the
 flat/hierarchical token field. Worth a companion ticket once the Core API
 shape is settled here. Also not yet exposed in the REST taxonomies
 endpoint — I didn't add it to
 WP_REST_Taxonomies_Controller::get_item_schema() in this patch because the
 API surface felt worth agreeing on first, but it's a natural follow-up.
 Bulk Edit. The existing UI already suppresses per-taxonomy controls in
 bulk mode (! $bulk), and the cap in wp_set_object_terms() means bulk-
 updating many posts to a single term still works correctly. No per-row
 bulk UI change needed, though an explicit bulk-edit dropdown for single-
 term taxonomies could be a follow-up enhancement.
 Open questions

 Argument naming — fine as-is, or would committers prefer an alternative?
 REST schema exposure — add allow_multiple_terms to the taxonomies endpoint
 schema in this patch or a follow-up?
 default_term interaction — when allow_multiple_terms => false and a
 default_term is set, I'm suppressing the "None" option so the UI always
 reflects a valid selection. Happy to make that configurable if there's a
 use case for allowing explicit clearing.
 Unit tests — haven't added them in this first pass; will follow up in a
 separate patch once the API shape is agreed, focused on
 wp_set_object_terms() cap behavior (including the $append downgrade), the
 new sanitize callback, and register_taxonomy() defaults wiring.

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/64991#comment:1>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list