Căutare care va verifica câmpul personalizat, titlul articolului și conținutul articolului

17 mai 2013, 23:18:59
Vizualizări: 23.6K
Voturi: 4

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;
}
0
Toate răspunsurile la întrebare 1
1
14

Î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.

18 mai 2013 01:19:04
Comentarii

Poți explica de ce NU ar trebui să folosești query_posts?

Lee Lee
12 oct. 2018 13:07:54