Extraer listas de posts de categorías en WordPress, Guía del desarrollador
ES

Extraer listas de posts de categorías en WordPress, Guía del desarrollador

Última verificación: 1 de julio de 2026
11 min de lectura
Tutorial
500+ proyectos WP
Desarrollador full-stack

#Introduccion a la recuperación de posts basada en categorías

Conoce más sobre el desarrollo WordPress profesional en WPPoland.

Una de las tareas más comunes en el desarrollo de WordPress es recuperar posts de categorías específicas. Ya sea que estes construyendo un diseño de homepage personalizado, creando una plantilla de archivo de categoría o mostrando contenido relacionado, entender como consultar posts por categoría de forma eficiente es esencial para cualquier desarrollador WordPress.

Esta guía completa cubre múltiples enfoques para extraer listas de posts de categorías, desde implementaciones simples hasta técnicas avanzadas de optimización. Al final, tendras un kit de herramientas completo para manejar consultas basadas en categorías en cualquier proyecto WordPress.

#Entendiendo las categorías de WordPress

Antes de profundizar en el código, es importante entender como WordPress maneja las categorías:

  • Las categorías son una taxonomía incorporada en WordPress
  • Cada post puede pertenecer a múltiples categorías
  • Las categorías pueden ser jerárquicas (relaciones padre/hijo)
  • Los datos de categoría se almacenan en las tablas wp_terms y wp_term_taxonomy
  • Las relaciones post-categoría se almacenan en wp_term_relationships

Entender esta estructura te ayuda a escribir consultas más eficientes y soluciónar problemas cuando surjan.

#Encontrar el ID de una categoría a partir de su slug o nombre

La mayoría de los argumentos de consulta aceptan tanto un slug como un ID numérico, pero los argumentos basados en ID (cat, category__in) son los más rápidos porque se saltan la búsqueda del término. Cuando solo conoces el slug, resuélvelo una vez y reutiliza el ID:

// From a slug
$term = get_category_by_slug('news');
$news_id = $term ? $term->term_id : 0;

// From a display name
$news_id = get_cat_ID('News'); // returns 0 if not found

// From any taxonomy (categories included)
$term = get_term_by('slug', 'news', 'category');

Cachea el ID resuelto en una constante o en una opción si lo dejas fijo en una plantilla; llamar a get_cat_ID() en cada petición añade una consulta que puedes evitar. En proyectos que hemos migrado desde alojamientos como SiteGround o Raiola Networks, este pequeño detalle es de los que más se repiten en temas heredados: decenas de get_cat_ID() dispersos por el functions.php.

#Método 1: WP_Query (El enfoque flexible)

WP_Query es la clase principal de WordPress para consultar posts. Ofrece máxima flexibilidad y es el enfoque recomendado para la mayoría de los casos de uso.

#Consulta básica por categoría

$args = array(
    'category_name' => 'noticias',
    'posts_per_page' => 10,
    'orderby' => 'date',
    'order' => 'DESC'
);

$query = new WP_Query($args);

if ($query->have_posts()) {
    while ($query->have_posts()) {
        $query->the_post();
        // Mostrar contenido del post
        ?>
        <article>
            <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
            <div class="entry-content">
                <?php the_excerpt(); ?>
            </div>
        </article>
        <?php
    }
    wp_reset_postdata();
}

#Consulta por ID de categoría

$args = array(
    'cat' => 5, // ID de categoria
    'posts_per_page' => 5
);

$query = new WP_Query($args);

#Multiples categorías

// Posts en CUALQUIERA de estas categorias (relacion OR)
$args = array(
    'category__in' => array(5, 10, 15),
    'posts_per_page' => 10
);

// Posts en TODAS estas categorias (relacion AND)
$args = array(
    'category__and' => array(5, 10),
    'posts_per_page' => 10
);

// Excluir categorias específicas
$args = array(
    'category__not_in' => array(3, 7),
    'posts_per_page' => 10
);

#Incluyendo categorías hijas

// Obtener posts de la categoria y todas sus hijas
$id_categoria_padre = 5;

$args = array(
    'cat' => $id_categoria_padre,
    'posts_per_page' => 20
);

// WP_Query incluye automáticamente categorias hijas cuando usas 'cat'

#Método 2: get_posts() (El enfoque simple)

Para casos de uso más simples, get_posts() proporciona una API más directa.

#Uso básico

$posts = get_posts(array(
    'category' => 5,
    'posts_per_page' => 10,
    'orderby' => 'date',
    'order' => 'DESC'
));

