Posso forçar o WP_Query a não retornar resultados?

23

Estou trabalhando em um site com um recurso de pesquisa que permite que os usuários pesquisem várias meta meta. Existe um padrão de pesquisa específico para o qual gostaria de não retornar resultados à força. O WP_Query tecnicamente encontrará resultados no banco de dados, mas eu gostaria de substituir isso de alguma forma para forçá-lo a não retornar resultados para acionar a if( $example->have_posts() )falha.

Existe algum tipo de parâmetro que eu possa passar para o WP_Query 'force_no_results' => trueque o forçará a não retornar resultados?

Brian
fonte
1
Parece que você está pedindo uma implementação já determinada, em vez de perguntar como resolver o problema raiz. Lendo nas entrelinhas, acho que o que você realmente deveria estar se perguntando é: como faço para tornar um padrão de pesquisa específico inquestionável? . Causar o WP_Query()retorno de nenhum resultado pode ou não ser a melhor maneira de responder a essa pergunta. Também pode ser útil se você descrever o padrão de pesquisa que deseja ser inquestionável. Conhecer o padrão de pesquisa pode ajudar a encontrar uma solução.
Chip Bennett

Respostas:

28

Experimentar

'post__in' => array(0)

Simples e direto ao ponto.

David Labbe
fonte
Meu primeiro pensamento foi: isso deve dar errado em algum lugar, mas, ao analisar o código relacionado, isso realmente deve funcionar muito bem. :)
Rarst
5
o zero é muito importante, pois apenas uma matriz vazia retornará as postagens recentes.
Mark Kaplun
Obrigado! Isso resolveu um erro para mim, pois post__inestava retornando postagens quando passou uma matriz vazia ... array(0)funciona muito bem! Isso é estranho, mas na verdade pode ser atribuído a um problema que surgiu no núcleo do WP como um bug, mas foi deixado como está porque muitos desenvolvedores de temas / plugins criaram funcionalidades em torno dele -_- core.trac.wordpress.org/ ticket / 28099
EranSch
3

Curiosamente, não há uma maneira limpa / explícita de curto-circuito WP_Query.

Se for a consulta principal, você pode resolver algo WP->parse_request(), parece haver um do_parse_requestfiltro relativamente recente (3.5) lá.

Mas, por WP_Querysi só, hacks sujos geralmente estão em ordem, como um curto-circuito na consulta SQL adicionando AND 1=0via posts_wherefiltro, etc.

Rarst
fonte
2
Obrigado pela informação. Era um loop secundário btw. E acabei fazendo um hack sujo, como o "post_type" => "break_loop"que é um tipo de postagem inexistente.
Brian
2

Os problemas ao definir um parâmetro de consulta para um valor inexistente são 2:

  • A consulta será executada. Portanto, mesmo se você já souber que não haverá resultados, há um pequeno preço de desempenho a pagar
  • As consultas do WordPress têm 19 'posts_*'ganchos de filtro diferentes ( 'posts_where', 'post_join'etc.) que atuam na consulta, para que você nunca tenha certeza de que, mesmo definindo parâmetros inexistentes, a consulta não retorne resultados, uma simples ORcláusula retornada por um filtro faz com que retorne algo.

Você precisa de uma rotina um pouco incondicional para garantir que uma consulta não retorne resultado e que não haja problema de desempenho (ou muito mínimo).

Para acionar essa rotina, você pode usar todos os métodos, tecnicamente pode passar qualquer argumento para WP_Query, argumentos de evento que não existem.

Então, se você gosta de algo assim 'force_no_results' => true, pode usá-lo da seguinte maneira:

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

e adicione um retorno de chamada em execução 'pre_get_posts'que faça o trabalho duro:

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

O que esse código faz é executado o 'pre_get_posts'mais tarde possível. Se o argumento 'force_no_results' estiver presente na consulta, então:

  1. primeiro remova todos os filtros possíveis que possam interferir na consulta e armazene-os em uma matriz auxiliar
  2. depois de ter certeza de que o filtro foi acionado, filtro adda que retorna esse tipo de solicitação: SELECT ID FROM wp_posts WHERE 0 = 1depois que todos os filtros são removidos, não há possibilidade de que essa consulta seja alterada e seja muito rápida e sem resultados.
  3. imediatamente após a execução dessa consulta, todos os filtros originais (se houver) são restaurados e todas as consultas subseqüentes funcionarão conforme o esperado.
gmazzap
fonte