
🛠 Exklusiva taxonomier i WordPress: hur du ersätter kryssrutor med radioknappar
Som standard låter WordPress dig tilldela hur många termer som helst från en enskild taxonomi till ett inlägg. Kryssrutor i sidofältet, och du är klar. Men vad händer om kunden behöver att redaktören väljer exakt ett alternativ? Till exempel "Projekttyp": case study, landningssida eller webbutik. Tre alternativ, och att ha två av dem samtidigt är meningslöst.
Det finns ingen inbyggd växel för "gör taxonomi exklusiv" i WordPress. En ticket i Trac har legat sedan 2010 utan framsteg. Men uppgiften kan lösas med kod, utan tillägg eller extra beroenden.
När du har läst klart den här artikeln kommer du att förvandla den vanliga metaboxen med kryssrutor till en panel med radioknappar: exakt en term per inlägg, färre redaktörsmisstag.
💡 Snabb översikt:
- Registrera en taxonomi med parametern meta_box_cb så att den vanliga metaboxen inte visas.
- Skapa ditt eget block med radioknappar på hooken add_meta_boxes.
- Använd save_post för att skriva den valda termen till databasen.
- Den fullständiga koden kan kopieras in i barntemats functions.php och fungerar direkt.
Vad taxonomier är och varför exklusivitet spelar roll
En taxonomi i WordPress är en mekanism för att gruppera inlägg. Standardfunktionerna "Kategorier" och "Etiketter" är också taxonomier. En anpassad taxonomi skapas för en specifik uppgift: "Projekttyp" för en portfölj, "Region" för en kontorskatalog, "Tjänstetyp" för en prislista.
Inbyggda kategorier fungerar som en exklusiv taxonomi: ett inlägg tillhör exakt en kategori, om du inte använder tilläggsplugins. Hierarkin "förälder → barn" antyder urvalslogiken för redaktören.
Alla anpassade taxonomier som registreras via register_taxonomy() är dock icke-exklusiva som standard. Gränssnittet består av kryssrutor eller ett fält med autocomplete. För etiketter och produktattribut är detta korrekt. Men när varje inlägg måste ha exakt en term blir kryssrutor en felkälla.
Lösningen: dölj den vanliga metaboxen och rendera din egen, med radioknappar och strikt kontroll. Detta är ingen workaround utan ett dokumenterat WordPress API, bara utspritt över flera steg.
Steg 1: registrera en anpassad taxonomi
Grunden är funktionen register_taxonomy(). Koden läggs till i barntemats functions.php eller via tillägget Code Snippets. Låt oss skapa en taxonomi project_type för vanliga inlägg:
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' );
Viktiga parametrar:
hierarchical => truemöjliggör en trädstruktur, som kategorier. Termer organiseras hierarkiskt: "Design → Landningssida", "Utveckling → Webbutik".show_in_rest => truegör taxonomin tillgänglig i REST API och blockredigeraren. Utan detta kommer Gutenberg inte att se metaboxen.meta_box_cb => falseochshow_in_quick_edit => falsetar helt bort det vanliga gränssnittet för termval.
Efter att ha sparat koden dök taxonomin project_type upp i menyn "Inlägg". Termer läggs till via "Inlägg → Projekttyp" med ett standardgränssnitt, som för kategorier.
Steg 2: dölj den vanliga metaboxen
Detta steg har faktiskt redan gjorts med parametrarna meta_box_cb och show_in_quick_edit i steg 1. För att sammanfatta:
meta_box_cb => falsetar bort metaboxen från inläggets redigeringssida.show_in_quick_edit => falsedöljer taxonomin från panelerna för snabbredigering och massredigering.
Utan dem lägger WordPress till ett standardgränssnitt: för hierarkiska taxonomier, kategorikryssrutor; för icke-hierarkiska, ett etikettfält med autocomplete.

Termer fylls i via en separat hanteringssida:

Steg 3: skapa en anpassad metabox med radioknappar
Registrera din egen metabox via hooken add_meta_boxes. Lägg till i 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 }
Parametrar för add_meta_box():
project_type_box: internt ID (godtyckligt men unikt).'Project Type': titel i adminpanelen.sd_render_project_type_meta_box: renderingsfunktion.'post': inläggstyp; kan vara en array för flera CPT:er.'side': sidofält. Alternativ:'normal','advanced'.
Funktionen som renderar radioknapparna:
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 }
Vad som är viktigt här:
get_terms()medhide_empty => falsereturnerar alla termer, inklusive oanvända.get_the_terms()returnerar en array; vi tar det första elementet[0]eftersom logiken garanterar högst en term.checked()är en inbyggd WordPress-funktion som matar utchecked="checked"när det finns en träff.esc_attr()ochesc_html()är obligatorisk escaping.
Resultatet är ett rent block med radioknappar:

