Sử dụng truy vấn meta ('meta_query') với truy vấn tìm kiếm ('s')


25

Cố gắng xây dựng một tìm kiếm không chỉ tìm kiếm mặc định (tiêu đề, nội dung, v.v.) mà còn là một trường tùy chỉnh cụ thể.

Truy vấn hiện tại của tôi:

$args = array(
  'post_type' => 'post',
  's' => $query,
  'meta_query' => array(
     array(
       'key' => 'speel',
       'value' => $query,
       'compare' => 'LIKE'
     )
   )
);

$search = new WP_Query( $args )
...

Điều này trả về các bài đăng phù hợp với cả truy vấn tìm kiếm VÀ truy vấn meta, nhưng tôi cũng muốn nó cũng trả về các bài đăng mà nó chỉ đơn giản phù hợp với một trong số chúng.

Có ý kiến ​​gì không?


Những gì bạn muốn làm là không thể chỉ bằng một truy vấn tìm kiếm. Bạn sẽ cần chạy cả hai truy vấn riêng biệt và sau đó hợp nhất chúng lại với nhau. Điều này đã được mô tả tại câu trả lời khác này. Nó sẽ giúp bạn một tay với cách làm. wordpress.stackexchange.com/questions/55519/ Mạnh
Nick Perkins

Câu trả lời:


19

Tôi đã tìm kiếm hàng giờ để tìm giải pháp cho vấn đề này. Hợp nhất mảng không phải là cách để đi, đặc biệt là khi các truy vấn phức tạp và bạn phải có thể thêm vào các truy vấn meta trong tương lai. Giải pháp đơn giảnđẹp mắt là thay đổi 's' thành một cho phép cả tìm kiếm tiêu đề và trường meta.

add_action( 'pre_get_posts', function( $q )
{
    if( $title = $q->get( '_meta_or_title' ) )
    {
        add_filter( 'get_meta_sql', function( $sql ) use ( $title )
        {
            global $wpdb;

            // Only run once:
            static $nr = 0; 
            if( 0 != $nr++ ) return $sql;

            // Modified WHERE
            $sql['where'] = sprintf(
                " AND ( %s OR %s ) ",
                $wpdb->prepare( "{$wpdb->posts}.post_title like '%%%s%%'", $title),
                mb_substr( $sql['where'], 5, mb_strlen( $sql['where'] ) )
            );

            return $sql;
        });
    }
});

Sử dụng:

$meta_query = array();
$args = array();
$search_string = "test";

$meta_query[] = array(
    'key' => 'staff_name',
    'value' => $search_string,
    'compare' => 'LIKE'
);
$meta_query[] = array(
    'key' => 'staff_email',
    'value' => $search_string,
    'compare' => 'LIKE'
);

//if there is more than one meta query 'or' them
if(count($meta_query) > 1) {
    $meta_query['relation'] = 'OR';
}

// The Query
$args['post_type'] = "staff";
$args['_meta_or_title'] = $search_string; //not using 's' anymore
$args['meta_query'] = $meta_query;



$the_query = new WP_Query($args)

Đây là cách đúng đắn,
Zorox

Tuyệt vời, điều này làm việc rất tốt cho tôi. Giải pháp tuyệt vời! Cảm ơn!
Fabiano

Đây là một truy vấn, không phải là một tìm kiếm. Nếu bạn có các plugin hoạt động trên tìm kiếm, nó không hoạt động. Tôi có lầm không?
marek.m

5

Rất nhiều mã có thể được giảm bằng cách sử dụng một phiên bản sửa đổi của câu trả lời này .

$q1 = new WP_Query( array(
    'post_type' => 'post',
    'posts_per_page' => -1,
    's' => $query
));

$q2 = new WP_Query( array(
    'post_type' => 'post',
    'posts_per_page' => -1,
    'meta_query' => array(
        array(
           'key' => 'speel',
           'value' => $query,
           'compare' => 'LIKE'
        )
     )
));

$result = new WP_Query();
$result->posts = array_unique( array_merge( $q1->posts, $q2->posts ), SORT_REGULAR );
$result->post_count = count( $result->posts );

Điều này làm việc rất tốt cho tôi (đặc biệt là vì tôi cần sử dụng WP_Query thay vì get_posts). Tôi đã phải sửa đổi dòng post_count của bạn thành: $result->post_count = count( $result->posts );bởi vì tôi chỉ nhận được 1 kết quả khác.
GreatBlakes

