Skip to content

Wszystko o WordPressie, tworzeniu stron — i nie tylko

🛠 Ekskluzywne taksonomie w WordPress: jak zastąpić checkboxy przyciskami radiowymi

🛠 Ekskluzywne taksonomie w WordPress: jak zastąpić checkboxy przyciskami radiowymi

Domyślnie WordPress pozwala przypisać do wpisu dowolną liczbę terminów jednej taksonomii. Checkboxy w sidebarze i gotowe, porządek. Ale co, jeśli klient potrzebuje, aby redaktor wybrał dokładnie jedną opcję? Na przykład „Typ projektu": case, landing page lub sklep internetowy. Trzy pozycje, a dwie z nich jednocześnie nie mają sensu.

Wbudowanego przełącznika „ustaw taksonomię jako wyłączną" w WordPressie nie ma. Zgłoszenie w Trac wisi od 2010 roku bez ruchu. Ale zadanie rozwiązuje się kodem, bez wtyczek i zbędnych zależności.

Pod koniec artykułu zamienisz standardowy metabox z checkboxami na panel z radio buttonami: dokładnie jeden termin na wpis, mniej błędów redaktora.

💡 Szybki przegląd:

  • Rejestrujemy taksonomię z parametrem meta_box_cb, standardowy metabox nie pojawi się.
  • Na hooku add_meta_boxes tworzymy własny blok z radio buttonami.
  • Przez save_post zapisujemy wybrany termin w bazie danych.
  • Pełny kod kopiuje się do functions.php motywu potomnego i działa od razu.

Czym są taksonomie i dlaczego potrzebna jest wyłączność

Taksonomia w WordPressie to mechanizm grupowania wpisów. Standardowe „Kategorie" i „Tagi" to również taksonomie. Niestandardową taksonomię tworzy się pod konkretne zadanie: „Typ projektu" dla portfolio, „Region" dla katalogu oddziałów, „Rodzaj usługi" dla cennika.

Wbudowane kategorie działają jak taksonomia wyłączna: wpis należy do dokładnie jednej kategorii, jeśli nie używa się wtyczek rozszerzających. Hierarchia „nadrzędna → podrzędna" podpowiada redaktorowi logikę wyboru.

Natomiast każda niestandardowa taksonomia zarejestrowana przez register_taxonomy() jest domyślnie niewyłączna. Interfejs: checkboxy lub pole z autouzupełnianiem. Dla tagów i cech produktu jest to poprawne. Ale kiedy każdy wpis musi mieć dokładnie jeden termin, checkboxy stają się źródłem błędów.

Rozwiązanie: ukryć standardowy metabox i wyrenderować własny, z radio buttonami i ścisłą kontrolą. To nie obejście, a udokumentowane API WordPressa, po prostu rozłożone na kilka kroków.

Krok 1: rejestrujemy niestandardową taksonomię

Podstawa: funkcja register_taxonomy(). Kod dodaje się w functions.php motywu potomnego lub przez wtyczkę Code Snippets. Stwórzmy taksonomię project_type dla standardowych wpisów:

