Exibir a categoria atual e a categoria pai no WordPress: guia técnico 2026

Exibir a categoria atual e a categoria pai no WordPress: guia técnico 2026

Última verificação: 15 de outubro de 2026
25 min de leitura
Tutorial
Desenvolvedor full-stack
500+ projetos WP

A exibição correta da hierarquia de categorias é fundamental para a navegação do utilizador e para SEO. Quando um visitante acede a um post, saber em que categoria e subcategoria ele se encontra ajuda na orientação e melhora a experiência do utilizador. Além disso, URLs de categorias bem estruturadas contribuem para o posicionamento nos motores de busca.

O WordPress utiliza um sistema de taxonomia flexível que permite criar hierarquias de categorias com múltiplos níveis. Contudo, extrair e exibir essas relações hierárquicas requer conhecimento das funções adequadas e da estrutura de dados do WordPress.

Este guia técnico ensina todas as técnicas para exibir categorias atuais, pais e hierarquias completas nos seus temas e plugins WordPress.

#O que são os fundamentos da taxonomia WordPress

#Categorias e tags no WordPress

Categorias são uma das duas taxonomias nativas do WordPress (a outra sendo tags). A principal diferença é que categorias são hierárquicas, o que significa que podem ter categorias “pai” e “filho”, enquanto tags são planas e não hierárquicas.

Características das categorias:

  • Podem ser organizadas em múltiplos níveis de profundidade
  • Cada post pode pertencer a múltiplas categorias
  • Categorias não utilizadas são mantidas no sistema
  • A estrutura hierárquica é armazenada no campo parent da tabela wp_term_taxonomy

#Em que tabelas o WordPress guarda as categorias

O WordPress armazena informações de categorias em várias tabelas da base de dados:

Tabela wp_terms Armazena os termos (categorias, tags, etc.) com os campos principais:

  • term_id: Identificador único
  • name: Nome da categoria
  • slug: Versão URL-friendly do nome
  • term_group: Agrupamento de termos sinónimos

Tabela wp_term_taxonomy Armazena as relações taxonómicas:

  • term_taxonomy_id: Identificador único
  • term_id: Referência para wp_terms
  • taxonomy: Tipo de taxonomia (category, post_tag, etc.)
  • parent: ID da categoria pai (0 se não houver pai)
  • count: Número de posts nessa categoria

#Propriedades do objeto de categoria

Quando obtém uma categoria no WordPress, recebe um objeto com as seguintes propriedades:

$category = get_category( 5 );

// Propriedades disponíveis:
echo $category->term_id;        // ID da categoria
echo $category->name;           // Nome (ex: "Tecnologia")
echo $category->slug;           // Slug (ex: "tecnologia")
echo $category->parent;         // ID do pai (0 se for categoria raiz)
echo $category->count;          // Número de posts
echo $category->description;    // Descrição da categoria
echo $category->cat_ID;         // Mesmo que term_id
echo $category->category_count; // Mesmo que count
echo $category->category_description; // Mesmo que description
echo $category->cat_name;       // Mesmo que name
echo $category->category_nicename; // Mesmo que slug
echo $category->category_parent; // Mesmo que parent

#Porque é que get_the_category() devolve a categoria errada

get_the_category() é prática e, ao mesmo tempo, a fonte de erro mais comum nos breadcrumbs. A função chama get_the_terms( $post_id, 'category' ) e devolve um array de objetos WP_Term ordenado por nome (o núcleo preenche a cache de termos com orderby => name), não pela hierarquia nem pela categoria que a redação considera principal. Se um post estiver em «Tecnologia», «WordPress» e «Desempenho», o primeiro elemento é o primeiro por ordem alfabética, não o nível mais profundo da árvore.

Fora do Loop, ou com um objeto de post diferente, passe sempre o ID: get_the_category( $post_id ). Caso contrário, a função usa o $post global e um widget ou um callback REST mostra a hierarquia do post errado.

$term->parent é apenas um ID inteiro. Sem get_category() ou get_term() não tem nome nem link. E sem esc_html() e esc_url() na saída, um nome de categoria com aspas ou «&» parte o HTML ou abre uma porta a XSS.

Há ainda a categoria predefinida. Uma instalação nova associa os posts à categoria «Sem categoria», e quando a redação mais tarde move o post para uma categoria real, a predefinida fica muitas vezes como segunda atribuição. Como o array vem ordenado por nome, um breadcrumb baseado em $categories[0] pode voltar a «Sem categoria». Filtre o termo guardado em get_option( 'default_category' ) antes de escolher a folha, ou exija uma categoria principal no processo editorial.