4

Tôi đã tối ưu hóa @Stabir Kira trả lời một chút

function wp78649_extend_search( $query ) {
    $search_term = filter_input( INPUT_GET, 's', FILTER_SANITIZE_NUMBER_INT) ?: 0;
    if (
        $query->is_search
        && !is_admin()
        && $query->is_main_query()
        && //your extra condition
    ) {
        $query->set('meta_query', [
            [
                'key' => 'meta_key',
                'value' => $search_term,
                'compare' => '='
            ]
        ]);

        add_filter( 'get_meta_sql', function( $sql )
        {
            global $wpdb;

            static $nr = 0;
            if( 0 != $nr++ ) return $sql;

            $sql['where'] = mb_eregi_replace( '^ AND', ' OR', $sql['where']);

            return $sql;
        });
    }
    return $query;
}
add_action( 'pre_get_posts', 'wp78649_extend_search');

Bây giờ bạn có thể tìm kiếm theo (tiêu đề, nội dung, đoạn trích) hoặc (trường meta) hoặc (cả hai).


3

Theo đề nghị của Nick Perkins , tôi đã phải hợp nhất hai truy vấn như vậy:

$q1 = get_posts(array(
        'fields' => 'ids',
        'post_type' => 'post',
        's' => $query
));

$q2 = get_posts(array(
        'fields' => 'ids',
        'post_type' => 'post',
        'meta_query' => array(
            array(
               'key' => 'speel',
               'value' => $query,
               'compare' => 'LIKE'
            )
         )
));

$unique = array_unique( array_merge( $q1, $q2 ) );

$posts = get_posts(array(
    'post_type' => 'posts',
    'post__in' => $unique,
    'post_status' => 'publish',
    'posts_per_page' => -1
));

if( $posts ) : foreach( $posts as $post ) :
     setup_postdata($post);

     // now use standard loop functions like the_title() etc.     

enforeach; endif;

1
Điều này vẫn không thể thực hiện được nếu không sáp nhập vào năm 2016? Tôi đang chỉnh sửa truy vấn tìm kiếm thông qua pre_get_posts, vì vậy đây thực sự không phải là một tùy chọn ...
trainoocation

@trainoocation Tôi không nghĩ vậy. Tôi đã thử nó từ 2 giờ trước và một tìm kiếm google đã đưa tôi đến đây.
Umair Khan Jadoon

2

Đó là một loại hack nhưng nó hoạt động. Bạn cần thêm bộ lọc tests_clauses. Hàm bộ lọc này kiểm tra xem có bất kỳ từ truy vấn nào tồn tại trong trường tùy chỉnh "speel" không và truy vấn còn lại vẫn còn nguyên.

function custom_search_where($pieces) {

    // filter for your query
    if (is_search() && !is_admin()) {

        global $wpdb;

        $keywords = explode(' ', get_query_var('s'));
        $query = "";
        foreach ($keywords as $word) {

            // skip possible adverbs and numbers
            if (is_numeric($word) || strlen($word) <= 2) 
                continue;

            $query .= "((mypm1.meta_key = 'speel')";
            $query .= " AND (mypm1.meta_value  LIKE '%{$word}%')) OR ";
        }

        if (!empty($query)) {
            // add to where clause
            $pieces['where'] = str_replace("(((wp_posts.post_title LIKE '%", "( {$query} ((wp_posts.post_title LIKE '%", $pieces['where']);

            $pieces['join'] = $pieces['join'] . " INNER JOIN {$wpdb->postmeta} AS mypm1 ON ({$wpdb->posts}.ID = mypm1.post_id)";
        }
    }
    return ($pieces);
}
add_filter('posts_clauses', 'custom_search_where', 20, 1);

2

Tôi đã có cùng một vấn đề, đối với trang web mới của tôi, tôi vừa thêm một "tiêu đề" meta mới:

Hàm.php

add_action('save_post', 'title_to_meta');

function title_to_meta($post_id)
{
    update_post_meta($post_id, 'title', get_the_title($post_id)); 
}

Và sau đó .. chỉ cần thêm một cái gì đó như thế:

$sub = array('relation' => 'OR');

$sub[] = array(
    'key'     => 'tags',
    'value'   => $_POST['q'],
    'compare' => 'LIKE',
);

