Búsqueda que mirará en campo personalizado, título y contenido de la entrada
Estoy buscando una manera de realizar una búsqueda que verifique un campo personalizado llamado 'keywords', el título de la entrada y el contenido de la entrada. Si cualquiera de estos campos tiene resultados similares a lo que el usuario busca, mostrará el tipo de entrada personalizada (programs) en la página de resultados.
No necesito ayuda con la visualización final del resultado (actualmente hace lo que quiero), pero necesito hacer que cuando busque, revise los tres campos (título de la entrada, contenido de la entrada y el campo personalizado keywords), y si cualquiera de ellos tiene un resultado similar a lo que se buscó, muestre los resultados. Este es el código que tengo hasta ahora. Actualmente solo está buscando en el campo personalizado keywords:
elseif($program_search) {
// búsqueda por texto de búsqueda de programa
query_posts(array(
'post_type' => 'program',
'meta_query' => array(
array(
'key' => 'keywords',
'value' => $program_search,
'compare' => 'LIKE'
),
)
));
if ( have_posts() ) :
while ( have_posts() ) :
the_post();
$l.= "<div class='program-item'>";
$l.= "<div class='program-item-image'><a href='".get_permalink($post->ID)."'>". get_the_post_thumbnail($post->ID, 'thumbnail')."</a></div>";
$l.= "<div class='program-item-title'><a href='".get_permalink($post->ID)."'>".get_the_title($post->ID)."</a></div>";
$l.= "<div class='program-item-content'>".get_the_excerpt()."</div>";
$l.= "<div style='clear:both;'></div>";
$l.= "</div>";
endwhile;
else:
endif;
}
Primero, no uses query_posts
.
Segundo, puedes pasar un parámetro s
para lograr la mayor parte del objetivo.
$program_search = 'test';
$args = array(
'post_type' => 'program',
's' => $program_search,
'meta_query' => array(
array(
'key' => 'keywords',
'value' => $program_search,
'compare' => 'LIKE'
),
)
);
$t = new WP_Query($args);
var_dump($t->request);
Ese parámetro s
activa los mecanismos de búsqueda ordinarios y se busca en el título y el contenido. Si miras la consulta generada verás...
SELECT
SQL_CALC_FOUND_ROWS
wp_posts.ID
FROM wp_posts
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
WHERE 1=1
AND (((wp_posts.post_title LIKE '%test%') OR (wp_posts.post_content LIKE '%test%')))
AND (wp_posts.post_password = '')
AND wp_posts.post_type = 'program'
AND (wp_posts.post_status = 'publish')
AND ((wp_postmeta.meta_key = 'keywords' AND CAST(wp_postmeta.meta_value AS CHAR) LIKE '%test%'))
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0, 5
Eso es la mayor parte de lo que necesitas. El LIMIT
, a menos que se especifique lo contrario, es el límite establecido en wp-admin->Ajustes->Generales. Sin embargo, hay un problema.
AND ((wp_postmeta.meta_key = 'keywords' AND CAST(wp_postmeta.meta_value AS CHAR) LIKE '%test%'))
Estoy bastante seguro de que quieres que sea OR ((wp_postmeta.meta_key ...
y realmente quieres que esté junto al post_title
y al post_content
también. Algo así:
AND (
(
(wp_posts.post_title LIKE '%test%')
OR
(wp_posts.post_content LIKE '%test%')
OR
(wp_postmeta.meta_key = 'keywords' AND CAST(wp_postmeta.meta_value AS CHAR) LIKE '%test%')
)
)
WP_Query
no hará eso, así que tenemos que crearlo con algunos filtros. Prueba de concepto:
function add_join_wpse_99849($joins) {
global $wpdb;
return $joins . " INNER JOIN {$wpdb->postmeta} ON ({$wpdb->posts}.ID = {$wpdb->postmeta}.post_id)";
}
function alter_search_wpse_99849($search,$qry) {
global $wpdb;
$add = $wpdb->prepare("({$wpdb->postmeta}.meta_key = 'keywords' AND CAST({$wpdb->postmeta}.meta_value AS CHAR) LIKE '%%%s%%')",$qry->get('s'));
$pat = '|\(\((.+)\)\)|';
$search = preg_replace($pat,'(($1 OR '.$add.'))',$search);
return $search;
}
$program_search = 'test';
$args = array(
'post_type' => 'program',
's' => $program_search
);
add_filter('posts_join','add_join_wpse_99849');
add_filter('posts_search','alter_search_wpse_99849',1,2);
$t = new WP_Query($args);
remove_filter('posts_join','add_join_wpse_99849');
remove_filter('posts_search','alter_search_wpse_99849',1,2);
// volcar algunos datos
var_dump($t->request);
var_dump($t->posts);
Observa que omití el meta_query
por completo y en gran parte dupliqué la funcionalidad. Eso es para evitar que se genere ese problemático AND
.
Estás aplicando y eliminando inmediatamente esos filtros para que no interfieran con otras consultas. Hay otras formas de mantener el filtro fuera del camino o de otras consultas. Aquí se describe uno de esos métodos. También puedes agregar el remove_filter
al callback del add_filter
para que se eliminen automáticamente.
