Căutare care va verifica câmpul personalizat, titlul articolului și conținutul articolului
Caut o modalitate de a efectua o căutare care să verifice un câmp personalizat numit 'keywords', titlul articolului și conținutul articolului. Dacă oricare dintre aceste câmpuri conține rezultate similare cu ceea ce caută utilizatorul, acesta va afișa tipul de articol personalizat (programs) în pagina de rezultate.
Nu am nevoie de ajutor cu afișarea rezultatului final (în prezent face ceea ce doresc), dar trebuie să fac astfel încât atunci când se efectuează căutarea să verifice toate cele trei câmpuri (titlul articolului, conținutul articolului și câmpul personalizat keywords), și dacă oricare dintre ele are un rezultat asemănător cu ceea ce s-a căutat, să afișeze rezultatele. Acesta este codul pe care îl am până acum. În prezent caută doar în câmpul personalizat keywords:
elseif($program_search) {
// caută după textul de căutare program
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;
}
În primul rând, nu utilizați query_posts
.
În al doilea rând, puteți pasa un parametru s
pentru a ajunge aproape acolo unde doriți.
$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);
Parametrul s
activează mecanismele obișnuite de căutare, astfel încât titlul și conținutul sunt căutate. Dacă analizați interogarea generată, veți vedea...
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
Aceasta este cea mai mare parte din ceea ce doriți. LIMIT
-ul, dacă nu este specificat altfel, este limita setată în wp-admin->Setări->Generale. Există însă o problemă.
AND ((wp_postmeta.meta_key = 'keywords' AND CAST(wp_postmeta.meta_value AS CHAR) LIKE '%test%'))
Sunt aproape sigur că doriți ca aceasta să fie OR ((wp_postmeta.meta_key ...
și de fapt să fie inclusă împreună cu post_title
și post_content
. Ceva de genul:
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
nu face asta, așa că trebuie să realizăm acest lucru cu niște filtre. Demonstrație 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);
// afișează niște date
var_dump($t->request);
var_dump($t->posts);
Observați că am omis complet meta_query
și am duplicat parțial funcționalitatea. Asta pentru a evita generarea acelui problematic AND
.
Aplicați și eliminați imediat acele filtre, astfel încât să nu interfereze cu alte interogări. Există și alte metode pentru a menține filtrul departe de alte interogări. O astfel de metodă este prezentată aici. De asemenea, puteți adăuga remove_filter
în callback-ul add_filter
pentru a le elimina automat.
