Skip to content

Tudo para WordPress, desenvolvimento web — e não só

🛠 Taxonomias exclusivas no WordPress: como substituir caixas de seleção por botões de rádio

🛠 Taxonomias exclusivas no WordPress: como substituir caixas de seleção por botões de rádio

Por predefinição, o WordPress permite atribuir a uma publicação quantos termos de uma única taxonomia quiser. Caixas de seleção na barra lateral e está pronto. Mas e se o cliente precisar que o editor selecione exatamente uma opção? Por exemplo, «Tipo de projeto»: caso de estudo, página de destino ou loja online. Três opções, e ter duas delas em conjunto não faz sentido.

Não existe nenhum interruptor incorporado para «tornar a taxonomia exclusiva» no WordPress. Um ticket no Trac está parado desde 2010, sem progresso. Mas a tarefa pode ser resolvida com código, sem plugins ou dependências extra.

No final deste artigo, irá transformar a caixa meta padrão com caixas de seleção num painel com botões de rádio: exatamente um termo por publicação, menos erros do editor.

💡 Resumo rápido:

  • Registe uma taxonomia com o parâmetro meta_box_cb para que a caixa meta padrão não apareça.
  • No hook add_meta_boxes, crie o seu próprio bloco com botões de rádio.
  • Use save_post para escrever o termo selecionado na base de dados.
  • O código completo pode ser copiado para o ficheiro functions.php do tema filho e funciona de imediato.

O que são taxonomias e porque é que a exclusividade é importante

Uma taxonomia no WordPress é um mecanismo para agrupar publicações. As «Categorias» e «Etiquetas» padrão também são taxonomias. Uma taxonomia personalizada é criada para uma tarefa específica: «Tipo de projeto» para um portefólio, «Região» para um diretório de filiais, «Tipo de serviço» para uma lista de preços.

As categorias incorporadas funcionam como uma taxonomia exclusiva: uma publicação pertence exatamente a uma categoria, a menos que use plugins de extensão. A hierarquia «pai → filho» sugere a lógica de seleção ao editor.

No entanto, qualquer taxonomia personalizada registada através de register_taxonomy() é não exclusiva por predefinição. A interface consiste em caixas de seleção ou um campo com preenchimento automático. Para etiquetas e atributos de produtos, isto está correto. Mas quando cada publicação deve ter exatamente um termo, as caixas de seleção tornam-se uma fonte de erros.

A solução: oculte a caixa meta padrão e renderize a sua própria, com botões de rádio e controlo rigoroso. Isto não é uma solução de recurso, mas sim uma API documentada do WordPress, apenas distribuída por vários passos.

Passo 1: registar uma taxonomia personalizada

A base é a função register_taxonomy(). O código é adicionado ao functions.php do tema filho ou através do plugin Code Snippets. Vamos criar uma taxonomia project_type para publicações padrão:

1function 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}
15add_action( 'init', 'sd_register_project_type_taxonomy' );

Parâmetros chave:

  • hierarchical => true ativa uma estrutura em árvore, como as categorias. Os termos são organizados hierarquicamente: «Design → Página de destino», «Desenvolvimento → Loja online».
  • show_in_rest => true torna a taxonomia disponível na API REST e no editor de blocos. Sem isto, o Gutenberg não verá a caixa meta.
  • meta_box_cb => false e show_in_quick_edit => false removem completamente a interface padrão de seleção de termos.

Depois de guardar o código, a taxonomia project_type apareceu no menu «Publicações». Os termos são adicionados através de «Publicações → Tipo de projeto» com uma interface padrão, como para as categorias.

Passo 2: ocultar a caixa meta padrão

Este passo já foi, na verdade, realizado com os parâmetros meta_box_cb e show_in_quick_edit no passo 1. Para recapitular:

  • meta_box_cb => false remove a caixa meta da página de edição da publicação.
  • show_in_quick_edit => false oculta a taxonomia dos painéis de edição rápida e em massa.

Sem eles, o WordPress adiciona uma interface padrão: para taxonomias hierárquicas, caixas de seleção de categorias; para as não hierárquicas, um campo de etiqueta com preenchimento automático.

parâmetros meta_box_cb e show_in_quick_edit no register_taxonomy

Os termos são preenchidos através de uma página de gestão separada:

Página de gestão de termos de taxonomia personalizada no admin do WordPress

Passo 3: criar uma caixa meta personalizada com botões de rádio

Registe a sua própria caixa meta através do hook add_meta_boxes. Adicione ao 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 __( '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 (arbitrário, mas único).
  • 'Project Type': título no painel de administração.
  • sd_render_project_type_meta_box: função de renderização.
  • 'post': tipo de publicação; pode ser um array para vários CPT.
  • 'side': barra lateral. Alternativas: 'normal', 'advanced'.

A função que renderiza os botões de rádio:

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>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}

O que é importante aqui:

  • get_terms() com hide_empty => false devolve todos os termos, incluindo os não utilizados.
  • get_the_terms() devolve um array; usamos o primeiro elemento [0], uma vez que a lógica garante que não há mais do que um termo.
  • checked() é uma função incorporada do WordPress que produz checked="checked" quando há uma correspondência.
  • esc_attr() e esc_html() são escapes obrigatórios.