#Como usar get_the_category() com verificação de pai

#Função simples para mostrar a categoria pai e a atual

Esta é a solução mais direta para exibir apenas um nível de hierarquia (pai e filho):

/**
 * Obtém a hierarquia de categoria (pai é atual) para o post atual
 *
 * @return string|false HTML da hierarquia ou false se não houver categorias
 */
function wppoland_get_category_hierarchy() {
    // Obter todas as categorias do post atual
    $categories = get_the_category();

    // Se não houver categorias, retornar false
    if ( empty( $categories ) ) {
        return false;
    }

    // Usar a primeira categoria como base
    $category = $categories[0];

    $output = '';

    // Se a categoria tem um pai, exibir primeiro
    if ( $category->parent ) {
        $parent = get_category( $category->parent );
        $parent_link = get_category_link( $parent->term_id );
        $output .= '<a href="' . esc_url( $parent_link ) . '" class="category-parent">';
        $output .= esc_html( $parent->name ) . '</a>';
        $output .= '<span class="breadcrumb-separator"> &raquo; </span>';
    }

    // Categoria atual
    $current_link = get_category_link( $category->term_id );
    $output .= '<a href="' . esc_url( $current_link ) . '" class="category-current">';
    $output .= esc_html( $category->name ) . '</a>';

    return $output;
}

#Como usar a função no template do tema

<?php
// No seu template (single.php, archive.php, etc.)
if ( function_exists( 'wppoland_get_category_hierarchy' ) ) {
    $hierarchy = wppoland_get_category_hierarchy();
    if ( $hierarchy ) {
        echo '<nav class="category-breadcrumb" aria-label="Breadcrumb">';
        echo $hierarchy;
        echo '</nav>';
    }
}
?>

#CSS para estilizar o breadcrumb de categorias

.category-breadcrumb {
    font-size: 14px;
    color: #666;
    margin-bottom: 20px;
    padding: 10px 15px;
    background: #f9f9f9;
    border-radius: 4px;
}

.category-breadcrumb a {
    color: #0073aa;
    text-decoration: none;
    transition: color 0.2s ease;
}

.category-breadcrumb a:hover {
    color: #00a0d2;
    text-decoration: underline;
}

.breadcrumb-separator {
    margin: 0 8px;
    color: #999;
}

.category-parent {
    font-weight: 500;
}

.category-current {
}

#Como mostrar a categoria atual na página de arquivo de categoria

Numa página de arquivo de categoria, get_the_category() não ajuda: cada post da lista pode ter várias categorias e nenhuma delas tem de ser o arquivo que está a ser mostrado. A categoria do arquivo é o objeto consultado. is_category() confirma o contexto, get_queried_object() devolve o WP_Term do arquivo e get_queried_object_id() apenas o seu ID.

if ( is_category() ) {
	$term = get_queried_object();

	foreach ( array_reverse( get_ancestors( $term->term_id, 'category', 'taxonomy' ) ) as $ancestor_id ) {
		$ancestor = get_term( $ancestor_id, 'category' );
		if ( $ancestor && ! is_wp_error( $ancestor ) ) {
			printf(
				'<a href="%s">%s</a> <span aria-hidden="true">/</span> ',
				esc_url( get_term_link( $ancestor ) ),
				esc_html( $ancestor->name )
			);
		}
	}

	echo '<h1>' . esc_html( $term->name ) . '</h1>';
}

Aqui o caminho por cima do título nasce do próprio termo do arquivo, por isso um post classificado em três ramos não o consegue desviar. Para o título sozinho também serve single_cat_title(), que imprime o nome do arquivo de categoria atual.

#Como listar as subcategorias da categoria atual

A direção oposta ao pai é a lista de filhos. wp_list_categories() aceita child_of (todos os descendentes de um termo) e depth (quantos níveis imprime). Um title_li vazio remove o elemento de lista com o título predefinido «Categorias», e assim é o seu código que controla o ul.

if ( is_category() ) {
	echo '<ul class="subcategories">';
	wp_list_categories(
		array(
			'child_of' => get_queried_object_id(),
			'depth'    => 1,
			'title_li' => '',
		)
	);
	echo '</ul>';
}

Dois pormenores dos valores predefinidos: hide_empty vale 1, pelo que as subcategorias vazias não aparecem até passar 'hide_empty' => 0. E child_of sem depth imprime toda a subárvore, não só o nível direto. Se precisar de dados em vez de HTML, get_categories( array( 'parent' => $id ) ) devolve apenas os filhos diretos, enquanto get_term_children( $id, 'category' ) devolve os IDs de todos os descendentes em qualquer nível.

