Ricerca che controlla campi personalizzati, titolo e contenuto dell'articolo
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;
}
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.