foreach ($posts as $post) {
    setup_postdata($post);
    ?>
    <article>
        <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
    </article>
    <?php
}
wp_reset_postdata();

#Con nombre de categoría

$posts = get_posts(array(
    'category_name' => 'tecnología',
    'numberposts' => 5
));

#Método 3: Shortcodes para editores de contenido

Crear un shortcode permite a los editores de contenido insertar listas de posts por categoría en cualquier lugar.

function shortcode_posts_categoria($atts) {
    $atts = shortcode_atts(array(
        'categoria' => '',
        'posts' => 5,
        'orderby' => 'date',
        'order' => 'DESC'
    ), $atts);

    $args = array(
        'category_name' => $atts['categoria'],
        'posts_per_page' => intval($atts['posts']),
        'orderby' => $atts['orderby'],
        'order' => $atts['order']
    );

    $query = new WP_Query($args);

    ob_start();

    if ($query->have_posts()) {
        echo '<div class="lista-posts-categoria">';
        while ($query->have_posts()) {
            $query->the_post();
            ?>
            <article class="post-categoria">
                <h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
                <p><?php the_excerpt(); ?></p>
            </article>
            <?php
        }
        echo '</div>';
    } else {
        echo '<p>No se encontraron posts en esta categoria.</p>';
    }

    wp_reset_postdata();

    return ob_get_clean();
}
add_shortcode('posts_categoria', 'shortcode_posts_categoria');

Uso: [posts_categoria categoría="noticias" posts="5"]

#Método 4: Modificar la consulta principal

Cuando quieras cambiar que posts aparecen en las páginas de archivo de categoría, usa la acción pre_get_posts.

function modificar_consultas_categoria($query) {
    // Solo modificar archivos de categoria en la consulta principal
    if ($query->is_category() && $query->is_main_query() && !is_admin()) {
        // Mostrar 20 posts por página en lugar del predeterminado
        $query->set('posts_per_page', 20);

        // Excluir posts de categoria específica en ciertas páginas de categoria
        $cat_actual = get_queried_object();
        if ($cat_actual->slug === 'destacados') {
            $query->set('category__not_in', array(10)); // Excluir categoria ID 10
        }
    }
}
add_action('pre_get_posts', 'modificar_consultas_categoria');

#Método 5: tax_query para un filtrado preciso y consciente de la taxonomía

Los atajos cat y category_name son cómodos, pero tax_query es el argumento al que recurres cuando los requisitos se vuelven específicos: combinar categorías con etiquetas, excluir términos hijos o consultar una taxonomía personalizada. Además expresa la lógica AND/OR de forma explícita, algo que los argumentos abreviados no pueden hacer.

$args = array(
    'posts_per_page' => 10,
    'tax_query' => array(
        'relation' => 'AND',
        array(
            'taxonomy' => 'category',
            'field'    => 'slug',
            'terms'    => array('news'),
        ),
        array(
            'taxonomy' => 'post_tag',
            'field'    => 'slug',
            'terms'    => array('featured'),
        ),
    ),
);

$query = new WP_Query($args);

La clave include_children es el detalle práctico que la mayoría pasa por alto. Por defecto, una tax_query sobre category arrastra todos los términos descendientes, lo que suele ser lo que quiere un archivo pero rara vez lo que quiere un bloque curado de la homepage:

'tax_query' => array(
    array(
        'taxonomy'         => 'category',
        'field'            => 'term_id',
        'terms'            => array(5),
        'include_children' => false, // only posts filed directly under term 5
    ),
),

Como tax_query funciona contra cualquier taxonomía, el mismo patrón recupera posts de un product_cat de WooCommerce, un portfolio_type o cualquier taxonomía que registre tu tema, sin necesidad de una función distinta por taxonomía. En tiendas WooCommerce en español es habitual reutilizar este patrón para listar productos de una categoría concreta sin duplicar código.

#Optimización de rendimiento

#1. Usar Transients para consultas costosas

function obtener_posts_categoria_con_cache($id_categoria, $cantidad = 5) {
    $clave_cache = 'cat_posts_' . $id_categoria . '_' . $cantidad;
    $posts = get_transient($clave_cache);

    if (false === $posts) {
        $args = array(
            'cat' => $id_categoria,
            'posts_per_page' => $cantidad
        );

        $query = new WP_Query($args);
        $posts = $query->posts;

        // Cache por 1 hora
        set_transient($clave_cache, $posts, HOUR_IN_SECONDS);
    }

    return $posts;
}

#2. Optimizar consultas de base de datos

// Solo recuperar los campos que necesitas
$args = array(
    'category_name' => 'noticias',
    'posts_per_page' => 10,
    'fields' => 'ids' // Solo obtener IDs de posts para mejor rendimiento
);