#Como verificar se um post está numa categoria filha

in_category() passa por has_category() até is_object_in_term(), e essa função compara apenas os termos atribuídos diretamente ao post. Um post classificado só em «WordPress» devolve false para in_category( 'tecnologia' ), mesmo que «WordPress» seja filha de «Tecnologia». Para condições do tipo «em qualquer ponto deste ramo», verifique também os antepassados:

/**
 * True if the post is in $parent_id or in any of its descendants.
 */
function wppoland_in_category_branch( $parent_id, $post_id = false ) {
	$parent_id = (int) $parent_id;

	foreach ( get_the_category( $post_id ) as $term ) {
		if ( $term->term_id === $parent_id || cat_is_ancestor_of( $parent_id, $term ) ) {
			return true;
		}
	}

	return false;
}

cat_is_ancestor_of() chama term_is_ancestor_of() com a taxonomia category e sobe pelos pais de forma recursiva. Em taxonomias personalizadas, chame diretamente term_is_ancestor_of( $pai, $filho, $taxonomia ). A mesma verificação evita que um item pai do menu lateral perca o estado ativo quando o leitor está no arquivo de uma neta.

#Como criar uma trilha breadcrumb completa

Para exibir toda a hierarquia (múltiplos níveis de ancestrais), precisamos de uma função recursiva:

/**
 * Obtém a trilha completa de categorias do post
 * Inclui todos os níveis: avô, pai, filho, neto
 *
 * @param int|null $post_id ID do post (opcional)
 * @return string HTML da trilha breadcrumb
 */
function wppoland_get_full_category_trail( $post_id = null ) {
    // Se não for específicado, usar o post atual
    if ( ! $post_id ) {
        $post_id = get_the_ID();
    }

    // Obter categorias do post
    $categories = get_the_category( $post_id );

    if ( empty( $categories ) ) {
        return '';
    }

    // Usar a primeira categoria
    $category = $categories[0];

    // Array para armazenar a trilha
    $trail = array();

    // Percorrer hierarquia de baixo para cima
    while ( $category->parent ) {
        $category = get_category( $category->parent );
        array_unshift( $trail, $category );
    }

    // Adicionar a categoria atual ao início
    array_unshift( $trail, get_category( $categories[0]->term_id ) );

    // Se a trilha só tem um elemento (categoria raiz), retornar apenas ela
    if ( count( $trail ) === 1 ) {
        $cat = $trail[0];
        return '<a href="' . esc_url( get_category_link( $cat->term_id ) ) . '">'
             . esc_html( $cat->name ) . '</a>';
    }

    // Construir HTML da trilha
    $output = '<nav class="breadcrumb-trail" aria-label="Breadcrumb">';
    $output .= '<ol class="breadcrumb-list">';

    foreach ( $trail as $index => $cat ) {
        $is_last = ( $index === count( $trail ) - 1 );

        $output .= '<li class="breadcrumb-item' . ( $is_last ? ' active' : '' ) . '">';

        if ( ! $is_last ) {
            $output .= '<a href="' . esc_url( get_category_link( $cat->term_id ) ) . '">';
            $output .= esc_html( $cat->name ) . '</a>';
            $output .= '<span class="breadcrumb-separator" aria-hidden="true">/</span>';
        } else {
            $output .= '<span class="breadcrumb-current">' . esc_html( $cat->name ) . '</span>';
        }

        $output .= '</li>';
    }

    $output .= '</ol>';
    $output .= '</nav>';

    return $output;
}

Para SEO avançado, adicione dados estruturados:

/**
 * Gera trilha breadcrumb com markup Schema.org JSON-LD
 *
 * @param int|null $post_id ID do post
 * @return string HTML + Script JSON-LD
 */
function wppoland_get_breadcrumb_with_schema( $post_id = null ) {
    if ( ! $post_id ) {
        $post_id = get_the_ID();
    }

    $categories = get_the_category( $post_id );

    if ( empty( $categories ) ) {
        return '';
    }

    $category = $categories[0];
    $trail = array();

    // Construir trilha de categorias
    while ( $category->parent ) {
        $category = get_category( $category->parent );
        array_unshift( $trail, $category );
    }
    array_unshift( $trail, get_category( $categories[0]->term_id ) );

    // Construir array para Schema.org
    $schema_items = array();

    // Homepage como primeiro item
    $schema_items[] = array(
        '@type' => 'ListItem',
        'position' => 1,
        'name' => 'Início',
        'item' => home_url( '/' )
    );

    // Categorias
    $position = 2;
    foreach ( $trail as $cat ) {
        $schema_items[] = array(
            '@type' => 'ListItem',
            'position' => $position,
            'name' => $cat->name,
            'item' => get_category_link( $cat->term_id )
        );
        $position++;
    }

    // Post atual (último item)
    $schema_items[] = array(
        '@type' => 'ListItem',
        'position' => $position,
        'name' => get_the_title( $post_id ),
        'item' => get_permalink( $post_id )
    );

    // Gerar JSON-LD
    $schema = array(
        '@context' => 'https://schema.org',
        '@type' => 'BreadcrumbList',
        'itemListElement' => $schema_items
    );

    // Gerar HTML
    $html = wppoland_get_full_category_trail( $post_id );

    // Adicionar JSON-LD
    $html .= '';

    return $html;
}

#Como usar get_category_parents() no WordPress

O WordPress oferece uma função nativa para obter a hierarquia de categorias:

/**
 * Usa get_category_parents() para obter hierarquia
 *
 * @param int $category_id ID da categoria
 * @param bool $link Se true, inclui links HTML
 * @param string $separator Separador entre categorias
 * @param bool $nicename Se true, usa nice name
 * @param array $deprecated Não usado desde o WordPress 4.8.0
 * @return string Hierarquia de categorias
 */
$parents = get_category_parents( $category_id, true, ' &raquo; ' );

// Exemplo completo com wrapper:
function wppoland_get_parents_wrapper() {
    $categories = get_the_category();

    if ( ! empty( $categories ) ) {
        $category = $categories[0];
        $parents = get_category_parents( $category->term_id, true, ' &raquo; ' );

        // Adicionar classes CSS
        $parents = str_replace(
            '<a href=',
            '<a class="breadcrumb-link" href=',
            $parents
        );

        return '<div class="category-parents">' . $parents . '</div>';
    }

    return '';
}

#Como usar get_term_parents_list() em vez de get_category_parents()

Desde o WordPress 4.8.0, get_category_parents() é apenas um invólucro: chama get_term_parents_list() com a taxonomia category. A mesma função trabalha com qualquer taxonomia hierárquica, incluindo product_cat do WooCommerce. Os argumentos são format (name ou slug), separator, link (por omissão true) e inclusive (por omissão true, que acrescenta o próprio termo no fim). O quinto argumento de get_category_parents() é $deprecated: não é usado desde a versão 4.8.0 e gera um aviso de descontinuação se lhe passar algum valor. O quarto, $nicename, mostra o slug em vez do nome, o que raramente interessa numa interface para leitores.

$list = get_term_parents_list(
	$term_id,
	'product_cat',
	array(
		'inclusive' => false,
		'separator' => ' / ',
	)
);

if ( $list && ! is_wp_error( $list ) ) {
	echo wp_kses_post( rtrim( $list, ' /' ) );
}

O código-fonte de category-template.php mostra duas particularidades. O nome entra no link sem esc_html(); só o URL passa por esc_url(). E o separador é acrescentado depois de cada elemento, incluindo o último, daí o rtrim() no exemplo. Com 'inclusive' => false omite o termo atual, por exemplo quando já aparece como título por baixo. A proteção contra uma cadeia de pais corrompida (um termo que, depois de uma importação defeituosa, aponta para um dos seus próprios descendentes) vem de get_ancestors(), que para assim que um ID de pai se repete.

#Obter posts por categoria com WP_Query

Quando precisa exibir posts de uma categoria e suas subcategorias:

/**
 * Obtém posts de uma categoria e todas suas subcategorias
 *
 * @param int|string $category Categoria por ID ou slug
 * @param int $posts_per_page Número de posts
 * @return WP_Query Resultado da query
 */
function wppoland_get_posts_in_category_and_children( $category, $posts_per_page = 10 ) {
    // Se for slug, obter ID
    if ( is_string( $category ) ) {
        $cat = get_category_by_slug( $category );
        if ( $cat ) {
            $category = $cat->term_id;
        }
    }

    // Obter todas as subcategorias
    $subcategories = get_categories( array(
        'child_of' => $category,
        'fields' => 'ids',
        'hide_empty' => false
    ) );

    // Incluir a categoria principal
    $all_categories = array_merge( array( $category ), $subcategories );

    // Query de posts
    $query = new WP_Query( array(
        'category__in' => $all_categories,
        'posts_per_page' => $posts_per_page,
        'orderby' => 'date',
        'order' => 'DESC',
        'ignore_sticky_posts' => true
    ) );

    return $query;
}

