Menggunakan kueri meta ('meta_query') dengan kueri penelusuran ('s')

25

Mencoba membangun pencarian yang tidak hanya mencari default (judul, konten, dll) tetapi juga bidang khusus tertentu.

Permintaan saya saat ini:

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

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

Ini mengembalikan posting yang cocok dengan permintaan pencarian DAN permintaan meta, tapi saya juga ingin itu untuk mengembalikan posting di mana itu hanya cocok dengan salah satu dari mereka.

Ada ide?

Lukas
sumber
Apa yang ingin Anda lakukan tidak mungkin hanya menggunakan satu permintaan pencarian. Anda perlu menjalankan kedua kueri secara terpisah dan kemudian menggabungkannya. Ini telah dijelaskan pada jawaban lain ini. Ini akan memberi Anda tangan untuk melakukannya. wordpress.stackexchange.com/questions/55519/…
Nick Perkins

Jawaban:

20

Saya telah mencari berjam-jam solusi untuk masalah ini. Penggabungan array bukan cara yang harus dilakukan, terutama ketika kueri kompleks dan Anda harus dapat menambahkan meta queri di masa mendatang. Solusi yang indah secara sederhana adalah mengubah 's' menjadi yang memungkinkan pencarian judul dan bidang 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;
        });
    }
});

Pemakaian:

$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)
Satbir Kira
sumber
ini jalan yang benar,
Zorox
Luar biasa, ini bekerja sangat baik untuk saya. Solusi hebat! Terima kasih!
Fabiano
Ini adalah permintaan, bukan pencarian. Jika Anda memiliki plugin yang berfungsi pada pencarian, itu tidak berfungsi. Apakah aku salah?
marek.m
5

Banyak kode dapat dikurangi dengan menggunakan versi modifikasi dari jawaban ini .

$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 );
A.Jesin
sumber
Ini bekerja sangat baik untuk saya (terutama karena saya perlu menggunakan WP_Query daripada get_posts). Saya memang harus memodifikasi baris post_count Anda menjadi: $result->post_count = count( $result->posts );karena saya hanya mendapatkan 1 hasil sebaliknya.
GreatBlakes
4

Saya telah mengoptimalkan @Stabir Kira menjawab sedikit

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

Sekarang Anda dapat mencari berdasarkan (judul, konten, excrept) atau (bidang meta) atau (keduanya).

Sebastian Piskorski
sumber
3

Sesuai saran Nick Perkins , saya harus menggabungkan dua pertanyaan seperti:

$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;
Lukas
sumber
1
Apakah ini masih tidak mungkin tanpa penggabungan pada tahun 2016? Saya mengedit permintaan pencarian melalui pre_get_posts, jadi ini benar-benar bukan pilihan ...
trainoasis
@trainoasis kurasa tidak. Saya telah mencobanya sejak 2 jam terakhir dan pencarian google membuat saya di sini.
Umair Khan Jadoon
2

Yah jenis hacknya tapi berhasil. Anda perlu menambahkan filter posts_clauses. Fungsi filter ini memeriksa apakah ada kata kueri yang ada di bidang khusus "speel" dan kueri yang tersisa tetap utuh.

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);
BAPAK
sumber
2

saya memiliki masalah yang sama, untuk situs baru saya, saya baru saja menambahkan meta "judul" baru:

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

Dan kemudian .. tambahkan saja seperti itu:

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

Apa pendapat Anda tentang solusi ini?

MarcoO
sumber
1
Itu sebenarnya tidak buruk, tetapi mengharuskan Anda untuk menyimpan kembali semua posting yang ada atau mulai menggunakannya sebelum Anda mulai menambahkan konten.
Berend
@Berend Anda mungkin bisa menulis fungsi yang mendapatkan semua posting dan loop melalui mereka memperbarui post_meta untuk masing-masing. Sertakan dalam templat atau fungsi khusus, jalankan sekali, lalu buang.
Slam
1

Semua solusi di atas hanya mengembalikan hasil jika ada kecocokan dalam meta key speel. Jika Anda memiliki hasil di tempat lain tetapi tidak di bidang ini, Anda tidak akan mendapatkan apa-apa. Tidak ada yang menginginkan itu.

Gabung kiri diperlukan. Berikut ini akan membuat satu.

           $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);
Tim
sumber
0

Ini adalah solusi hebat tetapi Anda harus memperbaiki satu hal. Ketika Anda memanggil 'post__in', Anda perlu mengatur larik id dan $ unik adalah larik posting.

contoh:

$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
));
Gabriel Bustos
sumber
0

@ satbir-kira jawaban berfungsi dengan baik tetapi hanya akan mencari melalui meta dan judul posting. Jika Anda ingin mencari melalui meta, judul, dan konten, berikut adalah versi yang dimodifikasi.

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

Dan ini dia penggunaannya:

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

Ganti $get['search']dengan nilai pencarian Anda

davexpression
sumber