검색 쿼리 ( 's')와 함께 메타 쿼리 ( 'meta_query') 사용


25

기본값 (제목, 내용 등)뿐만 아니라 특정 사용자 정의 필드도 검색하는 검색을 작성하려고합니다.

내 현재 검색어 :

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

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

검색 쿼리와 메타 쿼리 모두와 일치하는 게시물을 반환하지만 두 게시물 중 하나와 일치하는 게시물도 반환하고 싶습니다.

어떤 아이디어?


하나의 검색어만으로는 원하는 것이 불가능합니다. 두 쿼리를 개별적으로 실행 한 다음 함께 병합해야합니다. 이것은 다른 답변에서 설명되었습니다. 그것을하는 방법을 알려줄 것이다. wordpress.stackexchange.com/questions/55519/…
Nick Perkins

답변:


19

이 문제에 대한 해결책을 찾기 위해 몇 시간 동안 검색했습니다. 특히 쿼리가 복잡하고 나중에 메타 쿼리에 추가 할 수 있어야하는 경우에는 배열 병합을 수행 할 수 없습니다. 간단하게 아름다운 해결책은 's'를 제목과 메타 필드를 모두 검색 할 수있는 것으로 변경하는 것입니다.

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

용법:

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

이것이 올바른 방법입니다
Zorox

환상적인, 이것은 나를 위해 아주 잘 작동했습니다. 훌륭한 솔루션! 감사!
Fabiano

이것은 검색어가 아니라 검색입니다. 검색에서 작동하는 플러그인이 있으면 작동하지 않습니다. 내가 잘못?
marek.m

5

이 답변 의 수정 된 버전을 사용하면 많은 코드를 줄일 수 있습니다 .

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

이것은 나를 위해 잘 작동했습니다 (특히 get_posts 대신 WP_Query를 사용해야했기 때문에). post_count 줄을 다음과 같이 수정해야했습니다 $result->post_count = count( $result->posts );. 그렇지 않으면 1 개의 결과 만 얻었 기 때문입니다.
GreatBlakes

4

@Stabir Kira 답변을 약간 최적화했습니다.

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

이제 (제목, 내용, 발췌) 또는 (메타 필드) 또는 (둘 다)로 검색 할 수 있습니다.


3

당으로 닉 퍼킨스 ' 제안, 난과 같이 두 개의 쿼리를 병합했다 :

$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
2016 년에 병합하지 않으면 여전히 불가능합니까? pre_get_posts를 통해 검색어를 수정하고 있으므로이 옵션은 실제로는 아닙니다.
trainoasis

@trainoasis 나는 그렇게 생각하지 않습니다. 지난 2 시간 이후로 시도해 왔으며 Google 검색으로 나를 여기에 데려 왔습니다.
Umair Khan Jadoon

2

글쎄, 그 종류의 해킹이지만 작동합니다. posts_clauses 필터를 추가해야합니다. 이 필터 함수는 쿼리 단어 중 하나라도 사용자 정의 필드 "speel"에 존재하고 나머지 쿼리는 그대로 유지합니다.

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

나는 새로운 사이트에 대해 새로운 메타 "title"을 추가했다.

functions.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)); 
}

그리고 .. 그냥 다음과 같이 추가하십시오 :

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

이 해결 방법에 대해 어떻게 생각하십니까?


1
실제로 나쁘지는 않지만 콘텐츠를 추가하기 전에 기존 게시물을 모두 다시 저장하거나 사용을 시작해야합니다.
Berend

@Berend 아마도 모든 게시물을 가져 와서 각 게시물에 대해 post_meta를 업데이트하는 루프를 작성하는 함수를 작성할 수 있습니다. 사용자 정의 템플릿 또는 함수에 포함하고 한 번 실행 한 다음 폐기하십시오.
슬램

1

위의 모든 솔루션은 speel 메타 키에 일치하는 항목 만있는 경우에만 결과를 반환합니다. 다른 곳에 결과가 있지만이 필드에는없는 결과는 없습니다. 아무도 그것을 원하지 않습니다.

왼쪽 조인이 필요합니다. 다음은 하나를 만듭니다.

           $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

이것은 훌륭한 솔루션이지만 한 가지만 수정해야합니다. 'post__in'을 호출하면 id 배열을 설정해야하고 $ unique는 post 배열입니다.

예:

$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 답변은 훌륭하지만 메타 및 게시물 제목을 통해서만 검색합니다. 메타, 제목 및 컨텐츠를 검색하려면 수정 된 버전이 있습니다.

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

그리고 여기 사용법이 있습니다 :

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

$get['search']검색 값으로 교체

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.