Contents
Introducción: qué es el Loop y cuándo sobrescribirlo
El Loop de WordPress es la estructura que itera sobre los posts resultantes de la consulta principal (main query) para mostrar contenido en una plantilla. Sobrescribir el Loop con WP_Query significa crear una consulta personalizada dentro de una plantilla PHP para mostrar un conjunto distinto de posts (por tipo de post, taxonomía, metadatos, ordenación, etc.). Esto es útil cuando necesitas mostrar listas personalizadas en una página, un archivo o una sección específica sin tocar la consulta principal del propio WordPress.
Cuándo usar WP_Query y cuándo no
- Usa WP_Query dentro de plantillas cuando quieres un loop aislado y control total sobre los parámetros de la consulta, y manteniendo la consulta principal intacta.
- No uses query_posts. query_posts modifica la consulta principal y puede producir problemas de paginación y rendimiento.
- Si quieres cambiar la consulta principal antes de que WordPress la ejecute (por ejemplo, en un archivo de archive.php o home), prefiere pre_get_posts en functions.php en lugar de sobrescribir el loop en plantilla.
Conceptos clave que debes conocer
- paged: número de página actual para paginación.
- setup_postdata(post) / wp_reset_postdata(): para que funciones de plantilla como the_title() y the_content() funcionen con el post actual del loop personalizado.
- custom_query->have_posts() y custom_query->the_post() para iterar sobre una instancia de WP_Query.
- no_found_rows (true/false): mejora rendimiento si no necesitas paginación.
Ejemplo básico: sobrescribir el Loop con WP_Query
Ejemplo típico en un archivo de plantilla (por ejemplo: page-custom.php) donde queremos mostrar 6 posts del tipo post en una lista paginada:
lt?php // Obtener la paginación correcta (soporta front page y páginas estáticas) paged = (get_query_var(paged)) ? get_query_var(paged) : 1 args = array( post_type =gt post, posts_per_page =gt 6, paged =gt paged, ) custom_query = new WP_Query( args ) if ( custom_query-gthave_posts() ) : while ( custom_query-gthave_posts() ) : custom_query-gtthe_post() // Usa las funciones habituales de plantilla ?gt ltarticle id=post-lt?php the_ID() ?gt lt?php post_class() ?gtgt lth2gtlta href=lt?php the_permalink() ?gtgtlt?php the_title() ?gtlt/agtlt/h2gt ltdiv class=entrygtlt?php the_excerpt() ?gtlt/divgt lt/articlegt lt?php endwhile // Paginación: utiliza paginate_links() big = 999999999 // número grande para reemplazo echo paginate_links( array( base =gt str_replace( big, %#%, esc_url( get_pagenum_link( big ) ) ), format =gt ?paged=%#%, current =gt max( 1, paged ), total =gt custom_query-gtmax_num_pages ) ) else : echo ltpgtNo hay posts para mostrar.lt/pgt endif // Restaurar datos globales de post wp_reset_postdata() ?gt
Explicación
- Calculamos paged con get_query_var(paged) para que la paginación funcione tanto en archivos como en páginas.
- Se crea WP_Query con los argumentos deseados.
- En el bucle usamos the_post() y luego wp_reset_postdata() al final para restaurar el post global y evitar conflictos posteriores.
- paginate_links usa custom_query-gtmax_num_pages para saber cuántas páginas crear.
Paginación avanzada y casos especiales
La paginación suele dar problemas cuando se usan páginas estáticas como front page o cuando se utiliza offset. Aquí tienes varios escenarios y soluciones.
1) Paginación con offset
Si usas offset combinada con paged, hay que calcular el desplazamiento manualmente porque WP_Query no ajusta automáticamente el offset por página:
lt?php paged = (get_query_var(paged)) ? get_query_var(paged) : 1 posts_per_page = 5 offset = 2 // queremos saltar los primeros 2 posts permanentemente args = array( post_type =gt post, posts_per_page =gt posts_per_page, offset =gt offset ( (paged - 1) posts_per_page ), paged =gt paged, // aun así mantener paged para compatibilidad ) query = new WP_Query( args ) ?gt
Con este enfoque calculas offset = offset_inicial (paged – 1) posts_per_page.
2) Paginación en la página de inicio estática
En una home estática la variable de paginación a veces es page en lugar de paged. Para cubrir ambos:
lt?php paged = max( 1, get_query_var(paged), get_query_var(page) ) ?gt
Consultas avanzadas: tax_query, meta_query y ordenaciones
WP_Query permite combinar tax_query y meta_query para filtros complejos. Ejemplo: obtener events del tipo custom post type que cumplen una meta fecha mayor que hoy y pertenecen a la categoría conferencia.
lt?php paged = (get_query_var(paged)) ? get_query_var(paged) : 1 today = date( Y-m-d ) args = array( post_type =gt events, posts_per_page =gt 10, paged =gt paged, meta_key =gt event_date, orderby =gt meta_value, order =gt ASC, meta_query =gt array( array( key =gt event_date, value =gt today, compare =gt >=, type =gt DATE ), ), tax_query =gt array( array( taxonomy =gt event_category, field =gt slug, terms =gt conferencia, ), ), ) events_query = new WP_Query( args ) if ( events_query-gthave_posts() ) : while ( events_query-gthave_posts() ) : events_query-gtthe_post() // plantilla para evento endwhile wp_reset_postdata() endif ?gt
Buenas prácticas y rendimiento
- Si no necesitas paginación, añade no_found_rows =gt true para ahorrar la consulta COUNT() que calcula el total de páginas.
- Para listas que solo usan IDs o campos concretos, considera fields =gt ids para reducir carga.
- Evita consultas pesadas dentro de bucles anidados. Si necesitas datos extra, intenta obtenerlos en una única consulta o usar transients para cachear el resultado.
- No hagas queries en la cabecera antes de cargar estilos o scripts críticos que dependan del contenido la lógica de consulta debe estar en la plantilla o en hooks apropiados.
Ejemplo: no_found_rows y campos reducidos
lt?php args = array( post_type =gt product, posts_per_page =gt 20, no_found_rows =gt true, // mejora rendimiento si no hay paginación fields =gt ids, // solo necesitamos los IDs ) ids_query = new WP_Query( args ) if ( ids_query-gthave_posts() ) { ids = ids_query-gtposts // aquí tienes el array de IDs } wp_reset_postdata() ?gt
Alternativa cuando necesitas modificar la consulta principal: pre_get_posts
Si el objetivo es alterar el comportamiento del main query (por ejemplo, cambiar posts_per_page en la página principal o excluir una categoría en la home), es más apropiado usar pre_get_posts en functions.php. Esto evita el uso excesivo de queries adicionales y mantiene la paginación estándar.
lt?php // functions.php function mi_modificacion_main_query( query ) { if ( is_admin() ! query-gtis_main_query() ) { return } if ( query-gtis_home() ) { query-gtset( posts_per_page, 8 ) query-gtset( post__not_in, array( 123 ) ) // excluir post con ID 123 } } add_action( pre_get_posts, mi_modificacion_main_query ) ?gt
Errores comunes y cómo evitarlos
- No usar wp_reset_postdata() al final de un WP_Query puede romper loops y funciones posteriores que esperan el post global original.
- Usar query_posts en lugar de WP_Query: query_posts reescribe global wp_query y rompe la paginación.
- Olvidar calcular correctamente el paged en la home o páginas estáticas, provocando que la paginación siempre muestre la primera página.
- Combinar offset con paged sin ajustar el offset provoca duplicidad de posts o saltos inesperados.
Plantillas modulares: usar get_template_part en el loop personalizado
Para mantener el código limpio, carga trozos de plantilla con get_template_part dentro del while. Ejemplo:
lt?php custom_query = new WP_Query( args ) if ( custom_query-gthave_posts() ) : while ( custom_query-gthave_posts() ) : custom_query-gtthe_post() get_template_part( template-parts/content, get_post_type() ) endwhile wp_reset_postdata() endif ?gt
Checklist final antes de subir la plantilla
- ¿Has usado wp_reset_postdata() después de tu WP_Query?
- ¿La paginación funciona en front page y páginas estáticas (revisar get_query_var(paged) y page)?
- ¿Usas no_found_rows cuando no necesitas paginación para mejorar rendimiento?
- ¿Evitas query_posts y modificas main query con pre_get_posts cuando corresponde?
- ¿Has probado la consulta en entornos con muchos posts y con roles sin permisos para ver contenido privado?
Conclusión
Sobrescribir el Loop con WP_Query en una plantilla PHP te da flexibilidad total para mostrar cualquier conjunto de posts. El patrón básico consiste en crear una instancia de WP_Query con los argumentos adecuados, iterar con have_posts()/the_post(), usar funciones de plantilla dentro del bucle y terminar con wp_reset_postdata(). Ten en cuenta la paginación, el rendimiento (no_found_rows, fields) y las mejores prácticas (evitar query_posts, usar pre_get_posts cuando sea el main query). Si sigues las pautas presentadas en este artículo tendrás plantillas robustas, modulares y eficientes para tu tema de WordPress.
|
Acepto donaciones de BAT's mediante el navegador Brave 🙂 |