// Uso:
$query = wppoland_get_posts_in_category_and_children( 'tecnologia', 5 );

if ( $query->have_posts() ) {
    while ( $query->have_posts() ) {
        $query->the_post();
        // Exibir post
    }
    wp_reset_postdata();
}

#Exibir apenas categorias com posts

Para verificar se uma categoria tem posts antes de exibi-la:

/**
 * Verifica se categoria tem posts (incluindo subcategorias)
 *
 * @param int $category_id ID da categoria
 * @return bool True se tem posts
 */
function wppoland_category_has_posts( $category_id ) {
    $category = get_category( $category_id );

    // Verificar posts na categoria
    if ( $category->count > 0 ) {
        return true;
    }

    // Verificar posts nas subcategorias
    $subcategories = get_categories( array(
        'child_of' => $category_id,
        'hide_empty' => false,
        'fields' => 'ids'
    ) );

    foreach ( $subcategories as $sub_id ) {
        $sub = get_category( $sub_id );
        if ( $sub->count > 0 ) {
            return true;
        }
    }

    return false;
}

/**
 * Lista categorias com posts visíveis
 *
 * @return string HTML da lista
 */
function wppoland_list_active_categories() {
    $categories = get_categories( array(
        'hide_empty' => true,
        'parent' => 0, // Apenas categorias raiz
        'orderby' => 'name',
        'order' => 'ASC'
    ) );

    if ( empty( $categories ) ) {
        return '';
    }

    $output = '<ul class="active-categories">';

    foreach ( $categories as $cat ) {
        if ( wppoland_category_has_posts( $cat->term_id ) ) {
            $link = get_category_link( $cat->term_id );
            $output .= '<li><a href="' . esc_url( $link ) . '">';
            $output .= esc_html( $cat->name );
            $output .= '<span class="post-count">(' . intval( $cat->count ) . ')</span>';
            $output .= '</a></li>';
        }
    }

    $output .= '</ul>';

    return $output;
}

#Como trabalhar com categorias personalizadas e taxonomias

O sistema funciona da mesma forma para taxonomias personalizadas:

/**
 * Obtém hierarquia para qualquer taxonomia
 *
 * @param string $taxonomy Nome da taxonomia
 * @param int $term_id ID do termo
 * @return string HTML da hierarquia
 */
function wppoland_get_term_hierarchy( $taxonomy, $term_id ) {
    $term = get_term( $term_id, $taxonomy );

    if ( is_wp_error( $term ) || ! $term ) {
        return '';
    }

    $trail = array();
    $current = $term;

    // Percorrer hierarquia
    while ( $current->parent ) {
        $current = get_term( $current->parent, $taxonomy );
        array_unshift( $trail, $current );
    }

    // Adicionar termo atual
    array_unshift( $trail, $term );

    // Construir HTML
    $output = '<nav class="term-breadcrumb">';

    foreach ( $trail as $index => $t ) {
        $is_last = ( $index === count( $trail ) - 1 );

        if ( ! $is_last ) {
            $link = get_term_link( $t, $taxonomy );
            $output .= '<a href="' . esc_url( $link ) . '">' . esc_html( $t->name ) . '</a>';
            $output .= ' &raquo; ';
        } else {
            $output .= '<span class="current">' . esc_html( $t->name ) . '</span>';
        }
    }

    $output .= '</nav>';

    return $output;
}

// Uso para taxonomia personalizada:
$hierarchy = wppoland_get_term_hierarchy( 'produto_categoria', $term_id );

#Como ler a categoria principal do Yoast SEO e do Rank Math

Os editores atribuem muitas vezes várias categorias a um post, mas o breadcrumb deve seguir um único ramo. Os plugins SEO guardam essa escolha como post meta: o Yoast SEO em _yoast_wpseo_primary_category (o prefixo _yoast_wpseo_ mais primary_ e o nome da taxonomia, como mostra a classe WPSEO_Primary_Term) e o Rank Math em rank_math_primary_category. Leia esse valor antes de recorrer ao primeiro elemento do array:

/**
 * Devolve o ID da categoria folha para o breadcrumb.
 *
 * @param int $post_id ID do post.
 * @return int 0 se o post não tiver categorias.
 */
function wppoland_primary_category_id( $post_id ) {
	$post_id = (int) $post_id;

	foreach ( array( '_yoast_wpseo_primary_category', 'rank_math_primary_category' ) as $key ) {
		$term_id = (int) get_post_meta( $post_id, $key, true );
		if ( $term_id > 0 && term_exists( $term_id, 'category' ) ) {
			return $term_id;
		}
	}

	$categories = get_the_category( $post_id );
	return empty( $categories ) ? 0 : (int) $categories[0]->term_id;
}

