Ricerca che controlla campi personalizzati, titolo e contenuto dell'articolo

17 mag 2013, 23:18:59
Visualizzazioni: 23.6K
Voti: 4

Sto cercando un modo per eseguire una ricerca che controlli un campo personalizzato chiamato 'keywords', il titolo del post e il contenuto del post. Se uno qualsiasi di questi campi contiene risultati simili a ciò che l'utente cerca, dovrà mostrare il custom post type (programs) nella pagina dei risultati.

Non ho bisogno di aiuto con la visualizzazione finale dei risultati (che già funziona come desidero), ma ho bisogno di fare in modo che durante la ricerca vengano controllati tutti e tre i campi (titolo del post, contenuto del post e campo personalizzato keywords), e se uno qualsiasi di essi contiene un risultato simile a quello cercato, mostri i risultati. Questo è il codice che ho finora. Al momento sta cercando solo nel campo personalizzato keywords:

elseif($program_search) {
    // ricerca per testo di ricerca del programma
    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
Tutte le risposte alla domanda 1
1
14

Primo, non usare query_posts.

Secondo, puoi passare un parametro s per ottenere gran parte del risultato desiderato.

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

Il parametro s attiva i normali meccanismi di ricerca e vengono cercati sia il titolo che il contenuto. Se guardi la query generata vedrai...

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

Questo è gran parte di ciò che vuoi. Il LIMIT, se non specificato diversamente, è quello impostato in wp-admin->Impostazioni->Generali. C'è però un problema.

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

Sono abbastanza sicuro che tu voglia che sia OR ((wp_postmeta.meta_key ... e che in realtà lo vuoi insieme al post_title e al post_content. Qualcosa del genere:

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 non lo fa, quindi dobbiamo implementarlo con alcuni filtri. Prova di concetto:

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

Nota che ho omesso del tutto il meta_query e ho sostanzialmente duplicato la funzionalità. Questo per evitare che venga generato quel problematico AND.

Stai applicando e rimuovendo immediatamente quei filtri in modo che non interferiscano con altre query. Ci sono altri modi per tenere il filtro fuori dalle altre query. Un metodo è descritto qui. Puoi anche aggiungere il remove_filter al callback di add_filter per farli rimuovere automaticamente.

18 mag 2013 01:19:04
Commenti

Puoi spiegare perché NON dovresti usare query_posts?

Lee Lee
12 ott 2018 13:07:54