Búsqueda que mirará en campo personalizado, título y contenido de la entrada

17 may 2013, 23:18:59
Vistas: 23.6K
Votos: 4

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;
}
0
Todas las respuestas a la pregunta 1
1
14

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.

18 may 2013 01:19:04
Comentarios

¿Puedes explicar por qué NO se debe usar query_posts?

Lee Lee
12 oct 2018 13:07:54