O term_exists() protege contra um ID que ficou no meta depois de a categoria ter sido apagada. Sem plugin SEO, o núcleo do WordPress não tem o conceito de categoria principal: ou guarda o seu próprio post meta, ou aceita uma regra como «a categoria com mais antepassados». Quando dois plugins SEO convivem durante uma migração, decida qual deles é dono do campo e desative o módulo de breadcrumbs do outro.

#Como escolher a categoria quando o post tem várias

Quando um post pertence a múltiplas categorias, pode permitir que o utilizador escolha qual exibir:

/**
 * Exibe seletor de categorias para posts com múltiplas categorias
 *
 * @param int|null $post_id ID do post
 */
function wppoland_category_selector( $post_id = null ) {
    if ( ! $post_id ) {
        $post_id = get_the_ID();
    }

    $categories = get_the_category( $post_id );

    if ( count( $categories ) <= 1 ) {
        // Se só tem uma categoria, exibir normalmente
        echo wppoland_get_full_category_trail( $post_id );
        return;
    }

    // Múltiplas categorias - exibir seletor
    ?>
    <div class="multi-category-selector">
        <label for="category-select">Ver em:</label>
        <select id="category-select" onchange="window.location.href=this.value">
            <?php foreach ( $categories as $cat ) : ?>
                <option value="<?php echo esc_url( get_category_link( $cat->term_id ) ); ?>">
                    <?php echo esc_html( $cat->name ); ?>
                </option>
            <?php endforeach; ?>
        </select>
    </div>
    <?php
}

#O que a Google mostra a partir do BreadcrumbList

A documentação da Google sobre breadcrumbs define o mínimo: um BreadcrumbList com pelo menos dois ListItem, position a começar em 1 e um URL em item em cada elemento. A exceção é o último: se aí faltar item, a Google usa o URL da própria página. Para um post, a página inicial mais uma categoria já cumpre o mínimo; o título do post como último elemento é permitido, mas não obrigatório.

A Google aceita vários caminhos para a mesma página e recomenda um caminho que reflita o percurso típico do utilizador, em vez de copiar a estrutura do URL. Para breadcrumbs de categorias, isto é um argumento a favor da categoria principal: descreve o caminho pretendido pela redação, mesmo quando o permalink não contém nenhuma categoria.

O caminho só é visível na pesquisa Google em computador. Desde 23 de janeiro de 2025, os resultados em dispositivos móveis mostram apenas o domínio na linha do URL, como anunciou o blog Search Central. A marcação continua suportada e o relatório na Search Console mantém-se. Os breadcrumbs visíveis no tema servem, antes de mais, quem lê. Se o tema ou o plugin SEO já emitem um BreadcrumbList, não acrescente um segundo: escolha uma única fonte por modelo.

#Como usar o bloco Breadcrumbs do WordPress 7.0 com a categoria principal

Desde o WordPress 7.0, o núcleo inclui o seu próprio bloco core/breadcrumbs (a versão atual, segundo a API de versões do WordPress.org, é a 7.1.3). O block.json indica os atributos separator (por omissão /), showHomeItem, showCurrentItem, showOnHomePage e prefersTaxonomy. Num post sem post pai, o bloco constrói o caminho com termos de taxonomia: usa a primeira taxonomia registada para o tipo de conteúdo que tenha termos e, dentro dela, o primeiro termo devolvido por get_the_terms(), através de reset( $terms ). É a mesma armadilha de $categories[0]: sem intervenção, ganha o primeiro nome por ordem alfabética.

O código-fonte do bloco oferece para isso o filtro block_core_breadcrumbs_post_type_settings. Espera um array com taxonomy e term, e term é um slug, não um ID. Assim passa ao bloco a categoria principal do Yoast SEO ou do Rank Math:

add_filter(
	'block_core_breadcrumbs_post_type_settings',
	static function ( $settings, $post_type, $post_id ) {
		if ( 'post' !== $post_type ) {
			return $settings;
		}

		$primary = (int) get_post_meta( $post_id, '_yoast_wpseo_primary_category', true );
		if ( ! $primary ) {
			$primary = (int) get_post_meta( $post_id, 'rank_math_primary_category', true );
		}

		$term = $primary ? get_term( $primary, 'category' ) : null;
		if ( $term && ! is_wp_error( $term ) ) {
			$settings['taxonomy'] = 'category';
			$settings['term']     = $term->slug;
		}

		return $settings;
	},
	10,
	3
);

