Filtrar por un campo personalizado y ordenar por otro
Tengo un tipo de post personalizado "Listing" y quiero obtener todos los Listings que tienen un campo personalizado gateway_value != 'Yes'
, y ordenar los resultados por otro campo personalizado, location_level1_value
. Puedo hacer que las consultas funcionen por separado, pero no puedo combinarlas:
Consulta 1 (ordenar por ubicación):
$wp_query = new WP_Query( array (
'post_type' => 'listing',
'post_status' => 'publish',
'posts_per_page' => '9',
'meta_key' => 'location_level1_value',
'orderby' => 'location_level1_value',
'order' => 'ASC',
'paged' => $paged
)
);
Consulta 2 (valor del campo personalizado != Yes):
$wp_query = new WP_Query( array (
'post_type' => 'listing',
'posts_per_page' => '9',
'post_status' => 'publish',
'meta_key' => 'gateway_value',
'meta_value' => 'Yes',
'meta_compare' => '!=',
'paged' => $paged
)
);
Consulta combinada:
Consulté el codex para obtener ayuda con esto, pero la siguiente consulta no funciona:
$wp_query = new WP_Query( array (
'post_type' => 'listing',
'posts_per_page' => '9',
'post_status' => 'publish',
'meta_query' => array(
array(
'key' => 'gateway_value',
'value' => 'Yes',
'compare' => '!='
),
array(
'key' => 'location_level1_value'
)
),
'orderby' => "location_level1_value",
'order' => 'ASC',
'paged' => $paged
)
);
¿Qué estoy haciendo mal en la consulta combinada?
[ACTUALIZACIÓN]: Ahora que se ha lanzado la versión 3.1, la consulta combinada anterior todavía no funciona. Obtengo resultados, pero no están ordenados correctamente.
[ACTUALIZACIÓN]: var_dump($wp_query->request)
muestra lo siguiente:
string(527) " SELECT SQL_CALC_FOUND_ROWS wp_7v1oev_posts.* FROM wp_7v1oev_posts
INNER JOIN wp_7v1oev_postmeta ON (wp_7v1oev_posts.ID = wp_7v1oev_postmeta.post_id)
INNER JOIN wp_7v1oev_postmeta AS mt1 ON (wp_7v1oev_posts.ID = mt1.post_id) WHERE 1=1 AND wp_7v1oev_posts.post_type = 'listing' AND (wp_7v1oev_posts.post_status = 'publish') AND wp_7v1oev_postmeta.meta_key = 'gateway_value' AND CAST(wp_7v1oev_postmeta.meta_value AS CHAR) != 'Yes' AND mt1.meta_key = 'location_level1_value' ORDER BY wp_7v1oev_posts.post_date DESC LIMIT 0, 9"

Podrías usar la consulta para filtrar el contenido como deseas utilizando 'meta_query' con opciones de filtrado, y para la parte del orden, simplemente añade/modifica los siguientes parámetros:
- 'orderby' => 'meta_value'
- 'meta_key' => 'location_level1_value'
'order' => 'ASC'
$wp_query = new WP_Query( array ( 'post_type' => 'listing', 'posts_per_page' => '9', 'post_status' => 'publish', 'meta_query' => array( array( 'key' => 'gateway_value', 'value' => 'Yes', 'compare' => '!=' ) ), 'orderby' => 'meta_value', // esto significa que usaremos un campo meta // seleccionado para ordenar 'meta_key' => 'location_level1_value', // esto indica qué campo meta // se usará en el ordenamiento, // independientemente de los filtros 'order' => 'ASC', 'paged' => $paged ) );

Como dijo Jan, en el nuevo WordPress 3.1 puedes usar meta_query
, pero hasta que salga esa versión puedes usar tu primera consulta para ordenar y filtrar dentro de tu loop de esta manera:
Global $my_query;
$my_query = new WP_Query( array (
'post_type' => 'listing',
'post_status' => 'publish',
'posts_per_page' => '9',
'meta_key' => 'location_level1_value',
'orderby' => 'location_level1_value',
'order' => 'ASC',
'paged' => $paged
)
);
while ($my_query->have_posts){
$my_query->the_post();
//haz tus operaciones del loop
}
y agrega este código a tu functions.php
//filtro de unión
add_filter('posts_join', 'listing_join_865' );
function listing_join_865($join){
Global$ my_query;
if ('listing' = $my_query->query['post_type']){
$restriction1 = 'gateway_value';
return $join .="
LEFT JOIN $wpdb->postmeta AS $restriction1 ON(
$wpdb->posts.ID = $restriction1.post_id
AND $restriction1.meta_key = '$restriction1'
)";
}else {
return $join;
}
}
//filtro where
add_filter('posts_where', 'listing_where_865' );
function listing_where_865($where){
global $my_query;
if ('listing' = $my_query->query['post_type']){
return $where.= " AND $restriction1.meta_value != 'yes'";
}else{
return $where;
}
}
ahora esto debería funcionar.

Gracias por esto. Esto funciona, excepto que tengo este extraño efecto secundario de que mi paginación ya no funciona correctamente. En lugar de 9 por página, tengo "espacios vacíos" en mi cuadrícula donde estarían las entradas personalizadas que tienen gateway_value == "Yes"
sin el condicional... ¿Alguna idea sobre cómo solucionar esto?

sí, eso afectaría la paginación, así que supongo que la única solución sería una consulta SQL personalizada, dame unos minutos.

No te preocupes - simplemente usaré la segunda consulta y usaré el plugin http://wordpress.org/extend/plugins/post-types-order hasta que se lance la versión 3.1 :)

vaya, acabo de volver para ver tu comentario después de encontrar una solución. de todos modos, está aquí para futuros consultantes.

@בניית אתרים - Si indentas todo tu código será más fácil pegarlo en las respuestas. Ej. Ponlo en tu editor preferido, selecciónalo todo, luego indéntalo una vez, ahora copia y pega, y evitarás tener que añadir 4 espacios antes de cada línea del código (todo debería quedar en un bloque de código perfectamente sin necesidad de ajustes manuales).

@t31os - normalmente lo hago, pero no cuando respondo desde mi celular.

¿Escribiste eso desde un teléfono?... ¡respeto!.. yo ni siquiera intentaría escribir código en un teléfono.. :) +1 por las habilidades con el móvil! ;)

He intentado pegar bloques de código con tabulaciones desde mi editor de texto y nunca funciona - siempre tengo que agregar los espacios manualmente

Disculpas por responder mi propia pregunta:
Al revisar [http://core.trac.wordpress.org/ticket/15031][1], parece que este es un problema conocido. Lo he solucionado (¿o hackeado?) para que funcione usando post_filter
, de la siguiente manera (solo como referencia para cualquiera que esté buscando la misma respuesta):
En functions.php###
add_filter('posts_orderby', 'EV_locationl1' );
function EV_locationl1 ($orderby) {
global $EV_locationl1_orderby;
if ($EV_locationl1_orderby) $orderby = $EV_locationl1_orderby;
return $orderby;
}
WP_query modificado en el archivo de plantilla###
$EV_locationl1_orderby = " mt1.meta_value ASC";
$wp_query = new WP_Query( array (
'post_type' => 'listing',
'posts_per_page' => '9',
'post_status' => 'publish',
'meta_query' => array(
array(
'key' => 'gateway_value',
'value' => 'Yes',
'compare' => '!='
),
array(
'key' => 'location_level1_value'
)
),
'order' => $EV_locationl1_orderby,
'paged' => $paged
));
