Могу ли я заставить 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фильтр и т. Д.

Rarst
источник
2
Спасибо за информацию. Это был вторичный цикл между прочим. И я только что закончил тем, что делал грязный хак, как, например "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. После того, как убедитесь, что фильтр запущен, добавьте фильтр, который возвращает этот вид запроса: SELECT ID FROM wp_posts WHERE 0 = 1после того, как все фильтры удалены, нет возможности изменить этот запрос, и он очень быстрый и не дает никакого результата наверняка.
  3. сразу после выполнения этого запроса все исходные фильтры (если они были) восстанавливаются, и все последующие запросы будут работать как положено.
Gmazzap
источник