Um segundo filtro, block_core_breadcrumbs_items, permite alterar a lista final de pares label e url antes da renderização. A marcação do bloco já cobre o básico de acessibilidade: um nav com aria-label, um ol e o último elemento como span com aria-current="page". O bloco não imprime JSON-LD. O BreadcrumbList continua a vir do plugin SEO ou de uma função como a apresentada acima, e ambos devem usar o mesmo termo que entrega ao bloco através do filtro.

#Como tornar o breadcrumb de categorias acessível

Use <nav aria-label="..."> com um nome traduzido e marque o último elemento com aria-current="page". Os separadores visíveis (/, ») devem ficar em aria-hidden="true", para que os leitores de ecrã não leiam o símbolo entre cada link. Uma lista ordenada (ol e li) comunica a ordem e o número de passos melhor do que uma cadeia de links em linha. Não dependa só da cor para indicar o elemento atual.

#Como gerir breadcrumbs de categorias com Polylang e WPML

Os IDs dos termos dependem do idioma. Um caminho construído num idioma e mostrado noutro apresenta as etiquetas erradas. Resolva primeiro o ID do termo traduzido através da API do plugin e só depois chame get_ancestors(). Os permalinks seguem a estrutura de URL de cada idioma: get_term_link() respeita-a, um caminho escrito à mão não. A chave de cache do breadcrumb tem de incluir o idioma, e convém confirmar que o meta da categoria principal do Yoast ou do Rank Math aponta, depois da tradução, para um termo do mesmo idioma.

#Como otimizar performance de consultas de categorias

#Como fazer cache das categorias

Para sites com muito tráfego, implemente cache:

/**
 * Obtém hierarquia com cache transient
 *
 * @param int $post_id ID do post
 * @param int $cache_time Tempo de cache em segundos (padrão: 1 hora)
 * @return string HTML da hierarquia
 */
function wppoland_get_cached_category_hierarchy( $post_id = null, $cache_time = 3600 ) {
    if ( ! $post_id ) {
        $post_id = get_the_ID();
    }

    // Gerar chave de cache única
    $cache_key = 'cat_hierarchy_' . $post_id . '_' . get_current_blog_id();

    // Tentar obter do cache
    $cached = get_transient( $cache_key );

    if ( false !== $cached ) {
        return $cached;
    }

    // Gerar hierarquia
    $hierarchy = wppoland_get_full_category_trail( $post_id );

    // Salvar no cache
    set_transient( $cache_key, $hierarchy, $cache_time );

    return $hierarchy;
}

// Uso - substitua a chamada original
$hierarchy = wppoland_get_cached_category_hierarchy();

#Como evitar consultas excessivas a categorias

Quando precisar de múltiplas categorias, use uma única consulta:

/**
 * Otimizado: Obtém hierarquias para múltiplos posts
 * Evita N+1 queries
 *
 * @param array $post_ids Array de IDs de posts
 * @return array Array com post_id => hierarquia HTML
 */
function wppoland_get_multiple_category_hierarchies( $post_ids ) {
    if ( empty( $post_ids ) ) {
        return array();
    }

    // Obter todas as categorias de uma vez
    $all_categories = get_the_category( $post_ids );

    // Organizar por post
    $categories_by_post = array();
    foreach ( $all_categories as $cat ) {
        if ( ! isset( $categories_by_post[ $cat->post_id ] ) ) {
            $categories_by_post[ $cat->post_id ] = array();
        }
        $categories_by_post[ $cat->post_id ][] = $cat;
    }

    // Gerar hierarquias
    $hierarchies = array();
    foreach ( $post_ids as $post_id ) {
        if ( isset( $categories_by_post[ $post_id ] ) ) {
            $categories = $categories_by_post[ $post_id ];
            $category = $categories[0];

            // Gerar hierarquia (código simplificado)
            $trail = array();
            while ( $category->parent ) {
                $category = get_category( $category->parent );
                array_unshift( $trail, $category );
            }
            array_unshift( $trail, get_category( $categories[0]->term_id ) );

            // Construir HTML
            $html = '';
            foreach ( $trail as $cat ) {
                $html .= '<a href="' . esc_url( get_category_link( $cat->term_id ) ) . '">';
                $html .= esc_html( $cat->name ) . '</a> / ';
            }

            $hierarchies[ $post_id ] = rtrim( $html, ' / ' );
        }
    }

    return $hierarchies;
}

#Como criar breadcrumbs para páginas e categorias de produtos WooCommerce

