WP_Query - ¿Filtrar o directamente?
La cantidad de mis archivos, plantillas, scripts, consultas, etc. está creciendo y necesito un buen sistema para mantener todo organizado.
He intentado mantener todo ordenado:
- Sin etiquetas
<script>
en las plantillas CSS
inline solo cuando es una variablePHP
que puede cambiarse dinámicamente desde las opciones del admin- Archivos únicos grandes de
JS
yCSS
para minimizar las peticiones
Ahora es momento de organizar mis consultas porque tengo al menos 10 y siguen aumentando.
Primera opción: usar
add_filter()
personalizado con cada consulta- No tengo que buscar las consultas porque todas están en un archivo o directorio
- Si necesito cambiarla, solo debo modificarla en un lugar, no en todas mis plantillas
Segunda opción: escribir todas las consultas directamente en las plantillas como se suele hacer
- Básicamente cada punto es lo contrario de la primera opción
Pregunta:
¿Usar filtros para los argumentos de las consultas tiene alguna desventaja? ¿Rendimiento? ¿Algo más?
Ejemplo:
Usual:
$args = array( 'post_type' => 'my-post', 'posts_per_page' => 8, 'orderby' => 'rand', ); } $results = new WP_Query( $args );
Filtro:
//En un archivo -> fácil de encontrar y cambiar add_filter( 'some_args', 'some_search_args' ); function some_search_args( $search_args ) { $search_args['post_type'] = 'property'; $search_args['posts_per_page'] = 8; $search_args['orderby'] = 'rand'; //Todo tipo de lógica y código condicional puede ir aquí return $search_args; } //Y //Solo incluir así en cualquier plantilla que quieras y tantas veces como necesites //Para cambiar la consulta, solo tendrás que modificar el código de arriba $search_args = array(); $search_args = apply_filters( 'some_args', $search_args ); $results = new WP_Query( $search_args );
Debes considerar varias cosas aquí y parece que buscas mejorar el rendimiento de una consulta. La primera y más importante pregunta que debes hacerte es:
¿Necesito una consulta personalizada?
Hice una publicación extensa sobre este tema hace un tiempo que deberías revisar. Si respondiste que sí a la pregunta anterior después de leer mi publicación en el enlace, entonces debes considerar lo siguiente al crear consultas personalizadas:
Evita (cuando puedas) operaciones complejas de
orderby
como ordenar por valores meta. SQL no es el mejor para ordenar y PHP a veces es más rápido. Tiendo a preferirusort()
para ordenamientos complejos para ahorrar recursos. El orden aleatorio también es muy costoso en recursos.Evita (cuando puedas) construir consultas complejas con meta y tax queries anidados, especialmente con muchos operadores
OR
. Estos son bastante exigentes en recursos.Evita (cuando puedas) usar operadores
LIKE
en tu SQL generado. Estos también son costosos.Usa transients (y cachés) para almacenar consultas costosas. Para consultas aleatorias, no puedes hacer esto, así que necesitarás buscar otros métodos para abordar este problema.
Siempre evita el típico bucle
foreach
donde obtienes una lista de términos y luego ejecutas una consulta personalizada para cada uno, son realmente costosos. En su lugar, consulta todos los posts de una vez y luego usausort()
para ordenar los resultados.Crea una consulta según lo que necesites. La mayoría de las veces solo necesitamos consultar posts para obtener sus IDs y pasarlos a otra función. En casos como estos, solo consulta los IDs de los posts. Esto realmente ahorra muchos recursos. Simplemente agrega
'fields'=>'ids',
a los argumentos de tu consulta.Para acelerar consultas no paginadas, usa
get_posts()
o simplemente pasa'no_found_rows'=>true
aWP_Query
(esto es exactamente lo que hace `get_posts). Esto omite el proceso de paginación y ahorra muchos recursos en bases de datos grandes.
Esto solo pretende ser una guía para acelerar la consulta. Todavía hay otras cosas para acelerar las consultas.
¿Usar filtros para los argumentos de consulta tiene alguna desventaja? ¿Rendimiento? ¿Algo más?
No veo por qué podría haber problemas. Si estás creando un tema comercial, definitivamente lo estás haciendo correctamente. Hacer algo filtrable hace la vida de los autores de temas hijos mucho más fácil. Podría costar una milésima de una milésima de una milésima de segundo, pero definitivamente es tiempo bien empleado. Es como la sanitización. La sanitización cuesta tiempo y recursos (aunque es muy, muy poco), pero gastar un milisegundo más en algo puede salvar tu sitio de ser hackeado y destruido.
En mi humilde opinión, necesitarías buscar otras formas de acelerar una consulta sin comprometer la usabilidad y mantenibilidad. La opción 2 es definitivamente algo que deberías hacer para temas comerciales.
IDEA (Podría ser un poco exagerado ;-))
También puedes usar pre_get_posts
para filtrar tu consulta personalizada y hacerla filtrable. Es tan simple como establecer tu propio parámetro personalizado en tu consulta y luego usar ese parámetro para dirigir tu consulta.
En el siguiente ejemplo, usaremos un parámetro personalizado query_no
al que le daremos valores numéricos.
Las Consultas
$q1 = new WP_Query( ['query_no' => 1] );
$q2 = new WP_Query( ['query_no' => 2] );
$q3 = new WP_Query( ['query_no' => 3] );
pre_get_posts
add_action( 'pre_get_posts', function( $q )
{
if ( $q->get( 'query_no' ) == 1 ) {
$q->set( 'posts_per_page', -1 );
// Agrega cualquier otro argumento adicional para establecer
}
if ( $q->get( 'query_no' ) == 2 ) {
$q->set( 'post_type', ['post', 'page'] );
// Agrega cualquier otro argumento adicional para establecer
}
if ( $q->get( 'query_no' ) == 3 ) {
$q->set( 'post_status', 'trash' );
// Agrega cualquier otro argumento adicional para establecer
}
} );
El usuario ahora puede agregar argumentos adicionales o cambiar los pasados.
add_action( 'pre_get_posts', function( $q )
{
if ( $q->get( 'query_no' ) == 2 ) {
// Añadamos otro tipo de post
$post_types = $q->get( 'post_type' );
$post_types = array_merge( $post_types, ['my_post_type'] );
$q->set( 'post_type' , $post_types );
$q->set( 'posts_per_page', -1 );
// Agrega cualquier otro argumento adicional para establecer
}
},
11 // Asegúrate de que esto se ejecute después de la acción por defecto
);

¿Qué opinas sobre los transients cuando los resultados de las consultas son los mismos? Un ejemplo simple pero ilustrativo: se hace una consulta vía AJAX ->
se establece un transient ->
y cuando el usuario hace spam en el botón sin cambiar los campos de entrada (he configurado protección contra spam para los botones AJAX pero aún así...) ->
obtener los resultados de los transients? Pregunto esto porque mi gran consulta está vinculada con un mapa y el desplazamiento/zoom llama a otra consulta exactamente igual porque mostrar ej. 100,000 marcadores mata cualquier navegador.

Simplemente revisa las publicaciones vinculadas bajo usort()
. Yo creo nombres únicos para los transients tomando los argumentos, luego uso md5()
para crear una clave única que agrego al nombre del transient. De esta manera, si los argumentos de la consulta cambian, se crea un transient único. Cualquier otra llamada posterior con los mismos argumentos simplemente carga los resultados desde el transient.

Lo siento, debí estar ciego porque no lo vi antes... Gracias por la respuesta tan detallada.