1function sd_register_project_type_taxonomy() {
2 register_taxonomy(
3 'project_type',
4 'post',
5 array(
6 'label' => __( 'Тип проекта', '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}
15add_action( 'init', 'sd_register_project_type_taxonomy' );

Kluczowe parametry:

  • hierarchical => true włącza strukturę drzewiastą, jak w kategoriach. Terminy budują hierarchię: „Design → Landing page", „Rozwój → Sklep internetowy".
  • show_in_rest => true udostępnia taksonomię w REST API i edytorze bloków. Bez tego Gutenberg nie zobaczy metaboxu.
  • meta_box_cb => false oraz show_in_quick_edit => false całkowicie usuwają standardowy interfejs wyboru terminów.

Po zapisaniu kodu taksonomia project_type pojawiła się w menu „Wpisy". Terminy dodaje się przez „Wpisy → Typ projektu", interfejs jest standardowy, jak dla kategorii.

Krok 2: ukrywamy standardowy metabox

W praktyce ten krok został już wykonany przez parametry meta_box_cb i show_in_quick_edit w kroku 1. Utwierdźmy się:

  • meta_box_cb => false usuwa metabox ze strony edycji wpisu.
  • show_in_quick_edit => false ukrywa taksonomię z panelu szybkiej i masowej edycji.

Bez nich WordPress dodaje domyślny interfejs: dla taksonomii hierarchicznych checkboxy kategorii, dla niehierarchicznych pole tagów z autouzupełnianiem.

Parametry meta_box_cb i show_in_quick_edit w register_taxonomy

Terminy wypełnia się przez osobną stronę zarządzania:

Strona zarządzania terminami niestandardowej taksonomii w panelu WordPress

Krok 3: tworzymy niestandardowy metabox z radio buttonami

Rejestrujemy własny metabox przez hook add_meta_boxes. Dodaj w functions.php:

1add_action( 'add_meta_boxes', 'sd_add_project_type_meta_box' );
2
3function sd_add_project_type_meta_box() {
4 add_meta_box(
5 'project_type_box',
6 __( 'Тип проекта', 'textdomain' ),
7 'sd_render_project_type_meta_box',
8 'post',
9 'side',
10 'default'
11 );
12}

Parametry add_meta_box():

  • project_type_box, wewnętrzne ID (dowolne, ale unikalne).
  • 'Тип проекта', tytuł w panelu administracyjnym.
  • sd_render_project_type_meta_box, funkcja renderująca.
  • 'post', typ wpisu; można podać tablicę dla kilku CPT.
  • 'side', panel boczny. Alternatywy: 'normal', 'advanced'.

Funkcja renderująca radio buttony:

1function 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>Сначала добавьте термины на странице «Тип проекта».</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}

Co jest tutaj ważne:

  • get_terms() z hide_empty => false zwraca wszystkie terminy, włącznie z nieużywanymi.
  • get_the_terms() zwraca tablicę, bierzemy pierwszy element [0], ponieważ logika gwarantuje nie więcej niż jeden termin.
  • checked(), wbudowana funkcja WordPressa, wypisuje checked="checked" przy zgodności.
  • esc_attr() oraz esc_html(), obowiązkowe eskejpowanie.

Rezultat: czysty blok z radio buttonami:

Niestandardowe metabox z przyciskami radiowymi do wyboru jednego terminu taksonomii

Żadnych checkboxów, żadnej możliwości wyboru dwóch opcji.

Krok 4: zapisujemy termin przy zapisie wpisu

Bez tego kroku metabox jest czysto dekoracyjny. Używamy hooka save_post:

1add_action( 'save_post', 'sd_save_project_type_term' );
2
3function 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}

Szczegóły:

  • DOING_AUTOSAVE, pomijamy autozapis. Bez tego sprawdzenia termin jest nadpisywany w tle co 60 sekund.
  • current_user_can( 'edit_post', $post_id ), podstawowa kontrola uprawnień.
  • absint() konwertuje wartość na dodatnią liczbę całkowitą, bezpieczniej niż (int) sanitize_text_field().
  • wp_set_object_terms() z pojedynczym ID (nie tablicą) zapisuje dokładnie jeden termin, usuwając poprzednie powiązania.

Gotowe. Zapisz wpis, radio button zostanie utrwalony. Przy następnym otwarciu wybrany termin jest podświetlony.

Pełny kod do skopiowania

Wszystkie cztery kroki w jednym fragmencie. Dodaj w functions.php motywu potomnego lub przez Code Snippets:

1/**
2 * Эксклюзивная таксономия «Тип проекта» — один термин на пост.
3 * Добавить в functions.php дочерней темы.
4 */
5function sd_register_project_type_taxonomy() {
6 register_taxonomy(
7 'project_type',
8 'post',
9 array(
10 'label' => __( 'Тип проекта', '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}
19add_action( 'init', 'sd_register_project_type_taxonomy' );
20
21add_action( 'add_meta_boxes', 'sd_add_project_type_meta_box' );
22
23function sd_add_project_type_meta_box() {
24 add_meta_box(
25 'project_type_box',
26 __( 'Тип проекта', 'textdomain' ),
27 'sd_render_project_type_meta_box',
28 'post',
29 'side',
30 'default'
31 );
32}
33
34function 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>Сначала добавьте термины на странице «Тип проекта».</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
61add_action( 'save_post', 'sd_save_project_type_term' );
62
63function 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}

⚠️ Przed wklejeniem wykonaj pełną kopię zapasową strony. Kod został sprawdzony na aktualnej wersji WordPressa z klasycznym edytorem. W Gutenbergu niestandardowy metabox wyświetla się w panelu bocznym bez zmian.

W praktyce wdrażaliśmy ten snippet na trzech projektach, wszędzie zadziałał bez poprawek. Jeśli masz hierarchiczny typ wpisu lub kilka ról redaktorów, zamień 'post' na swój slug i zweryfikuj uprawnienia w save_post.


W WordPress Trac od 2010 roku wisi zgłoszenie #14877 dotyczące natywnego wsparcia dla wyłącznych taksonomii. Pojawi się parametr 'exclusive' => true w jądrze, cała konstrukcja skurczy się do jednej linijki. Póki zgłoszenie jest bez ruchu, podejście z radio buttonami pozostaje podstawowym rozwiązaniem.

A poniżej krótkie wideo na ten temat, aby zobaczyć proces na własne oczy:

⁉️🤔 Często zadawane pytania

Czy to działa w Gutenbergu?

Tak. Parametr show_in_rest => true przy rejestracji taksonomii włącza kompatybilność z edytorem bloków. Niestandardowy metabox pojawia się w bocznym panelu dokumentu, radio buttony wyświetlają się i zapisują poprawnie.

Czy można zastosować to podejście do dowolnych typów wpisów?

Tak. Zamień 'post' w register_taxonomy() i add_meta_box() na slug swojego CPT. Reszta kodu, nazwa taksonomii, etykieta, parametry, nie zmienia się. Podejście działa z każdym zarejestrowanym typem wpisu, włącznie z tymi utworzonymi przez ACF lub Custom Post Type UI.

Co się stanie, jeśli redaktor nie wybierze żadnego terminu?

Wpis zostanie zapisany bez przypisanego terminu, save_post po prostu nie wywoła wp_set_object_terms(). Jeśli obowiązkowy wybór jest krytyczny, dodaj walidację JavaScript w panelu administracyjnym lub sprawdzenie przez hook pre_post_update.

Dlaczego nie użyć wtyczki Radio Buttons for Taxonomies?

Można. Wtyczka rozwiązuje zadanie bez kodu, 100 000+ aktywnych instalacji. Minus: kolejna zależność. Dla jednej-dwóch stron wtyczka jest uzasadniona. Dla agencji i multisite kod w motywie daje pełną kontrolę bez zbędnych aktualizacji i konfliktów.

Jak dodać wybór hierarchiczny (nadrzędny → podrzędny)?

Taksonomie hierarchiczne (hierarchical => true) automatycznie otrzymują strukturę rodzic-dziecko. Aby wyświetlić hierarchię w niestandardowym metaboxie, zamień get_terms() na wp_dropdown_categories() z parametrem 'taxonomy' => 'project_type', funkcja wyświetli select z wcięciami.

Podsumowując: kiedy warto zawracać sobie głowę kodem

Wyłączna taksonomia nie jest potrzebna w każdym projekcie. Jeśli redaktorzy rozumieją logikę strony i nie mylą się przy wyborze, standardowe checkboxy wystarczą. Ale kiedy cena błędu jest wysoka (landing page w portfolio błędnie oznaczony zarówno jako „sklep internetowy", jak i „case"), pół godziny na kod zwraca się czystością treści.

  • Jeśli masz jedną stronę i nie masz developera, zainstaluj Radio Buttons for Taxonomies. Działa bez kodu.
  • Jeśli to agencja lub multisite, skopiuj powyższy kod do motywu bazowego. Mniej wtyczek, mniej punktów awarii przy aktualizacjach.
  • Jeśli strona działa na czystym Gutenbergu, oceń, czy taksonomia jest w ogóle potrzebna. Być może wystarczy pole ACF z radio buttonami: mniej encji, szybszy panel administracyjny.

Zacznij od strony testowej. Zarejestruj taksonomię, dodaj trzy terminy i utwórz wpis, interfejs zadziała od razu. Napisz w komentarzach, do jakiego zadania użyłeś wyłącznej taksonomii.