
🛠 Taxonomías exclusivas en WordPress: cómo reemplazar las casillas de verificación con botones de opción
Por defecto, WordPress le permite asignar a una entrada tantos términos de una misma taxonomía como desee. Casillas de verificación en la barra lateral y listo. Pero ¿qué ocurre si el cliente necesita que el editor seleccione exactamente una opción? Por ejemplo, «Tipo de proyecto»: caso de estudio, página de aterrizaje o tienda en línea. Tres opciones, y tener dos de ellas juntas no tiene sentido.
No existe una opción integrada de «hacer la taxonomía exclusiva» en WordPress. Un ticket en Trac lleva abierto desde 2010 sin avances. Pero la tarea se puede resolver con código, sin plugins ni dependencias adicionales.
Al final de este artículo, usted habrá transformado el cuadro meta estándar con casillas de verificación en un panel con botones de opción: exactamente un término por entrada, menos errores del editor.
💡 Resumen rápido:
- Registre una taxonomía con el parámetro meta_box_cb para que no aparezca el cuadro meta estándar.
- En el gancho add_meta_boxes, cree su propio bloque con botones de opción.
- Utilice save_post para escribir el término seleccionado en la base de datos.
- El código completo se puede copiar en el archivo functions.php del tema hijo y funciona de inmediato.
Qué son las taxonomías y por qué importa la exclusividad
Una taxonomía en WordPress es un mecanismo para agrupar entradas. Las «Categorías» y «Etiquetas» estándar también son taxonomías. Una taxonomía personalizada se crea para una tarea específica: «Tipo de proyecto» para un portafolio, «Región» para un directorio de sucursales, «Tipo de servicio» para una lista de precios.
Las categorías integradas funcionan como una taxonomía exclusiva: una entrada pertenece exactamente a una categoría, a menos que use plugins de extensión. La jerarquía «padre → hijo» sugiere la lógica de selección al editor.
Sin embargo, cualquier taxonomía personalizada registrada mediante register_taxonomy() es no exclusiva por defecto. La interfaz consiste en casillas de verificación o un campo con autocompletado. Para etiquetas y atributos de producto, esto es correcto. Pero cuando cada entrada debe tener exactamente un término, las casillas de verificación se convierten en una fuente de errores.
La solución: oculte el cuadro meta estándar y renderice el suyo propio, con botones de opción y control estricto. Esto no es un parche, sino una API documentada de WordPress, solo que repartida en varios pasos.
Paso 1: registrar una taxonomía personalizada
La base es la función register_taxonomy(). El código se añade al archivo functions.php del tema hijo o mediante el plugin Code Snippets. Vamos a crear una taxonomía project_type para las entradas estándar:
1 function sd_register_project_type_taxonomy() { 2 register_taxonomy( 3 'project_type', 4 'post', 5 array( 6 'label' => __( 'Project Type', 'textdomain' ), 7 'public' => true, 8 'show_in_rest' => true, 9 'hierarchical' => true, 10 'show_in_quick_edit' => false, 11 'meta_box_cb' => false, 12 ) 13 ); 14 } 15 add_action( 'init', 'sd_register_project_type_taxonomy' );
Parámetros clave:
hierarchical => truehabilita una estructura de árbol, como las categorías. Los términos se organizan jerárquicamente: «Diseño → Página de aterrizaje», «Desarrollo → Tienda en línea».show_in_rest => truehace que la taxonomía esté disponible en la API REST y en el editor de bloques. Sin esto, Gutenberg no verá el cuadro meta.meta_box_cb => falseyshow_in_quick_edit => falseeliminan por completo la interfaz estándar de selección de términos.
Después de guardar el código, la taxonomía project_type apareció en el menú «Entradas». Los términos se añaden a través de «Entradas → Tipo de proyecto» con una interfaz estándar, como para las categorías.
Paso 2: ocultar el cuadro meta estándar
Este paso ya se ha realizado en realidad con los parámetros meta_box_cb y show_in_quick_edit del paso 1. Para recapitular:
meta_box_cb => falseelimina el cuadro meta de la página de edición de entradas.show_in_quick_edit => falseoculta la taxonomía de los paneles de edición rápida y por lotes.
Sin ellos, WordPress añade una interfaz predeterminada: para taxonomías jerárquicas, casillas de verificación de categorías; para las no jerárquicas, un campo de etiquetas con autocompletado.

Los términos se rellenan a través de una página de gestión independiente:

Paso 3: crear un cuadro meta personalizado con botones de opción
Registre su propio cuadro meta a través del gancho add_meta_boxes. Añada a functions.php:
1 add_action( 'add_meta_boxes', 'sd_add_project_type_meta_box' ); 2 3 function sd_add_project_type_meta_box() { 4 add_meta_box( 5 'project_type_box', 6 __( 'Project Type', 'textdomain' ), 7 'sd_render_project_type_meta_box', 8 'post', 9 'side', 10 'default' 11 ); 12 }
Parámetros de add_meta_box():
project_type_box: ID interno (arbitrario pero único).'Project Type': título en el panel de administración.sd_render_project_type_meta_box: función de renderizado.'post': tipo de entrada; puede ser un array para varios CPT.'side': barra lateral. Alternativas:'normal','advanced'.
La función que renderiza los botones de opción:
1 function sd_render_project_type_meta_box( $post ) { 2 $terms = get_terms( array( 3 'taxonomy' => 'project_type', 4 'hide_empty' => false, 5 ) ); 6 7 if ( empty( $terms ) || is_wp_error( $terms ) ) { 8 echo '<p>First, add terms on the “Project Type” page.</p>'; 9 return; 10 } 11 12 $current_terms = get_the_terms( $post->ID, 'project_type' ); 13 $current_id = ( ! empty( $current_terms ) && ! is_wp_error( $current_terms ) ) 14 ? $current_terms[0]->term_id 15 : 0; 16 17 foreach ( $terms as $term ) : ?> 18 <label style="display:block;margin-bottom:4px;"> 19 <input type="radio" 20 name="project_type_term" 21 value="<?php echo esc_attr( $term->term_id ); ?>" 22 <?php checked( $current_id, $term->term_id ); ?>> 23 <?php echo esc_html( $term->name ); ?> 24 </label> 25 <?php endforeach; 26 }
Lo importante aquí:
get_terms()conhide_empty => falsedevuelve todos los términos, incluidos los no utilizados.get_the_terms()devuelve un array; tomamos el primer elemento[0]ya que la lógica garantiza que no haya más de un término.checked()es una función integrada de WordPress que imprimechecked="checked"cuando hay una coincidencia.esc_attr()yesc_html()son escapes obligatorios.
El resultado es un bloque limpio con botones de opción:

Sin casillas de verificación, sin forma de seleccionar dos opciones.
Paso 4: guardar el término al guardar la entrada
Sin este paso, el cuadro meta es puramente decorativo. Usamos el gancho save_post:
1 add_action( 'save_post', 'sd_save_project_type_term' ); 2 3 function sd_save_project_type_term( $post_id ) { 4 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { 5 return; 6 } 7 8 if ( ! current_user_can( 'edit_post', $post_id ) ) { 9 return; 10 } 11 12 if ( isset( $_POST['project_type_term'] ) ) { 13 $term_id = absint( $_POST['project_type_term'] ); 14 wp_set_object_terms( $post_id, $term_id, 'project_type' ); 15 } 16 }
Detalles:
DOING_AUTOSAVE: omitimos los autoguardados. Sin esta comprobación, el término se sobrescribe en segundo plano cada 60 segundos.current_user_can( 'edit_post', $post_id ): control básico de permisos.absint()convierte el valor a un entero positivo, más seguro que(int) sanitize_text_field().wp_set_object_terms()con un solo ID (no un array) escribe exactamente un término, eliminando las asociaciones previas.
Listo. Guarde la entrada y la selección del botón de opción quedará fijada. Al reabrirla, el término seleccionado aparece resaltado.
Código completo para copiar
Los cuatro pasos en un solo fragmento. Añádalo al archivo functions.php de su tema hijo o a través de Code Snippets:
1 /** 2 * Exclusive taxonomy "Project Type" — one term per post. 3 * Add to child theme's functions.php. 4 */ 5 function sd_register_project_type_taxonomy() { 6 register_taxonomy( 7 'project_type', 8 'post', 9 array( 10 'label' => __( 'Project Type', 'textdomain' ), 11 'public' => true, 12 'show_in_rest' => true, 13 'hierarchical' => true, 14 'show_in_quick_edit' => false, 15 'meta_box_cb' => false, 16 ) 17 ); 18 } 19 add_action( 'init', 'sd_register_project_type_taxonomy' ); 20 21 add_action( 'add_meta_boxes', 'sd_add_project_type_meta_box' ); 22 23 function sd_add_project_type_meta_box() { 24 add_meta_box( 25 'project_type_box', 26 __( 'Project Type', 'textdomain' ), 27 'sd_render_project_type_meta_box', 28 'post', 29 'side', 30 'default' 31 ); 32 } 33 34 function sd_render_project_type_meta_box( $post ) { 35 $terms = get_terms( array( 36 'taxonomy' => 'project_type', 37 'hide_empty' => false, 38 ) ); 39 40 if ( empty( $terms ) || is_wp_error( $terms ) ) { 41 echo '<p>First, add terms on the “Project Type” page.</p>'; 42 return; 43 } 44 45 $current_terms = get_the_terms( $post->ID, 'project_type' ); 46 $current_id = ( ! empty( $current_terms ) && ! is_wp_error( $current_terms ) ) 47 ? $current_terms[0]->term_id 48 : 0; 49 50 foreach ( $terms as $term ) : ?> 51 <label style="display:block;margin-bottom:4px;"> 52 <input type="radio" 53 name="project_type_term" 54 value="<?php echo esc_attr( $term->term_id ); ?>" 55 <?php checked( $current_id, $term->term_id ); ?>> 56 <?php echo esc_html( $term->name ); ?> 57 </label> 58 <?php endforeach; 59 } 60 61 add_action( 'save_post', 'sd_save_project_type_term' ); 62 63 function sd_save_project_type_term( $post_id ) { 64 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { 65 return; 66 } 67 68 if ( ! current_user_can( 'edit_post', $post_id ) ) { 69 return; 70 } 71 72 if ( isset( $_POST['project_type_term'] ) ) { 73 $term_id = absint( $_POST['project_type_term'] ); 74 wp_set_object_terms( $post_id, $term_id, 'project_type' ); 75 } 76 }
⚠️ Haga una copia de seguridad completa del sitio antes de pegar. El código ha sido probado en la versión actual de WordPress con el editor clásico. En Gutenberg, el cuadro meta personalizado se muestra en la barra lateral sin cambios.
En la práctica, desplegamos este fragmento en tres proyectos y funcionó en todos sin modificaciones. Si tiene un tipo de entrada jerárquico o múltiples roles de editor, reemplace 'post' por su slug y verifique los permisos en save_post.
El Trac de WordPress tiene el ticket #14877 abierto desde 2010 para el soporte nativo de taxonomías exclusivas. Una vez que aparezca un parámetro 'exclusive' => true en el núcleo, toda esta construcción se reducirá a una sola línea. Hasta que el ticket tenga movimiento, el enfoque de los botones de opción sigue siendo la solución principal.
Y a continuación, un breve video sobre el tema para que pueda ver el proceso en acción:
⁉️🤔 Preguntas frecuentes
¿Funciona esto en Gutenberg?
Sí. El parámetro
show_in_rest => trueal registrar la taxonomía habilita la compatibilidad con el editor de bloques. El cuadro meta personalizado aparece en la barra lateral del documento, y los botones de opción se muestran y guardan correctamente.
¿Se puede aplicar este enfoque a tipos de entrada personalizados?
Sí. Reemplace
'post'enregister_taxonomy()yadd_meta_box()por el slug de su CPT. El resto del código (nombre de la taxonomía, etiqueta, parámetros) permanece igual. El enfoque funciona con cualquier tipo de entrada registrado, incluidos los creados a través de ACF o Custom Post Type UI.
¿Qué sucede si el editor no selecciona ningún término?
La entrada se guardará sin un término asignado;
save_postsimplemente no llamará awp_set_object_terms(). Si la selección obligatoria es crítica, añada validación JavaScript en el administrador o una comprobación mediante el ganchopre_post_update.
¿Por qué no usar el plugin Radio Buttons for Taxonomies?
Puede hacerlo. El plugin resuelve la tarea sin código y tiene más de 100 000 instalaciones activas. La desventaja es otra dependencia. Para uno o dos sitios, el plugin está justificado. Para agencias y multisitios, el código en el tema da control total sin actualizaciones extra ni conflictos.
¿Cómo añado selección jerárquica (padre → hijo)?
Las taxonomías jerárquicas (
hierarchical => true) obtienen una estructura padre-hijo automáticamente. Para mostrar la jerarquía en el cuadro meta personalizado, reemplaceget_terms()porwp_dropdown_categories()usando el parámetro'taxonomy' => 'project_type'; la función generará un selector con sangría.
En conclusión: cuándo vale la pena el esfuerzo de escribir código
No en todos los proyectos se necesita una taxonomía exclusiva. Si los editores entienden la lógica del sitio y no cometen errores al seleccionar, las casillas de verificación estándar son suficientes. Pero cuando el costo de los errores es alto (una página de aterrizaje en el portafolio marcada erróneamente como «tienda en línea» y «caso de estudio» a la vez), media hora de codificación se amortiza con la limpieza del contenido.
- Si tiene un sitio y ningún desarrollador, instale Radio Buttons for Taxonomies. Funciona sin código.
- Si es una agencia o gestiona un multisitio, copie el código anterior en su tema base. Menos plugins, menos puntos de fallo durante las actualizaciones.
- Si su sitio funciona con Gutenberg puro, considere si realmente necesita una taxonomía. Quizás un campo de ACF con botones de opción sea suficiente: menos entidades, administración más rápida.
Comience con un sitio de prueba. Registre la taxonomía, añada tres términos y cree una entrada; la interfaz funcionará de inmediato. Escriba en los comentarios para qué tarea utilizó una taxonomía exclusiva.



