Bisakah saya memaksa WP_Query untuk tidak memberikan hasil?

23

Saya sedang mengerjakan situs web dengan fitur pencarian yang memungkinkan pengguna untuk mencari melalui banyak posting meta. Ada pola pencarian khusus yang ingin saya kembalikan tanpa hasil. WP_Query secara teknis akan menemukan hasil dalam basis data, tetapi saya ingin menimpanya agar memaksanya mengembalikan tidak ada hasil yang memicu if( $example->have_posts() )kegagalan.

Apakah ada semacam parameter yang dapat saya sampaikan ke WP_Query seperti 'force_no_results' => trueitu akan memaksanya untuk tidak memberikan hasil?

Brian
sumber
1
Sepertinya Anda meminta implementasi yang sudah ditentukan, alih-alih bertanya bagaimana menyelesaikan masalah root. Membaca yang tersirat, saya pikir apa yang seharusnya Anda tanyakan adalah: bagaimana cara membuat pola pencarian tertentu tidak bisa ditanyakan? . Menyebabkan WP_Query()tidak ada hasil mungkin atau mungkin bukan cara terbaik untuk menjawab pertanyaan itu. Mungkin juga bermanfaat jika Anda menggambarkan pola pencarian yang Anda inginkan tidak dapat ditanyakan. Mengetahui pola pencarian mungkin membantu menemukan solusi.
Chip Bennett

Jawaban:

28

Mencoba

'post__in' => array(0)

Sederhana dan to the point.

David Labbe
sumber
Pikiran pertama saya adalah - ini pasti salah di suatu tempat, tetapi dari membaca kode terkait hal ini seharusnya bekerja dengan baik. :)
Rarst
5
nol sangat penting karena hanya sebuah array kosong akan mengembalikan tulisan terbaru.
Mark Kaplun
Terima kasih! Ini memecahkan bug bagi saya seperti post__inmengembalikan posting ketika melewati array kosong ... array(0)berfungsi dengan baik! Ini aneh tetapi sebenarnya dapat ditelusuri ke masalah yang muncul di WP core sebagai bug tetapi kemudian dibiarkan apa adanya karena terlalu banyak pengembang tema / plugin membangun fungsionalitas di sekitarnya -_- core.trac.wordpress.org/ tiket / 28099
EranSch
3

Anehnya tidak ada cara bersih / eksplisit untuk hubungan pendek WP_Query.

Jika itu adalah pertanyaan utama yang mungkin Anda selidiki WP->parse_request(), sepertinya do_parse_requestada filter yang relatif baru (3.5) di sana.

Tetapi untuk WP_Queryitu sendiri hack kotor biasanya dalam urutan, seperti query SQL hubungan pendek dengan menambahkan AND 1=0melalui posts_wherefilter, dll.

Jarang
sumber
2
Terimakasih atas infonya. Itu adalah loop sekunder btw. Dan saya akhirnya melakukan hack kotor seperti "post_type" => "break_loop"yang merupakan jenis posting tidak ada.
Brian
2

Masalah pada menetapkan parameter kueri ke nilai tidak ada adalah 2:

  • Kueri akan berjalan, jadi meskipun Anda sudah tahu tidak akan ada hasil, ada sedikit harga kinerja yang harus dibayar
  • Kueri WordPress memiliki 19 'posts_*'kait filter yang berbeda ( 'posts_where',, 'post_join'dll.) Yang berfungsi pada kueri, sehingga Anda tidak pernah dapat memastikan bahwa bahkan pengaturan param yang tidak ada, kueri tidak menghasilkan apa-apa, ORklausa sederhana yang dikembalikan oleh filter membuat sesuatu kembali.

Anda perlu sedikit rutin hardcore untuk memastikan kueri kembali tanpa hasil dan tidak ada (atau sangat minim) masalah kinerja.

Untuk memicu rutinitas itu, Anda bisa menggunakan setiap metode, secara teknis Anda bisa meneruskan argumen apa pun WP_Query, argumen peristiwa yang tidak ada.

Jadi, jika Anda menyukai sesuatu seperti 'force_no_results' => true, Anda dapat menggunakannya seperti ini:

$a = new WP_Query( array( 's' => 'foo', 'force_no_results' => true ) );

dan menambahkan callback yang berjalan pada 'pre_get_posts'yang melakukan kerja keras:

add_action( 'pre_get_posts', function( $q ) {
  if (array_key_exists('force_no_results', $q->query) && $q->query['force_no_results']) {
    $q->query = $q->query_vars = array();
    $added = array();
    $filters = array(
      'where', 'where_paged', 'join', 'join_paged', 'groupby', 'orderby', 'distinct',
      'limits', 'fields', 'request', 'clauses', 'where_request', 'groupby_request',
      'join_request', 'orderby_request', 'distinct_request','fields_request',
      'limits_request', 'clauses_request'
    );
    // remove all possible interfering filter and save for later restore
    foreach ( $filters as $f ) {
      if ( isset($GLOBALS['wp_filter']["posts_{$f}"]) ) {
        $added["posts_{$f}"] = $GLOBALS['wp_filter']["posts_{$f}"];
        unset($GLOBALS['wp_filter']["posts_{$f}"]);
      }
    }
    // be sure filters are not suppressed
    $q->set( 'suppress_filters', FALSE );
    $done = 0;
    // use a filter to return a non-sense request
    add_filter('posts_request', function( $r ) use( &$done ) {
      if ( $done === 0 ) { $done = 1;
        $r = "SELECT ID FROM {$GLOBALS['wpdb']->posts} WHERE 0 = 1";
      }
      return $r;
    });
    // restore any filter that was added and we removed
    add_filter('posts_results', function( $posts ) use( &$done, $added ) {
      if ( $done === 1 ) { $done = 2;
        foreach ( $added as $hook => $filters ) {
          $GLOBALS['wp_filter'][$hook] = $filters;
        }
      }
      return $posts;
    });
  }
}, PHP_INT_MAX );

Apa yang dilakukan kode ini dijalankan 'pre_get_posts'selambat mungkin. Jika argumen 'force_no_results' hadir dalam kueri, maka:

  1. pertama-tama hapus semua kemungkinan filter yang dapat mengganggu kueri, dan simpan di dalam array pembantu
  2. setelah yakin bahwa filter terpicu, tambahkan filter yang mengembalikan permintaan semacam ini: SELECT ID FROM wp_posts WHERE 0 = 1begitu semua filter dihapus, tidak ada kemungkinan permintaan ini diubah dan sangat cepat, dan tidak memiliki hasil pasti
  3. segera setelah kueri ini dijalankan, semua filter asli (jika ada) dipulihkan dan semua kueri berikutnya akan berfungsi seperti yang diharapkan.
gmazzap
sumber