O resultado é um bloco limpo com botões de rádio:

Caixa personalizada com botões de rádio para selecionar um único termo de taxonomia

Sem caixas de seleção, sem forma de selecionar duas opções.

Passo 4: guardar o termo quando a publicação é guardada

Sem este passo, a caixa meta é puramente decorativa. Usamos o hook 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}

Detalhes:

  • DOING_AUTOSAVE: ignoramos os autosaves. Sem esta verificação, o termo é sobrescrito em segundo plano a cada 60 segundos.
  • current_user_can( 'edit_post', $post_id ): controlo básico de permissões.
  • absint() converte o valor para um número inteiro positivo, mais seguro do que (int) sanitize_text_field().
  • wp_set_object_terms() com um único ID (não um array) escreve exatamente um termo, removendo associações anteriores.

Pronto. Guarde a publicação e a seleção do botão de rádio será fixada. Quando a reabrir, o termo selecionado estará destacado.

Código completo para copiar

Todos os quatro passos num único fragmento. Adicione ao functions.php do seu tema filho ou através do Code Snippets:

1/**
2 * Exclusive taxonomy "Project Type" — one term per post.
3 * Add to child theme's functions.php.
4 */
5function 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}
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 __( 'Project Type', '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>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
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}

⚠️ Faça uma cópia de segurança completa do site antes de colar. O código foi testado na versão atual do WordPress com o editor clássico. No Gutenberg, a caixa meta personalizada é exibida na barra lateral sem alterações.

Na prática, implementámos este fragmento em três projetos e funcionou em todos sem modificações. Se tiver um tipo de publicação hierárquico ou várias funções de editor, substitua 'post' pelo seu slug e verifique as permissões em save_post.


O Trac do WordPress tem o ticket #14877 aberto desde 2010 para suporte nativo a taxonomia exclusiva. Assim que um parâmetro 'exclusive' => true aparecer no núcleo, toda esta construção será reduzida a uma única linha. Até que o ticket tenha movimento, a abordagem dos botões de rádio continua a ser a solução principal.

E abaixo, um pequeno vídeo sobre o tema para que possa ver o processo em ação:

⁉️🤔 Perguntas frequentes

Isto funciona no Gutenberg?

Sim. O parâmetro show_in_rest => true ao registar a taxonomia permite a compatibilidade com o editor de blocos. A caixa meta personalizada aparece na barra lateral do documento e os botões de rádio são exibidos e guardados corretamente.

Esta abordagem pode ser aplicada a tipos de publicação personalizados?

Sim. Substitua 'post' em register_taxonomy() e add_meta_box() pelo slug do seu CPT. O resto do código (nome da taxonomia, etiqueta, parâmetros) permanece igual. A abordagem funciona com qualquer tipo de publicação registado, incluindo os criados através de ACF ou Custom Post Type UI.

O que acontece se o editor não selecionar nenhum termo?

A publicação será guardada sem um termo atribuído; o save_post simplesmente não chamará wp_set_object_terms(). Se a seleção obrigatória for crítica, adicione validação JavaScript na administração ou uma verificação através do hook pre_post_update.

Porque não usar o plugin Radio Buttons for Taxonomies?

Pode usar. O plugin resolve a tarefa sem código e tem mais de 100.000 instalações ativas. A desvantagem é mais uma dependência. Para um ou dois sites, o plugin justifica-se. Para agências e multisites, o código no tema dá controlo total sem atualizações extra e conflitos.

Como adiciono seleção hierárquica (pai → filho)?

As taxonomias hierárquicas (hierarchical => true) obtêm automaticamente uma estrutura pai-filho. Para exibir a hierarquia na caixa meta personalizada, substitua get_terms() por wp_dropdown_categories() usando o parâmetro 'taxonomy' => 'project_type'; a função produzirá um seletor com indentação.

Resumo final: quando vale a pena o esforço de escrever código

Uma taxonomia exclusiva não é necessária para todos os projetos. Se os editores compreendem a lógica do site e não cometem erros ao selecionar, as caixas de seleção padrão são suficientes. Mas quando o custo dos erros é alto (uma página de destino no portefólio marcada por engano como «loja online» e «caso de estudo»), meia hora de codificação compensa com a limpeza do conteúdo.

  • Se tem um site e nenhum programador, instale o Radio Buttons for Taxonomies. Funciona sem código.
  • Se é uma agência ou gere um multisite, copie o código acima para o seu tema base. Menos plugins, menos pontos de falha durante as atualizações.
  • Se o seu site funciona em Gutenberg puro, considere se precisa mesmo de uma taxonomia. Talvez um campo ACF com botões de rádio seja suficiente: menos entidades, administração mais rápida.

Comece com um site de teste. Registe a taxonomia, adicione três termos e crie uma publicação; a interface funcionará de imediato. Escreva nos comentários para que tarefa usou uma taxonomia exclusiva.