Hierarquias de páginas (post_parent), categorias de loja do WooCommerce e tipos de conteúdo de documentação costumam precisar de caminhos próprios. Não misture no mesmo breadcrumb o pai do post e o pai da categoria, a menos que a arquitetura de informação o preveja. Um erro frequente em lojas: os breadcrumbs do tema leem category, enquanto os produtos vivem em product_cat. O caminho visível mostra secções do blogue, o schema mostra categorias de produto, e a Search Console assinala breadcrumbs inconsistentes. Uma taxonomia por tipo de conteúdo, um construtor de caminho, um bloco de schema.

#Como testar breadcrumbs de categorias antes de publicar

  • Post sem categoria: a função devolve uma string vazia ou false, sem avisos de PHP.
  • Só categoria de topo: sem link para o pai, mas com um BreadcrumbList válido com a página inicial e o termo.
  • Hierarquia alterada depois da publicação: limpe a cache do caminho antigo e do novo.
  • ID de categoria principal apagado no meta do Yoast ou do Rank Math: recurso a get_the_category().
  • Nome de categoria com aspas ou «&»: sempre esc_html().
  • Importação de CSV ou de um CMS antigo: o ID do pai pode apontar para um termo apagado, por isso verifique o resultado de get_term() e interrompa o caminho.
  • Tema de blocos: o shortcode ou a parte de template tem de ver o get_the_ID() correto no contexto do bloco.

Se o tema tiver CI, escreva estes casos como testes PHPUnit ou de integração. Pelo menos uma vez à mão: um post com duas categorias, categoria principal definida, um pai três níveis acima e a object cache vazia.

#Checklist para implementar a hierarquia de categorias

#Implementação básica

  • Adicionar função wppoland_get_category_hierarchy() ao functions.php
  • Inserir chamada no template onde deseja exibir
  • Adicionar CSS para estilização

#Implementação avançada

  • Usar wppoland_get_full_category_trail() para hierarquias completas
  • Adicionar markup Schema.org para SEO
  • Implementar cache com transients

#Otimização

  • Para sites com muito tráfego, usar cache agressivo
  • Em loops, usar consultas otimizadas
  • Minimizar chamadas get_category() em loops

#Boas práticas

  • Sempre usar esc_url() e esc_html() para segurança
  • Verificar se categorias existem antes de usar
  • Testar com posts em múltiplos níveis de hierarquia
  • Validar markup HTML

Com estas técnicas, pode criar sistemas de navegação por categorias robustos e otimizados para qualquer projeto WordPress.

Navegação por categorias hierárquicas parece resolvida até surgir o nível seguinte da árvore. Se quiser esta parte do tema construída para aguentar hierarquias reais, veja o nosso desenvolvimento de temas WordPress.

Próximo passo

Transforme o artigo numa implementação real

Este bloco reforça a ligação interna e conduz o leitor para o passo seguinte mais útil dentro da arquitetura do site.

Quer implementar isto no seu site?

Se quer transformar o artigo em melhorias concretas, redesign ou num plano de implementação, posso fechar o escopo e executar.

Explorar outros serviços WordPress e base de conhecimento

Reforce o seu negócio com suporte técnico profissional em áreas-chave do ecossistema WordPress.

Perguntas frequentes

Respostas práticas para aplicar o tema na execução real.

Porque é que get_the_category() não chega para breadcrumbs#
Devolve apenas os termos atribuídos ao post, ordenados por nome e não por hierarquia. Pais e avós não vêm ordenados ao lado. Para o caminho completo precisa de parent, get_term_parents_list() ou get_ancestors().
Que categoria usar quando o post tem várias#
Leia primeiro a categoria principal do Yoast SEO (_yoast_wpseo_primary_category) ou do Rank Math (rank_math_primary_category). Sem plugin SEO, escolha a categoria com mais antepassados e documente a regra para a redação.
O BreadcrumbList tem de incluir o próprio post#
Não. A Google exige pelo menos dois ListItem e, no último elemento, a propriedade item é opcional: sem ela, a Google usa o URL da própria página. O JSON-LD deve corresponder ao caminho visível.
Como mostrar o caminho de categorias num tema de blocos#
Desde o WordPress 7.0 existe o bloco core/breadcrumbs. Por omissão usa o primeiro termo por ordem alfabética, por isso a categoria principal é passada através do filtro block_core_breadcrumbs_post_type_settings.

Precisa de FAQ adaptado ao setor e mercado? Crio uma versão alinhada com os seus objetivos de negócio.

Fale connosco

Artigos Relacionados