WP_Query vs get_posts(): cuándo usar cada uno

febrero 7, 2026 por admin Desarrollo de Temas

Una de las preguntas más frecuentes cuando empiezas a desarrollar en WordPress es cuándo usar WP_Query y cuándo get_posts(). Ambas sirven para obtener posts de la base de datos, pero tienen diferencias importantes que afectan al rendimiento y al comportamiento de tu código.

En este artículo te explico las diferencias reales con ejemplos concretos.

WP_Query — la clase completa

WP_Query es la clase principal de WordPress para consultas a la base de datos. Es la más potente y la más flexible de las dos opciones.

$args = array(
    'post_type'      => 'producto',
    'posts_per_page' => 6,
    'orderby'        => 'date',
    'order'          => 'DESC',
    'tax_query'      => array(
        array(
            'taxonomy' => 'categoria_producto',
            'field'    => 'slug',
            'terms'    => 'novedades',
        ),
    ),
);

$query = new WP_Query( $args );

if ( $query->have_posts() ) {
    while ( $query->have_posts() ) {
        $query->the_post();
        ?>
        <article>
            <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
            <?php the_excerpt(); ?>
        </article>
        <?php
    }
    wp_reset_postdata(); // SIEMPRE después del loop
}

La línea wp_reset_postdata() al final es crítica. Cuando usas the_post() dentro del loop, WordPress modifica el post global $post. Si no reseteas, otras partes de la página pueden mostrar datos incorrectos.


get_posts() — la función simplificada

get_posts() es internamente un wrapper de WP_Query con algunos parámetros preconfigurados. Devuelve directamente un array de objetos WP_Post, sin necesidad de un loop:

$productos = get_posts( array(
    'post_type'      => 'producto',
    'posts_per_page' => 6,
    'orderby'        => 'title',
    'order'          => 'ASC',
) );

if ( ! empty( $productos ) ) {
    foreach ( $productos as $producto ) {
        echo '<h2>' . esc_html( $producto->post_title ) . '</h2>';
    }
}

Más limpio para casos simples. Sin loop, sin wp_reset_postdata().


Las diferencias clave

Estas son las diferencias que realmente importan en el día a día:

1. suppress_filters

Por defecto, get_posts() tiene suppress_filters = true, lo que significa que ignora los filtros registrados sobre la query, incluyendo los de plugins como WPML o Polylang. Si necesitas que los filtros funcionen, debes desactivarlo explícitamente:

$posts = get_posts( array(
    'post_type'        => 'producto',
    'suppress_filters' => false, // Activar filtros
) );

2. Paginación

WP_Query soporta paginación nativa con paged y paginate_links(). get_posts() no. Si necesitas paginar, usa siempre WP_Query:

$paged = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;

$query = new WP_Query( array(
    'post_type'      => 'producto',
    'posts_per_page' => 6,
    'paged'          => $paged,
) );

// Al final del loop:
echo paginate_links( array(
    'total'   => $query->max_num_pages,
    'current' => $paged,
) );
wp_reset_postdata();

3. Funciones de template

Dentro de un loop de WP_Query (con the_post()), puedes usar todas las funciones de template de WordPress: the_title(), the_content(), the_permalink(), the_thumbnail(). Con get_posts() trabajas directamente con el objeto $post y sus propiedades.


Cuándo usar cada uno — la regla práctica

  • Usa WP_Query cuando: necesitas paginación, vas a usar funciones de template dentro del loop, necesitas que los filtros de plugins funcionen, o la consulta es compleja.
  • Usa get_posts() cuando: solo necesitas un array de posts para procesar datos, la consulta es simple y no necesitas paginación, o estás construyendo algo fuera del ciclo normal de templates.

El error más frecuente — modificar el query principal

Un error muy común es usar WP_Query para modificar el número de posts en el blog principal o en páginas de archivo. La forma correcta de hacerlo es con el hook pre_get_posts, que modifica el query antes de que se ejecute sin crear uno secundario:

// MAL — crea un query secundario innecesario
$query = new WP_Query( array( 'posts_per_page' => 12 ) );

// BIEN — modifica el query principal directamente
add_action( 'pre_get_posts', 'mi_modificar_query_principal' );
function mi_modificar_query_principal( $query ) {
    if ( ! is_admin() && $query->is_main_query() && $query->is_home() ) {
        $query->set( 'posts_per_page', 12 );
    }
}

Usar pre_get_posts es más eficiente porque evita ejecutar dos queries cuando una es suficiente.


Conclusión

La elección entre WP_Query y get_posts() no es una cuestión de preferencia sino de contexto. Para templates con loop y paginación, WP_Query. Para obtener datos sin mostrarlos directamente, get_posts(). Y para modificar el query principal de una página, siempre pre_get_posts.


¿Qué sigue?

  • → pre_get_posts: modifica cualquier query sin código duplicado
  • → Cómo ordenar y filtrar CPTs con tax_query y meta_query
  • → Transients API: cachear resultados de queries costosas

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *