WP_Query dengan “post_title LIKE 'something%'”?

44

Saya perlu melakukan WP_Querydengan LIKEpada post_title.

Saya mulai dengan ini WP_Query:

$wp_query = new WP_Query( 
    array (
        'post_type'        => 'wp_exposants',
        'posts_per_page'   => '1',
        'post_status'      => 'publish',
        'orderby'          => 'title', 
        'order'            => 'ASC',
        'paged'            => $paged
    )
); 

Tapi apa yang sebenarnya ingin saya lakukan terlihat seperti ini di SQL:

$query = "
        SELECT      *
        FROM        $wpdb->posts
        WHERE       $wpdb->posts.post_title LIKE '$param2%'
        AND         $wpdb->posts.post_type = 'wp_exposants'
        ORDER BY    $wpdb->posts.post_title
";
$wpdb->get_results($query);

Outputnya mencetak hasil yang saya perkirakan, tetapi saya menggunakan regular <?php while ( $wp_query->have_posts() ) : $wp_query->the_post(); ?>untuk menampilkan hasilnya.
Dan itu tidak berhasil $wpdb->get_results().

Bagaimana saya bisa mencapai apa yang saya jelaskan di sini?

Ludo
sumber

Jawaban:

45

Saya akan menyelesaikan ini dengan filter aktif WP_Query. Salah satu yang mendeteksi variabel kueri tambahan dan menggunakannya sebagai awalan judul.

add_filter( 'posts_where', 'wpse18703_posts_where', 10, 2 );
function wpse18703_posts_where( $where, &$wp_query )
{
    global $wpdb;
    if ( $wpse18703_title = $wp_query->get( 'wpse18703_title' ) ) {
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'' . esc_sql( $wpdb->esc_like( $wpse18703_title ) ) . '%\'';
    }
    return $where;
}

Dengan cara ini Anda masih dapat memanggil WP_Query, Anda hanya meneruskan judul sebagai wpse18703_titleargumen (atau mengubah nama menjadi sesuatu yang lebih pendek).

Jan Fabry
sumber
Yang satu ini entah bagaimana melewatkan $wpdb->prepare().
kaiser
@iser: Sudah lama, tapi saya pikir ini tidak mungkin dilakukan prepare(). $wpdb->prepare('LIKE "%s%%"', 'banana')akan kembali "LIKE ''banana'%'", jadi kami harus membuat sendiri kueri, dan melakukan pelarian juga.
Jan Fabry
1
@JanFabry Senang melihatmu agaaaaaaaain! :) Mampir mengobrol beberapa saat, hm? StopPress akan senang melihat Anda. Tentang itu prepare(). Ya, itu rumit dan saya harus mencobanya beberapa kali, sebelum saya menyiasatinya. Dari sesuatu yang saya hanya membuat: $wpdb->prepare( ' AND {$wpdb->posts}.post_title LIKE %s ', esc_sql( '%'.like_escape( trim( $term ) ).'%' ) ). Dan saya cukup yakin esc_sql()itu tidak perlu dan hanya paranoid.
kaiser
Tampaknya Anda tidak dapat mencari string dengan '(tanda kutip) di dalamnya. Saya kira itu karena melarikan diri? Saya belum menemukan solusinya
Vincent Decaux
19

Sederhana:

function title_filter( $where, &$wp_query )
{
    global $wpdb;
    if ( $search_term = $wp_query->get( 'search_prod_title' ) ) {
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . esc_sql( like_escape( $search_term ) ) . '%\'';
    }
    return $where;
}

$args = array(
    'post_type' => 'product',
    'posts_per_page' => $page_size,
    'paged' => $page,
    'search_prod_title' => $search_term,
    'post_status' => 'publish',
    'orderby'     => 'title', 
    'order'       => 'ASC'
);

add_filter( 'posts_where', 'title_filter', 10, 2 );
$wp_query = new WP_Query($args);
remove_filter( 'posts_where', 'title_filter', 10, 2 );
return $wp_query;
Rao
sumber
13
Harap sertakan penjelasan beserta kode Anda.
s_ha_dum
2
Penyederhanaan hebat
Timo Huovinen
1
Kode adalah saya pikir menjelaskan sendiri, minimal bagi saya. Terima kasih telah berbagi skrip lengkap.
Hassan Dad Khan
Gunakan '$ wpdb-> esc_like (' bukan 'esc_sql (like_escape ('
fdrv
@ fdrv Anda benar tetapi menurut wp docs $ wpdb-> esc_like masih perlu esc_sql (). Jadi saya pikir kode yang benar adalah esc_sql ($ wpdb-> esc_like ($ search_term))
Waqas Bukhary
16

Ingin memperbarui kode ini yang Anda kerjakan untuk wordpress 4.0 dan di atasnya karena esc_sql () tidak digunakan lagi di 4.0 lebih tinggi.

function title_filter($where, &$wp_query){
    global $wpdb;

    if($search_term = $wp_query->get( 'search_prod_title' )){
        /*using the esc_like() in here instead of other esc_sql()*/
        $search_term = $wpdb->esc_like($search_term);
        $search_term = ' \'%' . $search_term . '%\'';
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE '.$search_term;
    }

    return $where;
}

Sisa barangnya sama.

Saya juga ingin menunjukkan bahwa Anda dapat menggunakan variabel s dalam argumen WP_Query untuk lulus istilah pencarian, yang juga akan mencari judul posting yang saya percayai.

Seperti ini:

$args = array(
    'post_type' => 'post',
    's' => $search_term,
    'post_status' => 'publish',
    'orderby'     => 'title', 
    'order'       => 'ASC'        
);
$wp_query = new WP_Query($args);
Ashan Jay
sumber
Apa sebenarnya search_prod_titleitu? Haruskah saya mengubahnya ke yang lain?
Antonios Tsimourtos
Sejak kapan esc_sqldepricated? Ini bukan. $wpdb->escapeadalah ... developer.wordpress.org/reference/functions/esc_sql
Jeremy
Perhatikan bahwa parameter s juga mencari konten posting, yang mungkin bukan tujuan yang diinginkan. =)
Christine Cooper
10

Dengan beberapa solusi rentan diposting di sini, saya datang dengan versi yang disederhanakan dan disanitasi.

Pertama, kami membuat fungsi untuk posts_wherefilter yang memungkinkan Anda hanya menampilkan posting yang cocok dengan kondisi tertentu:

function cc_post_title_filter($where, &$wp_query) {
    global $wpdb;
    if ( $search_term = $wp_query->get( 'cc_search_post_title' ) ) {
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . $wpdb->esc_like( $search_term ) . '%\'';
    }
    return $where;
}

Sekarang kita tambahkan cc_search_post_titleke argumen kueri kami:

$args = array(
    'cc_search_post_title' => $search_term, // search post title only
    'post_status' => 'publish',
);

Dan akhirnya bungkus filter di sekitar kueri:

add_filter( 'posts_where', 'cc_post_title_filter', 10, 2 );
$query = new WP_Query($args);
remove_filter( 'posts_where', 'cc_post_title_filter', 10 );

Menggunakan get_posts ()

Fungsi tertentu yang mengambil posting tidak menjalankan filter, jadi fungsi filter posts_where yang Anda lampirkan tidak akan mengubah kueri. Jika Anda berencana untuk menggunakan get_posts()kueri posting Anda, Anda perlu disetel suppress_filterske false dalam array argumen Anda:

$args = array(
    'cc_search_post_title' => $search_term,
    'suppress_filters' => FALSE,
    'post_status' => 'publish',
);

Sekarang Anda dapat menggunakan get_posts():

add_filter( 'posts_where', 'cc_post_title_filter', 10, 2 );
$posts = get_posts($args);
remove_filter( 'posts_where', 'cc_post_title_filter', 10 );

Bagaimana dengan sparameternya?

The sParameter tersedia:

$args = array(
    's' => $search_term,
);

Saat menambahkan istilah pencarian Anda ke dalam skerja parameter dan itu akan mencari judul posting, itu juga akan mencari konten posting.

Bagaimana dengan titleparameter yang ditambahkan dengan WP 4.4?

Melewati istilah pencarian ke dalam titleparameter:

$args = array(
    'title' => $search_term,
);

Peka huruf besar-kecil dan LIKE, tidak %LIKE%. Ini berarti pencarian hellotidak akan menghasilkan posting dengan judul Hello Worldatau Hello.

Christine Cooper
sumber
Luar biasa. Saya mencari 'post_title' sebagai parameter dan, jelas, tidak menemukan apa pun.
MastaBaba
7

Membangun jawaban lain sebelum saya, untuk memberikan fleksibilitas dalam situasi di mana Anda ingin mencari posting yang berisi kata dalam bidang meta ATAU dalam judul posting, saya memberikan opsi itu melalui argumen "title_filter_relation." Dalam implementasi ini, saya hanya mengizinkan input "ATAU" atau "DAN" dengan default "DAN."

function title_filter($where, &$wp_query){
    global $wpdb;
    if($search_term = $wp_query->get( 'title_filter' )){
        $search_term = $wpdb->esc_like($search_term); //instead of esc_sql()
        $search_term = ' \'%' . $search_term . '%\'';
        $title_filter_relation = (strtoupper($wp_query->get( 'title_filter_relation'))=='OR' ? 'OR' : 'AND');
        $where .= ' '.$title_filter_relation.' ' . $wpdb->posts . '.post_title LIKE '.$search_term;
    }
    return $where;
}

Berikut adalah contoh kode yang sedang bekerja untuk jenis tulisan "faq" yang sangat sederhana di mana pertanyaannya adalah judul tulisan itu sendiri:

add_filter('posts_where','title_filter',10,2);
$s1 = new WP_Query( array(
    'post_type' => 'faq',
    'posts_per_page' => -1,
    'title_filter' => $q,
    'title_filter_relation' => 'OR',
    'post_status' => 'publish',
    'orderby'     => 'title', 
    'order'       => 'ASC',
    'meta_query' => array(
        'relation' => 'OR',
        array(
            'key' => 'faq_answer',
            'value' => $q,
            'compare' => 'LIKE'
        )
    )
));
remove_filter('posts_where','title_filter',10,2);
David Choy
sumber
1
Wawasan yang bagus, menambahkan "kueri permintaan" khusus ke argumen kueri yang diteruskan WP_Queryagar dapat mengaksesnya di dalam posts_wherefilter.
Tom Auger