Os temas WordPress usam body_class() para adicionar classes CSS úteis à tag <body>. No entanto, por padrão, não indica claramente se uma página é filha de uma seção pai específica.
Se você tem uma estrutura como:
/services//services/web-design//services/seo/
Você pode querer estilizar todas as páginas em “Services” com um fundo azul. As classes padrão como page-id-123 são irritantes de manter.
O problema: Targeting CSS limitado
A função padrão body_class() do WordPress adiciona classes como:
page-id-123(numérico, difícil de lembrar)page-template-default(genérico)page(muito amplo)
Mas não lhe diz:
- A que seção a página pertence
- A hierarquia da página (relação pai/filho)
- O slug da página (identificador legível)
Isso torna o targeting CSS difícil. Você acaba com código como:
/* Mau: Difícil de manter */
.page-id-123,
.page-id-124,
.page-id-125 {
background: blue;
}
Cada vez que você adiciona uma nova página, precisa atualizar seu CSS. Isso não escala.
A solução: Adicionar slugs pais às classes do body
Ao adicionar slugs da página pai à classe do body, você pode direcionar seções inteiras com uma única regra CSS. Isso torna sua folha de estilos sustentável e escalável.
O snippet completo
Adicione esta versão aprimorada ao seu functions.php:
/**
* Add page slugs and parent slugs to body classes
*
* Adds:
* - Current page slug
* - Parent page slug (if exists)
* - Grandparent page slug (if exists)
* - All ancestor slugs
*
* @param array $classes Existing body classes
* @return array Modified classes array
*/
function wppoland_add_slug_body_class( $classes ) {
global $post;
if ( ! isset( $post ) || ! is_page() ) {
return $classes;
}
// 1. Add current page slug
$classes[] = 'page-slug-' . sanitize_html_class( $post->post_name );
// 2. Add parent page slug (if exists)
if ( $post->post_parent ) {
$parent = get_post( $post->post_parent );
if ( $parent ) {
$classes[] = 'parent-' . sanitize_html_class( $parent->post_name );
// 3. Add grandparent slug (if exists)
if ( $parent->post_parent ) {
$grandparent = get_post( $parent->post_parent );
if ( $grandparent ) {
$classes[] = 'grandparent-' . sanitize_html_class( $grandparent->post_name );
}
}
// 4. Add all ancestor slugs (recursive)
$ancestors = get_post_ancestors( $post->ID );
foreach ( $ancestors as $ancestor_id ) {
$ancestor = get_post( $ancestor_id );
if ( $ancestor ) {
$classes[] = 'ancestor-' . sanitize_html_class( $ancestor->post_name );
}
}
}
}
// 5. Add template hierarchy classes
$template = get_page_template_slug( $post->ID );
if ( $template ) {
$template_slug = str_replace( '.php', '', basename( $template ) );
$classes[] = 'template-' . sanitize_html_class( $template_slug );
}
return $classes;
}
add_filter( 'body_class', 'wppoland_add_slug_body_class' );
Resultado: Classes do body aprimoradas
Agora sua tag <body> incluirá:
<body class="page page-id-123 page-slug-web-design parent-services ancestor-services ...">
Classes adicionadas:
page-slug-web-design- Slug da página atualparent-services- Slug do pai diretograndparent-company- Slug do avô (se existir)ancestor-services- Todos os slugs ancestraistemplate-custom- Nome do arquivo template (se personalizado)
Exemplos de uso
Exemplo 1: Estilizar todas as páginas de serviços
/* Fundo azul para TODAS as páginas de serviços */
body.parent-services {
background-color: #eef;
}
/* Estilo específico para cabeçalho de serviços */
body.parent-services .site-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
/* Rodapé da seção de serviços */
body.parent-services .site-footer {
border-top: 3px solid #667eea;
}
Exemplo 2: Layouts diferentes por seção
/* Layout largura total para documentação */
body.parent-documentation .content-area {
max-width: 100%;
padding: 0;
}
/* Layout barra lateral para blog */
body.parent-blog .content-area {
max-width: 1200px;
display: grid;
grid-template-columns: 2fr 1fr;
gap: 2rem;
}
Técnicas avançadas e extensões
Classes condicionais baseadas em funções de usuário
Uma extensão particularmente útil é adicionar classes baseadas na função do usuário. Isso permite definir estilos diferentes para administradores, editores ou usuários conectados:
/**
* Adiciona classes específicas de funções de usuário
*
* @param array $classes Classes existentes do body
* @return array Classes modificadas
*/
function wppoland_add_user_role_body_class( $classes ) {
if ( is_user_logged_in() ) {
$current_user = wp_get_current_user();
// Usuário conectado
$classes[] = 'logged-in';
// Adicionar função do usuário
if ( ! empty( $current_user->roles ) ) {
foreach ( $current_user->roles as $role ) {
$classes[] = 'user-role-' . sanitize_html_class( $role );
}
}
// Nome de usuário para estilos personalizados
$classes[] = 'user-id-' . get_current_user_id();
} else {
$classes[] = 'visitor';
}
return $classes;
}
add_filter( 'body_class', 'wppoland_add_user_role_body_class' );
Exemplo de uso:
/* Exibir informações de debug específicas para admin */
body.user-role-administrator .debug-panel {
display: block;
position: fixed;
bottom: 0;
left: 0;
background: rgba(255, 0, 0, 0.8);
color: white;
padding: 10px;
font-size: 12px;
z-index: 9999;
}
/* Saudar usuários conectados */
body.logged-in .welcome-message::before {
content: 'Bem-vindo de volta, ' attr(data-username) '!';
}
Classes para Custom Post Types e Taxonomias
Ao trabalhar com Custom Post Types, geralmente é útil adicionar o próprio post type como classe para permitir estilização específica:
/**
* Adiciona classes específicas de CPT e Taxonomias
*
* @param array $classes Classes existentes do body
* @return array Classes modificadas
*/
function wppoland_add_cpt_taxonomy_body_class( $classes ) {
// Detecção de Custom Post Type
if ( is_singular() ) {
$post_type = get_post_type();
if ( $post_type !== 'post' && $post_type !== 'page' ) {
$classes[] = 'single-cpt-' . sanitize_html_class( $post_type );
$classes[] = 'cpt-' . sanitize_html_class( $post_type );
}
}
// Classes de Taxonomia Customizada
if ( is_tax() || is_category() || is_tag() ) {
$term = get_queried_object();
if ( $term ) {
$classes[] = 'taxonomy-' . sanitize_html_class( $term->taxonomy );
$classes[] = 'term-' . sanitize_html_class( $term->slug );
$classes[] = 'term-id-' . $term->term_id;
}
}
// Classes de arquivo para CPT
if ( is_post_type_archive() ) {
$post_type = get_query_var( 'post_type' );
if ( is_array( $post_type ) ) {
$post_type = reset( $post_type );
}
$classes[] = 'archive-cpt-' . sanitize_html_class( $post_type );
}
return $classes;
}
add_filter( 'body_class', 'wppoland_add_cpt_taxonomy_body_class' );
Classes específicas do WooCommerce
Para lojas WooCommerce, existem várias páginas específicas que requerem estilos diferentes. Aqui está uma função estendida para classes específicas do WooCommerce:
/**
* Adiciona classes específicas do WooCommerce
*
* @param array $classes Classes existentes do body
* @return array Classes modificadas
*/
function wppoland_add_woocommerce_body_class( $classes ) {
if ( ! function_exists( 'is_woocommerce' ) ) {
return $classes;
}
// WooCommerce ativado
$classes[] = 'woocommerce-active';
// Páginas de loja
if ( is_shop() ) {
$classes[] = 'woocommerce-shop';
// Categoria de produto
$product_cat = get_queried_object();
if ( $product_cat && ! is_wp_error( $product_cat ) ) {
$classes[] = 'product-category-' . sanitize_html_class( $product_cat->slug );
}
}
// Páginas de produto
if ( is_product() ) {
$classes[] = 'single-product';
// Categorias do produto atual
$product_cats = get_the_terms( get_the_ID(), 'product_cat' );
if ( $product_cats && ! is_wp_error( $product_cats ) ) {
foreach ( $product_cats as $cat ) {
$classes[] = 'has-product-cat-' . sanitize_html_class( $cat->slug );
}
}
}
// Carrinho
if ( is_cart() ) {
$classes[] = 'woocommerce-cart';
// Detectar carrinho vazio
if ( WC()->cart->is_empty() ) {
$classes[] = 'cart-empty';
} else {
$classes[] = 'cart-filled';
}
}
// Checkout
if ( is_checkout() ) {
$classes[] = 'woocommerce-checkout';
// Página de pagamento
if ( is_wc_endpoint_url( 'order-pay' ) ) {
$classes[] = 'order-payment';
}
}
// Conta do usuário
if ( is_account_page() ) {
$classes[] = 'woocommerce-account';
// Páginas específicas de conta
if ( is_wc_endpoint_url( 'orders' ) ) {
$classes[] = 'my-orders';
} elseif ( is_wc_endpoint_url( 'downloads' ) ) {
$classes[] = 'my-downloads';
} elseif ( is_wc_endpoint_url( 'edit-address' ) ) {
$classes[] = 'edit-address';
} elseif ( is_wc_endpoint_url( 'payment-methods' ) ) {
$classes[] = 'payment-methods';
}
}
return $classes;
}
add_filter( 'body_class', 'wppoland_add_woocommerce_body_class', 20 );
Exemplo de estilização WooCommerce:
/* Headers específicos por categoria de produto */
body.product-category-eletronica .product-header {
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
color: white;
}
body.product-category-roupas .product-header {
background: linear-gradient(135deg, #f5f5f5 0%, #e0e0e0 100%);
color: #333;
}
/* Call-to-action para carrinho vazio */
body.woocommerce-cart.cart-empty .cart-empty-content {
text-align: center;
padding: 60px 20px;
}
body.woocommerce-cart.cart-empty .return-to-shop {
margin-top: 30px;
}
body.woocommerce-cart.cart-empty .button {
background: #667eea;
color: white;
padding: 15px 30px;
border-radius: 8px;
font-size: 18px;
}
Considerações de desempenho e otimização
Cache de classes do body
Em temas complexos com muitos filtros de classes body, o desempenho pode sofrer. Aqui está uma versão otimizada que usa cache:
/**
* Versão otimizada com transients para melhor performance
*
* @param array $classes Classes existentes do body
* @return array Classes modificadas
*/
function wppoland_optimized_slug_body_class( $classes ) {
global $post;
if ( ! isset( $post ) || ! is_singular() ) {
return $classes;
}
// Chave de cache baseada no ID do post
$cache_key = 'wppoland_body_classes_' . $post->ID;
$cached_classes = get_transient( $cache_key );
// Se estiver em cache, usar valores em cache
if ( false !== $cached_classes && is_array( $cached_classes ) ) {
return array_merge( $classes, $cached_classes );
}
$additional_classes = array();
// Slug da página atual
$additional_classes[] = 'page-slug-' . sanitize_html_class( $post->post_name );
// Pais e ancestrais
$ancestors = get_post_ancestors( $post->ID );
foreach ( $ancestors as $ancestor_id ) {
$ancestor = get_post( $ancestor_id );
if ( $ancestor ) {
$additional_classes[] = 'ancestor-' . sanitize_html_class( $ancestor->post_name );
}
}
// Slug do pai direto
if ( $post->post_parent ) {
$parent = get_post( $post->post_parent );
if ( $parent ) {
$additional_classes[] = 'parent-' . sanitize_html_class( $parent->post_name );
}
}
// Armazenar em cache (1 hora)
set_transient( $cache_key, $additional_classes, HOUR_IN_SECONDS );
return array_merge( $classes, $additional_classes );
}
add_filter( 'body_class', 'wppoland_optimized_slug_body_class' );
Limpar cache quando posts são atualizados
Para garantir que as classes atualizadas sejam refletidas, limpe os transients quando um post for modificado:
/**
* Limpa o cache de classes body quando posts são atualizados
*
* @param int $post_id ID do post sendo limpo
*/
function wppoland_clear_body_class_cache( $post_id ) {
// Ignorar auto-saves e revisões
if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
return;
}
// Limpar cache para este post e seus descendentes
delete_transient( 'wppoland_body_classes_' . $post_id );
// Limpar cache para posts ancestrais
$ancestors = get_post_ancestors( $post_id );
foreach ( $ancestors as $ancestor_id ) {
delete_transient( 'wppoland_body_classes_' . $ancestor_id );
}
// Limpar cache para posts descendentes
$descendants = get_posts( array(
'post_type' => 'page',
'post_parent' => $post_id,
'fields' => 'ids',
'posts_per_page' => -1,
) );
foreach ( $descendants as $descendant_id ) {
delete_transient( 'wppoland_body_classes_' . $descendant_id );
}
}
add_action( 'save_post', 'wppoland_clear_body_class_cache' );
Dicas de implementação
Combinando todos os filtros
Para máxima flexibilidade, combine todos os filtros em um único MU-plugin ou no functions.php do tema:
/**
* Combina todos os filtros de classes body em um único arquivo
*/
// Slug e hierarquia de páginas
add_filter( 'body_class', 'wppoland_add_slug_body_class' );
// Funções de usuário
add_filter( 'body_class', 'wppoland_add_user_role_body_class' );
// CPT e Taxonomias
add_filter( 'body_class', 'wppoland_add_cpt_taxonomy_body_class' );
// WooCommerce (se ativo)
if ( function_exists( 'is_woocommerce' ) ) {
add_filter( 'body_class', 'wppoland_add_woocommerce_body_class', 20 );
}
Usando com temas de bloco (Full Site Editing)
Para temas de bloco WordPress, adicione ao functions.php do tema ou a um plugin de funcionalidades:
/**
* Suporte a classes body para temas de bloco
*
* @param array $classes Classes existentes
* @return array Classes modificadas
*/
function wppoland_block_theme_body_classes( $classes ) {
global $wp_query;
// Detectar se é um tema de bloco
if ( ! function_exists( 'wp_is_block_theme' ) || ! wp_is_block_theme() ) {
return $classes;
}
// Adicionar classes específicas de template
if ( is_singular() ) {
$template_type = get_template_part_type();
if ( $template_type ) {
$classes[] = 'template-' . sanitize_html_class( $template_type );
}
}
return $classes;
}
add_filter( 'body_class', 'wppoland_block_theme_body_classes', 10, 1 );
Solução de problemas
Classes não aparecem
Se as classes não estiverem aparecendo:
- Verifique se o filtro está conectado: Certifique-se de que
add_filterestá sendo executado - Verifique se é uma página: O snippet só funciona em páginas (
is_page()) - Verifique permissões de usuário: Algumas classes podem requerer privilégios de administrador
- Limpe caches: Cache de tema ou servidor pode estar retendo classes antigas
Conflitos com temas
Se houver conflitos com o tema:
-
Prioridade do filtro: Tente alterar a prioridade do filtro
add_filter( 'body_class', 'wppoland_add_slug_body_class', 20 ); -
Verificar tema pai: O filtro pode precisar ser adicionado ao tema pai, não ao filho
-
Override de classes: O tema pode estar substituindo classes completamente
Debug de classes
Para ver todas as classes sendo adicionadas:
/**
* Debug: Mostrar todas as classes do body
*/
function wppoland_debug_body_classes( $classes ) {
if ( current_user_can( 'administrator' ) ) {
error_log( 'Body classes: ' . print_r( $classes, true ) );
}
return $classes;
}
add_filter( 'body_class', 'wppoland_debug_body_classes', 999 );
Melhores práticas
- Use nomes semânticos: Prefira
parent-servicesaparent-123 - Limite o número de classes: Não adicione mais de 10-15 classes extras
- Use cache para sites grandes: Transients melhoram performance significativamente
- Documente suas classes: Mantenha um registro das classes personalizadas
- Teste em dispositivos móveis: Algumas classes podem afetar layouts responsivos
- Versione seu código: Use controle de versão para rastrear mudanças
Resumo
Adicionar slugs da página pai às classes do body é uma técnica simples mas poderosa que torna o targeting CSS escalável e sustentável. Em vez de manter listas de IDs de página, você pode direcionar seções inteiras com uma única classe.
Benefícios:
- ✅ Escalável: Funciona automaticamente para novas páginas
- ✅ Sustentável: Uma regra CSS para seções inteiras
- ✅ Semântico: Nomes de classe legíveis
- ✅ Flexível: Funciona com qualquer tema
- ✅ Performance: Suporte a cache para sites grandes
- ✅ Extensível: Adicione classes para CPTs, taxonomias, WooCommerce e muito mais
Atualizado: 29 de janeiro de 2026



