web-dev-qa-db-fra.com

Recherche qui cherchera dans un champ personnalisé, un titre et un contenu de publication

Je cherche un moyen d'effectuer une recherche et, tout en effectuant la recherche, il vérifie un champ personnalisé appelé "mots-clés", le titre de l'article et le contenu de l'article. Si l'un de ces champs contient des résultats similaires à ceux que l'utilisateur recherche, le type de publication personnalisé (programmes) s'affiche dans la page des résultats.

Je n'ai pas besoin d'aide pour le résultat final (il fait actuellement ce que je veux,) mais je dois le configurer pour qu'il vérifie les trois champs (titre du message, contenu du message et mots-clés personnalisés), et si l'un d'entre eux a un résultat similaire à celui recherché, il affiche les résultats. C'est le code que j'ai jusqu'à présent. Il ne cherche actuellement que dans le champ personnalisé Mots-clés:

elseif($program_search) {
    // search by program search text
    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;
}
4
Brandon

Tout d'abord, n'utilisez pas query_posts.

Deuxièmement, vous pouvez passer un paramètre s pour obtenir le maximum.

$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);

Ce paramètre s permet de mettre en place les mécanismes de recherche ordinaires et de rechercher le titre et le contenu. Si vous regardez cette requête générée, vous verrez ...

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

C'est la plupart de ce que vous voulez. La variable LIMIT, sauf indication contraire, correspond à la limite définie dans wp-admin-> Paramètres-> Général. Il y a un problème cependant.

AND ((wp_postmeta.meta_key = 'keywords' AND CAST(wp_postmeta.meta_value AS CHAR) LIKE '%test%')) 

Je suis sûr que vous voulez que ce soit le OR ((wp_postmeta.meta_key ... et que vous le vouliez vraiment avec le post_title et le post_content aussi. Quelque chose comme ça:

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 ne fera pas cela alors nous devons le faire avec des filtres. Preuve de concept:

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);

// dump some data
var_dump($t->request);
var_dump($t->posts);

Remarquez que j’ai omis le meta_query et copié en grande partie la fonctionnalité. C’est pour empêcher la génération de cette variable AND.

Vous appliquez et supprimez immédiatement ces filtres pour qu'ils n'interfèrent pas avec d'autres requêtes. Il existe d'autres moyens de garder le filtre à l'écart ou d'autres requêtes. Une telle méthode est décrite ici . Vous pouvez également ajouter le remove_filter au rappel add_filter pour les supprimer automatiquement.

11
s_ha_dum