$sub[] = array(
    'key'     => 'description',
    'value'   => $_POST['q'],
    'compare' => 'LIKE',
);

$sub[] = array(
    'key'     => 'title',
    'value'   => $_POST['q'],
    'compare' => 'LIKE',
);

$params['meta_query'] = $sub;

Bạn nghĩ gì về cách giải quyết này?


1
Điều đó thực sự không tệ, nhưng yêu cầu bạn phải lưu lại tất cả các bài đăng hiện có hoặc bắt đầu sử dụng nó trước khi bạn bắt đầu thêm nội dung.
Berend

@Berend bạn có thể có thể viết một hàm nhận được tất cả các bài đăng và vòng lặp thông qua chúng cập nhật post_meta cho mỗi bài. Bao gồm nó trong một mẫu hoặc chức năng tùy chỉnh, chạy nó một lần, sau đó loại bỏ nó.
Slam

1

Tất cả các giải pháp trên chỉ trả về kết quả nếu một trận đấu tồn tại trong khóa meta speel. Nếu bạn có kết quả ở nơi khác nhưng không phải trong lĩnh vực này, bạn sẽ không nhận được gì. Không ai muốn điều đó.

Một sự tham gia trái là cần thiết. Sau đây sẽ tạo ra một.

           $meta_query_args = array(
              'relation' => 'OR',
              array(
                'key' => 'speel',
                'value' => $search_term,
                'compare' => 'LIKE',
              ),
              array(
                'key' => 'speel',
                'compare' => 'NOT EXISTS',
              ),
            );
            $query->set('meta_query', $meta_query_args);

0

Đây là một giải pháp tuyệt vời nhưng bạn cần khắc phục một điều. Khi bạn gọi 'post__in', bạn cần đặt một mảng id và $ unique là một mảng các bài đăng.

thí dụ:

$q1 = get_posts(array(
        'fields' => 'ids',
        'post_type' => 'post',
        's' => $query
));

$q2 = get_posts(array(
        'fields' => 'ids',
        'post_type' => 'post',
        'meta_query' => array(
            array(
               'key' => 'speel',
               'value' => $query,
               'compare' => 'LIKE'
            )
         )
));

$unique = array_unique( array_merge( $q1->posts, $q2->posts ) );

$array = array(); //here you initialize your array

foreach($posts as $post)
{
    $array[] = $post->ID; //fill the array with post ID
}


$posts = get_posts(array(
    'post_type' => 'posts',
    'post__in' => $array,
    'post_status' => 'publish',
    'posts_per_page' => -1
));

0

@ satbir-kira trả lời hoạt động tuyệt vời nhưng nó sẽ chỉ tìm kiếm thông qua tiêu đề meta và bài viết. Nếu bạn muốn nó tìm kiếm thông qua meta, tiêu đề và nội dung, đây là phiên bản sửa đổi.

    add_action( 'pre_get_posts', function( $q )
    {
      if( $title = $q->get( '_meta_or_title' ) )
      {
        add_filter( 'get_meta_sql', function( $sql ) use ( $title )
        {
          global $wpdb;

          // Only run once:
          static $nr = 0;
          if( 0 != $nr++ ) return $sql;

          // Modified WHERE
          $sql['where'] = sprintf(
              " AND ( (%s OR %s) OR %s ) ",
              $wpdb->prepare( "{$wpdb->posts}.post_title like '%%%s%%'", $title),
              $wpdb->prepare( "{$wpdb->posts}.post_content like '%%%s%%'", $title),
              mb_substr( $sql['where'], 5, mb_strlen( $sql['where'] ) )
          );

          return $sql;
        });
      }
    });

Và đây là cách sử dụng:

$args['_meta_or_title'] = $get['search']; //not using 's' anymore

$args['meta_query'] = array(
  'relation' => 'OR',
  array(
    'key' => '_ltc_org_name',
    'value' => $get['search'],
    'compare' => 'LIKE'
  ),
  array(
    'key' => '_ltc_org_school',
    'value' => $get['search'],
    'compare' => 'LIKE'
  ),
  array(
    'key' => '_ltc_district_address',
    'value' => $get['search'],
    'compare' => 'LIKE'
  )
);

Thay thế $get['search']bằng giá trị tìm kiếm của bạn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.