$query = new WP_Query($args);

#3. Usar Object Caching

Si tu sitio usa un object cache (Redis, Memcached), los resultados de WP_Query se cachean automáticamente, mejorando el rendimiento para consultas repetidas.

#Técnicas avanzadas

#Plantillas personalizadas para archivos de categoría

Crea un archivo de plantilla category-noticias.php para estilos específicos de categoría:

<?php
/* Template Name: Categoria - Noticias */
get_header(); ?>

<div class="archivo-categoria">
    <h1><?php single_cat_title(); ?></h1>

    <?php if (have_posts()) : ?>
        <div class="cuadricula-posts">
            <?php while (have_posts()) : the_post(); ?>
                <?php get_template_part('content', 'category'); ?>
            <?php endwhile; ?>
        </div>

        <?php the_posts_págination(); ?>
    <?php else : ?>
        <p>No se encontraron posts en esta categoria.</p>
    <?php endif; ?>
</div>

<?php get_footer(); ?>

#Carga AJAX para posts de categoría

Para una mejor experiencia de usuario, implementa carga AJAX. Hay dos detalles que hacen tropezar a mucha gente: ajaxurl solo está definido en wp-admin, así que en el front end tienes que pasarlo tú mismo, y cada petición necesita un nonce para superar una revisión de seguridad.

Encola el script y entrégale la URL de admin-ajax junto con un nonce:

function enqueue_category_loader() {
    wp_enqueue_script(
        'category-loader',
        get_theme_file_uri('/js/category-loader.js'),
        array('jquery'),
        '1.0',
        true
    );
    wp_localize_script('category-loader', 'catLoader', array(
        'ajaxurl' => admin_url('admin-ajax.php'),
        'nonce'   => wp_create_nonce('load_category_posts'),
    ));
}
add_action('wp_enqueue_scripts', 'enqueue_category_loader');

La petición desde el front end lee entonces del objeto localizado:

jQuery(document).ready(function($) {
    $('.load-more').on('click', function() {
        var button = $(this);

        $.ajax({
            url: catLoader.ajaxurl,
            type: 'POST',
            data: {
                action: 'load_category_posts',
                nonce: catLoader.nonce,
                category: button.data('category'),
                page: button.data('page')
            },
            success: function(response) {
                $('.posts-container').append(response);
                button.data('page', button.data('page') + 1);
            }
        });
    });
});

Por último, registra el handler tanto para usuarios autenticados como anónimos (wp_ajax_ y wp_ajax_nopriv_), verifica el nonce y devuelve el marcado renderizado:

function load_category_posts_handler() {
    check_ajax_referer('load_category_posts', 'nonce');

    $category = sanitize_text_field($_POST['category'] ?? '');
    $page     = max(1, intval($_POST['page'] ?? 1));

    $query = new WP_Query(array(
        'category_name'  => $category,
        'posts_per_page' => 5,
        'paged'          => $page,
    ));

    if ($query->have_posts()) {
        while ($query->have_posts()) {
            $query->the_post();
            printf(
                '<article><h3><a href="%s">%s</a></h3></article>',
                esc_url(get_permalink()),
                esc_html(get_the_title())
            );
        }
        wp_reset_postdata();
    }

    wp_die(); // required so admin-ajax stops cleanly
}
add_action('wp_ajax_load_category_posts', 'load_category_posts_handler');
add_action('wp_ajax_nopriv_load_category_posts', 'load_category_posts_handler');

#Mostrar posts de categoría en un tema de bloques

En los temas de bloques (el estándar desde WordPress 6.1) a menudo no necesitas PHP en absoluto. El bloque Query Loop filtrado por categoría muestra la misma lista desde el editor: inserta un Query Loop, abre los ajustes del bloque y, en Filtros, añade la categoría que quieras. Guárdalo como un patrón sincronizado y los editores podrán colocar la lista curada en cualquier página sin tocar una plantilla.

Recurre a los enfoques con código de arriba cuando necesites lógica que el bloque no puede expresar: cache con transients, exclusiones condicionales por archivo o una salida que consuma algo distinto del tema (un boletín por correo, una respuesta REST).

#Obtener posts de categoría a través de la REST API

Para front ends headless, una isla de React o una integración externa, WordPress expone los posts de categoría a través de la REST API sin necesidad de un endpoint personalizado:

GET /wp-json/wp/v2/posts?categories=5&per_page=10&_fields=id,title,link,excerpt