Inga kryssrutor, inget sätt att välja två alternativ.
Steg 4: spara termen när inlägget sparas
Utan detta steg är metaboxen rent dekorativ. Vi använder hooken 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 }
Detaljer:
DOING_AUTOSAVE: vi hoppar över autosparningar. Utan denna kontroll skrivs termen över i bakgrunden var 60:e sekund.current_user_can( 'edit_post', $post_id ): grundläggande behörighetskontroll.absint()konverterar värdet till ett positivt heltal, säkrare än(int) sanitize_text_field().wp_set_object_terms()med ett enskilt ID (inte en array) skriver exakt en term och tar bort tidigare kopplingar.
Klart. Spara inlägget, så låses radioknappsvalet. När du öppnar det igen är den valda termen markerad.
Fullständig kod för kopiering
Alla fyra steg i ett snippet. Lägg till i ditt barntemas functions.php eller via 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 }
⚠️ Gör en fullständig säkerhetskopia av webbplatsen innan du klistrar in. Koden har testats på den aktuella versionen av WordPress med den klassiska redigeraren. I Gutenberg visas den anpassade metaboxen i sidofältet utan ändringar.
I praktiken distribuerade vi detta snippet på tre projekt, och det fungerade överallt utan modifieringar. Om du har en hierarkisk inläggstyp eller flera redaktörsroller, ersätt 'post' med din slug och verifiera behörigheter i save_post.
WordPress Trac har haft ticket #14877 öppen sedan 2010 för inbyggt stöd för exklusiv taxonomi. När en parameter 'exclusive' => true dyker upp i core, kommer hela denna konstruktion att krympa till en enda rad. Tills ticketen får rörelse förblir radioknappsmetoden den primära lösningen.
Och nedan, en kort video om ämnet så att du kan se processen i aktion:
⁉️🤔 Vanliga frågor
Fungerar detta i Gutenberg?
Ja. Parametern
show_in_rest => truevid registrering av taxonomin möjliggör kompatibilitet med blockredigeraren. Den anpassade metaboxen visas i dokumentets sidofält, och radioknappar visas och sparas korrekt.
Kan denna metod tillämpas på anpassade inläggstyper?
Ja. Ersätt
'post'iregister_taxonomy()ochadd_meta_box()med din CPT-slug. Resten av koden (taxonominamn, etikett, parametrar) förblir densamma. Metoden fungerar med alla registrerade inläggstyper, inklusive de som skapats via ACF eller Custom Post Type UI.
Vad händer om redaktören inte väljer någon term?
Inlägget sparas utan tilldelad term;
save_postanropar helt enkelt intewp_set_object_terms(). Om obligatoriskt val är kritiskt, lägg till JavaScript-validering i admin eller en kontroll via hookenpre_post_update.
Varför inte använda tillägget Radio Buttons for Taxonomies?
Du kan. Tillägget löser uppgiften utan kod och har 100 000+ aktiva installationer. Nackdelen är ytterligare ett beroende. För en eller två webbplatser är tillägget motiverat. För byråer och multisites ger kod i temat full kontroll utan extra uppdateringar och konflikter.
Hur lägger jag till hierarkiskt urval (förälder → barn)?
Hierarkiska taxonomier (
hierarchical => true) får en förälder-barn-struktur automatiskt. För att visa hierarkin i den anpassade metaboxen, ersättget_terms()medwp_dropdown_categories()med parametern'taxonomy' => 'project_type'; funktionen kommer att mata ut en select med indrag.
Sammanfattning: när det är värt ansträngningen att skriva kod
En exklusiv taxonomi behövs inte för varje projekt. Om redaktörer förstår webbplatsens logik och inte gör misstag vid val, räcker vanliga kryssrutor. Men när kostnaden för fel är hög (en landningssida i portföljen felaktigt markerad som både "webbutik" och "case study"), betalar en halvtimmes kodning sig i innehållets renhet.
- Om du har en webbplats och ingen utvecklare, installera Radio Buttons for Taxonomies. Det fungerar utan kod.
- Om du är en byrå eller driver en multisite, kopiera koden ovan till ditt bastema. Färre tillägg, färre felpunkter vid uppdateringar.
- Om din webbplats körs på ren Gutenberg, överväg om du ens behöver en taxonomi. Kanske räcker ett ACF-fält med radioknappar: färre entiteter, snabbare admin.
Börja med en testsajt. Registrera taxonomin, lägg till tre termer och skapa ett inlägg; gränssnittet fungerar omedelbart. Skriv i kommentarerna vilken uppgift du använde en exklusiv taxonomi för.



