ฉันสามารถบังคับให้ WP_Query ส่งคืนผลลัพธ์ไม่ได้หรือไม่


23

ฉันกำลังทำงานกับเว็บไซต์ที่มีคุณสมบัติการค้นหาที่ช่วยให้ผู้ใช้สามารถค้นหาเมตาโพสต์ได้มากมาย มีรูปแบบการค้นหาเฉพาะที่ฉันต้องการบังคับให้ส่งคืนผลลัพธ์ไม่ได้ WP_Query ในทางเทคนิคจะค้นหาผลลัพธ์ในฐานข้อมูล แต่ฉันต้องการแทนที่อย่างใดเพื่อบังคับให้ส่งคืนผลลัพธ์ที่ไม่ก่อให้เกิดการif( $example->have_posts() )ล้มเหลว

มีพารามิเตอร์บางประเภทที่ฉันสามารถส่งไปยัง WP_Query เช่น'force_no_results' => trueนั้นจะบังคับให้ส่งคืนผลลัพธ์หรือไม่?


1
ดูเหมือนว่าคุณกำลังขอให้มีการใช้งานที่กำหนดไว้แล้วแทนที่จะถามว่าจะแก้ไขปัญหารากได้อย่างไร การอ่านระหว่างบรรทัดฉันคิดว่าสิ่งที่คุณควรถามจริงๆคือฉันจะสร้างรูปแบบการค้นหาที่เฉพาะเจาะจงได้อย่างไร . สาเหตุที่ทำให้WP_Query()ไม่มีผลลัพธ์อาจเป็นวิธีที่ดีที่สุดในการตอบคำถามนั้นหรือไม่ก็ได้ นอกจากนี้ยังอาจเป็นประโยชน์หากคุณต้องการอธิบายรูปแบบการค้นหาที่คุณต้องการให้ไม่สามารถค้นหาได้ การรู้รูปแบบการค้นหาอาจช่วยแก้ไขปัญหาได้
Chip Bennett

คำตอบ:


28

ลอง

'post__in' => array(0)

ง่ายและตรงประเด็น


ความคิดแรกของฉันคือ - สิ่งนี้จะผิดพลาดไปบ้าง แต่จากการอ่านรหัสที่เกี่ยวข้องสิ่งนี้น่าจะใช้ได้จริง :)
Rarst

5
ศูนย์มีความสำคัญมากเนื่องจากอาเรย์ที่ว่างเปล่าจะส่งคืนโพสต์ล่าสุด
Mark Kaplun

ขอบคุณ! สิ่งนี้แก้ไขข้อผิดพลาดสำหรับฉันpost__inเมื่อโพสต์กลับเมื่อผ่านอาร์เรย์ที่ว่างเปล่า ... ใช้array(0)งานได้ดี! นี่เป็นเรื่องแปลก แต่จริง ๆ แล้วมันสามารถสืบย้อนไปถึงปัญหาที่เกิดขึ้นใน WP core เป็นข้อผิดพลาด แต่ถูกทิ้งไว้ตามที่เป็นเพราะนักพัฒนาธีม / ปลั๊กอินมากเกินไปสร้างฟังก์ชันการทำงานรอบ ๆ มัน -_- core.trac.wordpress.org/ ตั๋ว / 28099
EranSch

3

อยากรู้อยากเห็นไม่มีการทำความสะอาด / WP_Queryวิธีการที่ชัดเจนในการลัดวงจร

หากเป็นคำถามหลักที่คุณอาจแก้ไขบางสิ่งบางอย่างWP->parse_request()ดูเหมือนว่าจะมีdo_parse_requestตัวกรอง(3.5) ล่าสุด

แต่สำหรับWP_Queryแฮ็คที่สกปรกมักจะเป็นไปตามลำดับเช่นคิวรี SQL แบบลัดวงจรโดยการเพิ่มAND 1=0ผ่านposts_whereตัวกรอง ฯลฯ


2
ขอบคุณสำหรับข้อมูล. มันเป็นลูปรอง btw และฉันก็ลงเอยด้วยการทำแฮ็คสกปรก"post_type" => "break_loop"ซึ่งเป็นประเภทโพสต์ที่ไม่มีอยู่จริง
ไบรอัน

2

ปัญหาในการตั้งค่าพารามิเตอร์การสืบค้นให้เป็นค่าที่ไม่มีอยู่คือ 2:

  • ข้อความค้นหาจะทำงานดังนั้นแม้ว่าคุณจะรู้อยู่แล้วว่าจะไม่มีผลลัพธ์ที่จะต้องจ่ายตามประสิทธิภาพเล็กน้อย
  • คำสั่ง WordPress มี 19 แตกต่างกัน'posts_*'ตะขอตัวกรอง ( 'posts_where', 'post_join'ฯลฯ .. ) ว่าการกระทำในแบบสอบถามเพื่อให้คุณไม่สามารถมั่นใจได้ว่าแม้กระทั่งการตั้งค่าพารามิเตอร์ unexistent แบบสอบถามกลับไม่มีผลง่ายORประโยคกลับโดยตัวกรองการทำบางสิ่งบางอย่างกลับมา

คุณต้องการรูทีนฮาร์ดคอร์เล็กน้อยเพื่อให้แน่ใจว่าแบบสอบถามไม่ส่งคืนผลลัพธ์และไม่มีปัญหาประสิทธิภาพการทำงาน (หรือขั้นต่ำมาก)

ในการทริกเกอร์รูทีนนั้นคุณสามารถใช้ทุกวิธีโดยทางเทคนิคคุณสามารถส่งอาร์กิวเมนต์ใด ๆ ไปยังWP_Queryอาร์กิวเมนต์ของเหตุการณ์ที่ไม่มีอยู่

ดังนั้นถ้าคุณชอบอะไร'force_no_results' => trueคุณสามารถใช้มันได้:

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

และเพิ่มการเรียกกลับที่ทำงาน'pre_get_posts'อย่างหนัก:

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

รหัสนี้ทำงานได้'pre_get_posts'ช้าเท่าที่จะเป็นไปได้ หากอาร์กิวเมนต์ 'force_no_results' มีอยู่ในแบบสอบถามแล้ว:

  1. ก่อนอื่นให้ลบตัวกรองที่เป็นไปได้ทั้งหมดที่สามารถรบกวนแบบสอบถามและเก็บไว้ในอาร์เรย์ผู้ช่วย
  2. หลังจากตรวจสอบให้แน่ใจว่ามีการเรียกใช้ตัวกรองแล้วตัวกรอง adda ที่ส่งคืนคำขอประเภทนี้: SELECT ID FROM wp_posts WHERE 0 = 1เมื่อตัวกรองทั้งหมดถูกลบออกไปแล้วจะไม่มีความเป็นไปได้ที่แบบสอบถามนี้จะถูกเปลี่ยนและรวดเร็วมากและไม่มีผลลัพธ์ที่แน่นอน
  3. ทันทีหลังจากเรียกใช้คิวรีนี้ตัวกรองดั้งเดิมทั้งหมด (หากมี) จะถูกกู้คืนและแบบสอบถามที่ตามมาทั้งหมดจะทำงานได้ตามที่คาดไว้
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.