Usa categories_exclude para filtrar un término, _embed para traer las imágenes destacadas y los nombres de términos en una sola llamada, y _fields para reducir la carga a lo que el cliente realmente muestra. Para resolver un slug al ID que espera el endpoint, consulta primero /wp-json/wp/v2/categories?slug=news.

#Depurar una consulta de categoría que devuelve los posts equivocados

Cuando una consulta devuelve demasiados posts, muy pocos o posts inesperados, inspecciona el SQL que realmente ejecutó en lugar de adivinar con los argumentos. Instala Query Monitor y te mostrará todas las consultas de la página, incluida la que genera tu loop, con las lentas marcadas. Para una comprobación rápida sin plugin, vuelca la consulta ya interpretada:

$query = new WP_Query($args);
// The exact SQL WordPress built from your $args
error_log($query->request);

Los dos culpables detrás de la mayoría de las sorpresas son la inclusión de términos hijos (mira include_children más arriba) y algún filtro pre_get_posts perdido de un plugin o del tema que altera la consulta principal. Si el SQL parece correcto pero el resultado está vacío, confirma que el término tenga realmente posts publicados asignados en el idioma o contexto actual. En sitios multilingües con Polylang o WPML, esto último es la causa más frecuente en el mercado español: la categoría existe, pero los posts están asignados a la versión en otro idioma.

#Errores comunes a evitar

  1. No restablecer post data: Siempre llama a wp_reset_postdata() después de loops personalizados
  2. Consultar en cada carga de página: Usa cache para consultas costosas
  3. No verificar si existen posts: Siempre verifica have_posts() antes de iterar
  4. Modificar la consulta principal incorrectamente: Usa pre_get_posts en lugar de crear nuevas consultas en páginas de archivo
  5. Ignorar la páginación: Recuerda manejar la páginación para archivos de categoría grandes

#Conclusion

WordPress proporciona múltiples formás de extraer posts de categorías, cada una adecuada para diferentes escenarios:

  • WP_Query: Mejor para visualizaciones complejas y personalizadas
  • get_posts(): Ideal para listas simples de posts
  • Shortcodes: Perfecto para flexibilidad del editor de contenido
  • pre_get_posts: Esencial para modificar páginas de archivo

Entender estos métodos y cuando usar cada uno te hara un desarrollador WordPress más efectivo. Recuerda siempre considerar el rendimiento, especialmente en sitios con grandes cantidades de contenido.

Para sitios en producción, implementa estrategias de cache y prueba tus consultas con herramientas como Query Monitor para asegurar un rendimiento óptimo.

Necesitas ayuda con consultas avanzadas de WordPress? Nuestro equipo de desarrollo WordPress puede implementar soluciones optimizadas para tu proyecto. Contactaños.

Siguiente paso

Transforma el artículo en una implementación real

Este bloque refuerza el enlazado interno y lleva al lector al siguiente paso más útil dentro de la arquitectura del sitio.

¿Quieres implementar esto en tu sitio?

Si quieres transformar el artículo en mejoras concretas, rediseño o un plan de implementación, puedo cerrar el alcance y ejecutar.

Cluster relacionado

Explora otros servicios WordPress y base de conocimiento

Refuerza tu negocio con soporte técnico profesional en áreas clave del ecosistema WordPress.

Necesito ser un desarrollador experimentado para usar esta guía?#
Esta guía está diseñada para desarrolladores WordPress intermedios. Se asume conocimiento básico de PHP y WordPress, pero todo el código se explica paso a paso.
Estas técnicas funcionaran con cualquier tema de WordPress?#
La mayoría de las técnicas son independientes del tema y funcionan con temas estándar de WordPress. Sin embargo, algunos temas muy personalizados pueden requerir adaptacion adicional.
Es seguro implementar estos cambios en un sitio en vivo?#
Siempre prueba los cambios en un entorno de staging primero. Aunque estas técnicas están listas para producción, las pruebas previenen problemas potenciales en sitios en vivo.
Estos métodos funcionan con constructores de páginas como Elementor?#
Sí, la mayoría de los métodos funcionan junto a constructores de páginas. Algunos pueden requerir pasos de integración específicos que se indican en la sección de implementación.
Sigo necesitando código en un tema de bloques?#
Para una lista básica, no. El bloque Query Loop filtrado por categoría muestra los posts de la categoría directamente desde el editor. Recurre a los enfoques con código cuando necesites cache, exclusiones condicionales o una salida que se consuma fuera del tema, como una respuesta REST.

¿Necesitas un FAQ adaptado a tu sector y mercado? Preparamos una versión alineada con tus objetivos de negocio.

Hablemos

Artículos Relacionados