Чи можу я змусити WP_Query не повернути результатів?


23

Я працюю над веб-сайтом із функцією пошуку, яка дозволяє користувачам здійснювати пошук у багатьох метах публікації. Існує конкретна схема пошуку, за яку я б хотів насильно повернути результати. Технічно WP_Query знайде результати в базі даних, але я хотів би якось змінити це, щоб змусити його повернути відсутні результати, щоб викликати if( $example->have_posts() )помилку.

Чи є якийсь параметр, який я можу передати WP_Query, як такий, 'force_no_results' => trueщо змусить його не повертати результатів?


1
ІТ здається, що ви вимагаєте вже визначеної реалізації, а не запитуєте, як вирішити кореневу проблему. Читаючи між рядками, я думаю, що ви насправді повинні запитати: як я можу зробити конкретний шаблон пошуку незрівнянним? . Причина WP_Query()повернення результатів не може бути, а може бути і не найкращим способом відповісти на це питання. Це також може бути корисним, якщо ви опишете шаблон пошуку, який ви хочете отримати незрівнянним. Знання структури пошуку може допомогти вирішити рішення.
Чіп Беннетт

Відповіді:


28

Спробуйте

'post__in' => array(0)

Просте і суттєве.


Перша моя думка полягала в тому, що це має кудись піти не так, але від зневоднення відповідного коду це насправді має працювати досить добре. :)
Рарст

5
нуль дуже важливий, оскільки просто порожній масив поверне останні повідомлення.
Марк Каплун

Спасибі! Це вирішило помилку для мене, як post__inповертало повідомлення, коли проходив порожній масив ... array(0)чудово працює! Це дивно, але насправді це може бути простежено до проблеми, яка виникла в ядрі WP як помилка, але тоді її залишили як - це тому, що надто багато розробників теми / плагінів побудували навколо неї функціонал -_- core.trac.wordpress.org/ квиток / 28099
EranSch

3

Цікаво, що немає чіткого / явного способу короткого замикання WP_Query.

Якщо це основний запит, ви можете щось розробити WP->parse_request(), мабуть, є порівняно недавній (3.5) do_parse_requestфільтр.

Але WP_Queryсамі по собі брудні хаки зазвичай в порядку, наприклад, короткий замикання SQL запиту шляхом додавання AND 1=0через posts_whereфільтр тощо.


2
Дякуємо за інформацію. Це була вторинна петля btw. І я щойно закінчив робити брудний хакер, "post_type" => "break_loop"який є неіснуючим постом.
Брайан

2

Проблеми щодо встановлення параметра запиту на неіснуюче значення: 2:

  • Запит буде запущений, тому навіть якщо ви вже знаєте, що результатів не буде, потрібно заплатити невелику ціну продуктивності
  • У WordPress-запитах є 19 різних 'posts_*'гаків фільтрів ( 'posts_where', 'post_join'і т. Д.), Які діють на запит, тому ви ніколи не можете бути впевнені, що навіть якщо встановити неіснуючий параметр, запит не поверне результатів, простий 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. одразу після запуску цього запиту всі оригінальні фільтри (якщо такі були) відновлені, і всі наступні запити працюватимуть, як очікувалося.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.