La función estándar de WordPress the_category() es genial, pero tiene un defecto: siempre genera enlaces HTML (<a href="...">...</a>) a la página de archivo. ¿Qué pasa si estás construyendo un diseño personalizado (como una tarjeta de portfolio o un slider) donde la categoría debe ser texto plano, no un elemento clicable?
Descubre más sobre desarrollo profesional WordPress en WPPoland. La solución es usar get_the_category(), que devuelve un array de objetos en lugar de HTML listo.
Obtener la categoría de una entrada sin enlace en PHP
Aquí tienes un fragmento listo para usar que puedes pegar en tu single.php o content.php:
<?php
// Obtener todas las categorías asignadas a la entrada actual
$categories = get_the_category();
if ( ! empty( $categories ) ) {
// Mostrar el nombre de la primera categoría encontrada
echo esc_html( $categories[0]->name );
}
?>Cómo mostrar varias categorías separadas por comas
Si tu entrada tiene múltiples categorías y quieres listarlas como texto separado por comas:
<?php
$categories = get_the_category();
$output = array();
if ( ! empty( $categories ) ) {
foreach ( $categories as $category ) {
// Añadir nombre al array
$output[] = esc_html( $category->name );
}
// Unir el array en una cadena con separador
echo implode( ', ', $output );
}
?>Funciones de WordPress para obtener el nombre de categoría
WordPress trae varias funciones que devuelven el nombre de una categoría sin envolverlo en un enlace. Cada una encaja en un contexto distinto:
get_the_category(): dentro del loop, devuelve un array de objetosWP_Termde la entrada actual.$categories[0]->namees el acceso más directo al primer nombre.get_cat_name( $cat_id ): recibe un ID y devuelve solo el nombre como cadena. Útil cuando ya conoces el ID, por ejemplo guardado en un campo de opciones del tema.single_cat_title( '', false ): en páginas de archivo de categoría devuelve el título del archivo actual. El segundo parámetro enfalsehace que la función devuelva el valor en lugar de imprimirlo.get_the_terms()frente aget_the_term_list(): la segunda genera HTML con enlaces ya montados, la primera devuelve objetos crudos. Para texto plano y control total del marcado quieresget_the_terms().
<?php
// 1. Dentro del loop: primera categoría de la entrada actual
$categories = get_the_category();
if ( ! empty( $categories ) ) {
echo esc_html( $categories[0]->name );
}
// 2. Con un ID conocido, dentro o fuera del loop
echo esc_html( get_cat_name( 12 ) );
// 3. En category.php o archive.php: título del archivo actual
if ( is_category() ) {
echo esc_html( single_cat_title( '', false ) );
}
// 4. get_the_terms(): objetos crudos, sin HTML generado
$terms = get_the_terms( get_the_ID(), 'category' );
if ( $terms && ! is_wp_error( $terms ) ) {
echo esc_html( $terms[0]->name );
}
?>La regla práctica: si la función termina en _list o empieza por the_, imprime o devuelve HTML listo. Si empieza por get_the_ y devuelve objetos, tienes el control.
Obtener los nombres de categoría como array con wp_get_post_terms
wp_get_post_terms() pasa su tercer argumento a wp_get_object_terms(), así que acepta las opciones de WP_Term_Query que get_the_terms() no admite. Con 'fields' => 'names' devuelve un array de cadenas y el bucle desaparece:
<?php
// Solo los nombres, primero las categorías más usadas
$nombres = wp_get_post_terms(
get_the_ID(),
'category',
array(
'fields' => 'names',
'orderby' => 'count',
'order' => 'DESC',
)
);
if ( ! is_wp_error( $nombres ) && ! empty( $nombres ) ) {
echo esc_html( implode( ', ', $nombres ) );
}
?>El precio es la caché. get_the_terms() lee primero la caché de relaciones de cada entrada, y el WP_Query principal la rellena para todas las entradas de la página porque update_post_term_cache vale true por defecto. wp_get_post_terms() se salta esa caché y siempre llama a wp_get_object_terms(), de modo que en un archivo con veinte tarjetas lanza veinte consultas de términos para datos que WordPress ya tenía cargados. Dentro del loop, wp_list_pluck( get_the_category(), 'name' ) da el mismo array de nombres desde la caché. Reserva wp_get_post_terms() para los sitios donde necesitas sus argumentos, como ordenar por count en una barra lateral o un callback REST que trabaja con una sola entrada.
Cómo ordenar y excluir categorías de una entrada
Cuando una entrada tiene varias categorías, WordPress las devuelve ordenadas por nombre de forma predeterminada, pero a menudo quieres otro orden o necesitas ocultar una categoría interna (por ejemplo una que solo usas para marcar entradas destacadas). Como get_the_category() devuelve un array normal de PHP, puedes filtrarlo y reordenarlo con las funciones estándar:
<?php
$categories = get_the_category();
if ( ! empty( $categories ) ) {
// Excluir la categoría "destacados" por slug
$categories = array_filter( $categories, function( $cat ) {
return 'destacados' !== $cat->slug;
} );
// Ordenar por número de entradas, de mayor a menor
usort( $categories, function( $a, $b ) {
return $b->count - $a->count;
} );
$names = array_map( function( $cat ) {
return esc_html( $cat->name );
}, $categories );
echo implode( ', ', $names );
}
?>El mismo patrón sirve para excluir por term_id, limitar la lista con array_slice( $categories, 0, 2 ) o poner una categoría concreta siempre en primer lugar.
Qué devuelve get_the_category() además del nombre
Esta función te da acceso al objeto completo de categoría. Además del nombre (->name), puedes extraer:
->slug(útil para clases CSS, p. ej.,<span class="cat-<?php echo $cat->slug; ?>">)->term_id(ID de la categoría)->description(descripción de la categoría)->count(número de entradas en esta categoría)
Qué hace get_the_category dentro del núcleo de WordPress
En el código fuente de wordpress-develop, get_the_category() es un envoltorio fino. Llama a get_the_terms( $post_id, 'category' ), convierte un resultado false o WP_Error en un array vacío, lo reindexa con array_values(), pasa cada término por la función privada _make_cat_compat() y devuelve el resultado a través del filtro get_the_categories. De esas pocas líneas salen tres consecuencias prácticas.
Las propiedades heredadas solo existen en la salida de esta función. _make_cat_compat() copia los campos modernos a nombres antiguos: cat_ID, cat_name, category_nicename, category_count, category_description y category_parent. Los objetos de get_the_terms() no las reciben. Una plantilla que lee $cat->cat_name funciona hoy y deja de mostrar nada el día que alguien cambia la llamada por get_the_terms() para admitir una taxonomía personalizada. Lee name, slug y term_id, que comparten ambas funciones.
El orden es alfabético, no editorial. get_the_terms() consulta primero la caché de relaciones de términos de la entrada y, si no hay datos, llama a wp_get_object_terms(), que ejecuta un WP_Term_Query cuyo orderby predeterminado es name. Por eso $categories[0] es la primera categoría por orden alfabético, salvo que un filtro reordene el array. Nunca es la categoría principal elegida en un plugin SEO.
Los plugins pueden reescribir el array. Cualquier función enganchada a get_the_categories (con el argumento $post_id desde WordPress 4.4) o a get_the_terms puede añadir, quitar o reordenar términos antes de que tu plantilla los vea. Si una etiqueta muestra una categoría que el editor nunca asignó, revisa las funciones enganchadas a esos dos hooks antes de depurar la plantilla.
Cómo mostrar la categoría como etiqueta con clase CSS
Un caso de uso común es estilizar etiquetas en tarjetas de blog.
// Dentro del loop de WordPress
$cats = get_the_category();
$first_cat = !empty($cats) ? $cats[0] : null;
if ($first_cat) : ?>
<span class="badge badge-<?php echo esc_attr($first_cat->slug); ?>">
<?php echo esc_html($first_cat->name); ?>
</span>
<?php endif; ?>De esta forma, si tienes una categoría “Noticias”, obtendrás la clase .badge-noticias, que puedes colorear fácilmente en CSS. Este nivel de control es algo que the_category() simplemente no ofrece.
Obtener la categoría principal de Yoast o Rank Math
Cuando una entrada tiene múltiples categorías, es común querer mostrar solo la “principal”:
function wppoland_get_primary_category_name() {
$post_id = get_the_ID();
// Intentar obtener categoría primaria de Yoast
if ( class_exists( 'WPSEO_Primary_Term' ) ) {
$primary = new WPSEO_Primary_Term( 'category', $post_id );
$term_id = $primary->get_primary_term();
if ( $term_id ) {
$term = get_term( $term_id );
if ( ! is_wp_error( $term ) ) {
return esc_html( $term->name );
}
}
}
// Intentar obtener de RankMath
$rankmath_primary = get_post_meta( $post_id, 'rank_math_primary_category', true );
if ( $rankmath_primary ) {
$term = get_term( $rankmath_primary );
if ( ! is_wp_error( $term ) ) {
return esc_html( $term->name );
}
}
// Fallback: primera categoría
$cats = get_the_category( $post_id );
return ! empty( $cats ) ? esc_html( $cats[0]->name ) : '';
}CSS para etiquetas de categoría en WordPress
CSS para badges de categoría elegantes:
.badge {
display: inline-block;
padding: 0.25rem 0.75rem;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
border-radius: 9999px;
background: #e5e7eb;
color: #374151;
}
/* Colores por categoría */
.badge-noticias {
background: #dbeafe;
color: #1e40af;
}
.badge-tutorial {
background: #d1fae5;
color: #065f46;
}
.badge-opinion {
background: #fef3c7;
color: #92400e;
}
/* Hover sutil */
.badge:hover {
filter: brightness(0.95);
cursor: default;
}Plantilla de tarjeta de blog con la categoría como insignia
Un ejemplo completo de tarjeta de blog con categoría como insignia:
<?php while ( have_posts() ) : the_post(); ?>
<article class="blog-card">
<?php if ( has_post_thumbnail() ) : ?>
<div class="card-image">
<?php the_post_thumbnail( 'medium_large' ); ?>
<?php
$cats = get_the_category();
if ( ! empty( $cats ) ) :
$primary_cat = $cats[0];
?>
<span class="card-badge badge-<?php echo esc_attr( $primary_cat->slug ); ?>">
<?php echo esc_html( $primary_cat->name ); ?>
</span>
<?php endif; ?>
</div>
<?php endif; ?>
<div class="card-content">
<h2 class="card-title">
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
</h2>
<div class="card-meta">
<time datetime="<?php echo get_the_date('c'); ?>">
<?php echo get_the_date(); ?>
</time>
<?php
// Mostrar todas las categorías como texto
$all_cats = get_the_category();
$cat_names = array_map( function( $cat ) {
return esc_html( $cat->name );
}, $all_cats );
echo '<span class="categories">' . implode( ' / ', $cat_names ) . '</span>';
?>
</div>
<p class="card-excerpt"><?php echo wp_trim_words( get_the_excerpt(), 20 ); ?></p>
</div>
</article>
<?php endwhile; ?>Nombre de un término de taxonomía personalizada sin enlace
El mismo principio se aplica a taxonomías personalizadas con get_the_terms():
$genres = get_the_terms( get_the_ID(), 'genre' );
if ( ! empty( $genres ) && ! is_wp_error( $genres ) ) {
$genre_names = array();
foreach ( $genres as $genre ) {
$genre_names[] = esc_html( $genre->name );
}
echo implode( ', ', $genre_names );
}Cómo obtener términos de cualquier taxonomía como texto
Crea una función helper que funcione con cualquier taxonomía:
/**
* Obtener nombres de términos como texto plano
*
* @param string $taxonomy Nombre de la taxonomía
* @param string $separator Separador entre nombres
* @param int|null $post_id ID de la entrada
* @return string Lista de nombres separados
*/
function wppoland_get_term_names( $taxonomy = 'category', $separator = ', ', $post_id = null ) {
$post_id = $post_id ?: get_the_ID();
if ( $taxonomy === 'category' ) {
$terms = get_the_category( $post_id );
} else {
$terms = get_the_terms( $post_id, $taxonomy );
}
if ( empty( $terms ) || is_wp_error( $terms ) ) {
return '';
}
$names = array_map( function( $term ) {
return esc_html( $term->name );
}, $terms );
return implode( $separator, $names );
}
// Uso:
echo wppoland_get_term_names( 'category' ); // "Noticias, WordPress"
echo wppoland_get_term_names( 'post_tag', ' | ' ); // "PHP | CSS | HTML"
echo wppoland_get_term_names( 'genre', ' / ', 123 ); // "Acción / Drama"Cómo escapar el nombre de categoría con WPML o Polylang
Antes de guardar un término, default-filters.php pasa el nombre por sanitize_text_field(), wp_filter_kses() y, con prioridad 30, por _wp_specialchars() en el hook pre_term_name. Las etiquetas HTML se eliminan al guardar, y un nombre como “Diseño & UX” queda en la base de datos como Diseño & UX.
Dentro de HTML eso no causa problemas. esc_html() llama a _wp_specialchars() con la doble codificación desactivada, así que un & existente se queda como & y el navegador muestra un ”&” normal. El & literal aparece fuera de HTML: en un JSON-LD construido con wp_json_encode(), en un campo REST que JavaScript escribe con textContent, en el asunto de un correo en texto plano o en una exportación CSV. Una llamada a htmlspecialchars() de PHP, que codifica dos veces por defecto, produce el &amp; visible. En esos contextos decodifica primero y aplica después el escape del formato de destino:
<?php
$categories = get_the_category();
if ( ! empty( $categories ) ) {
// Convertir el "&" almacenado en "&" para un contexto que no es HTML
$nombre = wp_specialchars_decode( $categories[0]->name, ENT_QUOTES );
$schema = array( 'articleSection' => $nombre );
echo wp_json_encode( $schema );
}
?>Sobre la internacionalización: los nombres de categoría son contenido, no cadenas de código, así que no pasan por __() ni por los archivos .po del tema. Si el sitio es multilingüe con WPML o Polylang, get_the_category() ya devuelve el término traducido del idioma activo, no tienes que hacer nada extra. Lo que sí conviene traducir con esc_html__() son las etiquetas fijas alrededor, como el texto “Publicado en:” que precede a la lista.
Cómo mostrar la categoría en el editor de bloques con un shortcode
En temas de bloques y patrones no puedes soltar PHP directamente en la plantilla. Un shortcode mínimo hace de puente: registra una función que devuelva (no imprima) el nombre plano y podrás usarla en el bloque Shortcode, dentro de patrones o en widgets clásicos:
<?php
// functions.php del tema hijo o un plugin propio
add_shortcode( 'categoria_texto', function() {
$categories = get_the_category();
if ( empty( $categories ) ) {
return '';
}
// return, nunca echo: un shortcode debe devolver su salida
return esc_html( $categories[0]->name );
} );
?>Después basta con insertar [categoria_texto] donde lo necesites. Como el shortcode lee la entrada global, funciona en plantillas de entrada individual y dentro del loop de un bloque Query Loop.
El bloque Términos de la entrada (Post Terms) del núcleo no sirve como alternativa. Su block.json define solo los atributos term, separator, prefix y suffix, y su callback de renderizado en PHP construye la salida con get_the_term_list(), así que cada término que imprime es un enlace. No existe ningún ajuste que quite los enlaces. Un CSS como pointer-events: none solo oculta el clic: el marcado sigue siendo un ancla y los lectores de pantalla siguen anunciando un enlace.
Por qué no usar strip_tags sobre the_category
Este atajo sigue apareciendo en temas antiguos y en respuestas de foros:
<?php
// Antipatrón: no lo hagas.
echo strip_tags( get_the_category_list( ', ' ) );
?>Problemas concretos:
- Trabajo inútil. WordPress construye el HTML completo con enlaces,
rely URL para que tú tires las etiquetas. - Separadores frágiles. Si el tema o un filtro sobre
the_categoryañade envoltorios,strip_tags()puede pegar nombres sin espacio. - No escapa. Después de
strip_tags()sigues necesitandoesc_html(), y mucha gente lo olvida. - Pierdes los datos. Sin el objeto no tienes
slugniterm_idpara clases CSS o schema, así que acabas volviendo aget_the_category().
Reserva strip_tags() para contenido rico de origen desconocido, no para quitar anclas que tú mismo has pedido a la API.
Cómo cachear el nombre de categoría en WordPress
get_the_category() y get_the_terms() leen la relación entre entrada y términos y los objetos WP_Term. Con una caché de objetos persistente (Redis o Memcached mediante drop-in), términos y relaciones entran en caché sin código adicional. En la práctica:
- No crees un transient por tarjeta solo para el nombre de la categoría en el loop principal: el coste de
get_the_category()es bajo frente al resto de la plantilla. - Si cacheas fragmentos HTML completos (tarjetas en transient o en el edge), el nombre va dentro del fragmento, y el fragmento se invalida al guardar la entrada (
save_post) o al editar el término (edited_term). - Si tu índice propio (Elasticsearch, una tabla personalizada) guarda solo el
term_id, resuelve elnameal renderizar conget_term(). Así, renombrar una categoría actualiza el archivo sin reconstruir el índice.
<?php
add_action(
'save_post_post',
function ( $post_id ) {
delete_transient( 'wppoland_card_html_' . (int) $post_id );
}
);
?>Cuándo usar the_category con enlaces
Hay pantallas en las que el marcado con enlaces es justo lo que se busca: la línea clásica “Publicado en Noticias, Eventos” bajo una entrada individual, un widget de metadatos donde cada categoría debe ser clicable o un tema minimalista sin tarjetas en el que los archivos de categoría son la navegación secundaria. Ahí llama a the_category( ', ' ) o usa el bloque Post Terms y no reconstruyas el marcado a mano. Si más adelante el diseño pide un enlace alrededor de una sola etiqueta, envuelve el nombre escapado en <a href="<?php echo esc_url( get_category_link( $term->term_id ) ); ?>"> en lugar de volver a the_category(). El error es mezclar los dos modos en un mismo componente sin una regla, así que deja la regla escrita en el tema: las etiquetas de tarjeta son texto, las líneas de metadatos son enlaces.
Por qué get_the_category() devuelve categorías equivocadas
Tres fallos que aparecen una y otra vez en temas heredados:
- Intentar limpiar la salida de
the_category(). Esta función imprime el marcado con enlaces directamente y no tiene modo de texto plano. Capturar su salida conob_start()y pasarla porstrip_tags()funciona, pero es frágil y lento. La solución correcta es no usarla:get_the_category()te da los datos crudos desde el principio. - Olvidar
wp_reset_postdata()tras un loop personalizado.get_the_category()sin argumento lee la entrada global. Si acabas de recorrer unWP_Querysecundario y no restauras el estado, la siguiente llamada devuelve las categorías de la entrada equivocada:
<?php
$destacados = new WP_Query( array( 'posts_per_page' => 3 ) );
while ( $destacados->have_posts() ) {
$destacados->the_post();
$cats = get_the_category(); // correcto: lee la entrada del loop secundario
}
wp_reset_postdata(); // sin esta línea, get_the_category() posterior apunta mal
?>- No comprobar
is_wp_error()conget_the_terms(). Si la taxonomía no está registrada (un plugin desactivado, un typo en el nombre), la función devuelve un objetoWP_Errory elforeachposterior lanza un aviso. La comprobación dobleif ( $terms && ! is_wp_error( $terms ) )cubre los dos casos: sin términos y taxonomía inexistente.
Resumen
get_the_category() es la herramienta correcta cuando necesitas nombres de categoría como texto plano sin enlaces. Los puntos clave son:
the_category()siempre genera enlaces HTML, no se puede evitarget_the_category()devuelve objetos con acceso completo a metadatos- Siempre escapa la salida con
esc_html()por seguridad - Usa
implode()para listas separadas elegantemente - El mismo patrón funciona con taxonomías personalizadas vía
get_the_terms() - Crea funciones helper reutilizables para mantener tu código DRY







