¿Puedo forzar a WP_Query a que no devuelva ningún resultado?

23

Estoy trabajando en un sitio web con una función de búsqueda que permite a los usuarios buscar en muchas publicaciones meta. Hay un patrón de búsqueda específico para el que me gustaría no devolver ningún resultado por la fuerza. El WP_Query técnicamente encontrará resultados en la base de datos, pero me gustaría anular eso de alguna manera para obligarlo a no devolver ningún resultado que provoque if( $example->have_posts() )que falle.

¿Hay algún tipo de parámetro que pueda pasar a WP_Query como 'force_no_results' => trueque lo obligará a no devolver resultados?

Brian
fuente
1
Parece que está solicitando una implementación ya determinada, en lugar de preguntar cómo resolver el problema raíz. Leyendo entre líneas, creo que lo que realmente debería preguntarse es: ¿cómo puedo hacer que un patrón de búsqueda específico no se pueda consultar? . Causar WP_Query()no devolver resultados puede o no ser la mejor manera de responder a esa pregunta. También podría ser útil si describiera el patrón de búsqueda que desea que no se pueda consultar. Conocer el patrón de búsqueda podría ayudar a descubrir una solución.
Chip Bennett

Respuestas:

28

Tratar

'post__in' => array(0)

Simple y al grano.

David Labbe
fuente
Lo primero que pensé fue: esto tiene que salir mal en alguna parte, pero al pasar por alto el código relacionado, esto debería funcionar bastante bien. :)
Rarst
55
el cero es muy importante ya que solo una matriz vacía devolverá las publicaciones recientes.
Mark Kaplun
¡Gracias! Esto resolvió un error para mí, ya que post__inestaba devolviendo publicaciones cuando pasaba una matriz vacía ... ¡ array(0)funciona muy bien! Esto es extraño, pero en realidad se puede rastrear a un problema que surgió en el núcleo de WP como un error, pero luego se dejó como está porque demasiados desarrolladores de temas / complementos crearon una
EranSch
3

Curiosamente no hay una forma limpia / explícita de cortocircuito WP_Query.

Si se trata de una consulta principal con la que puede resolver algo WP->parse_request(), parece haber un do_parse_requestfiltro relativamente reciente (3.5) allí.

Pero por WP_Querysí mismos, los hacks sucios generalmente están en orden, como el cortocircuito de la consulta SQL al agregar a AND 1=0través de un posts_wherefiltro, etc.

Rarst
fuente
2
Gracias por la info. Fue un bucle secundario por cierto. Y acabé haciendo un truco sucio como el "post_type" => "break_loop"que es un tipo de publicación inexistente.
Brian
2

Los problemas al establecer un parámetro de consulta en un valor inexistente son 2:

  • La consulta se ejecutará, por lo que incluso si ya sabe que no habrá resultados, debe pagar un pequeño precio de rendimiento
  • Consultas WordPress tiene 19 diferentes 'posts_*'enlaces de filtros ( 'posts_where', 'post_join', etc ..) que actúan sobre la consulta, por lo que nunca puede estar seguro de que incluso el establecimiento de parámetro unexistent la consulta devuelve ningún resultado, un simple ORcláusula devuelto por un filtro devolverlo es algo.

Necesita una rutina un poco dura para asegurarse de que una consulta no devuelva ningún resultado y no haya un problema de rendimiento (o muy mínimo).

Para activar esa rutina, puede usar todos los métodos, técnicamente puede pasar cualquier argumento a WP_Query, argumentos de evento que no existan.

Entonces, si te gusta algo como 'force_no_results' => true, puedes usarlo así:

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

y agrega una devolución de llamada en ejecución 'pre_get_posts'que hace el trabajo 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 );

Lo que hace este código se ejecuta lo 'pre_get_posts'más tarde posible. Si el argumento 'force_no_results' está presente en la consulta, entonces:

  1. primero elimine todos los filtros posibles que puedan interferir con la consulta y almacénelos dentro de una matriz auxiliar
  2. después de asegurarse de que se activa el filtro, agregue un filtro que devuelva este tipo de solicitud: SELECT ID FROM wp_posts WHERE 0 = 1una vez que se eliminan todos los filtros, no hay posibilidades de que esta consulta cambie y es muy rápida, y no tiene ningún resultado seguro
  3. inmediatamente después de ejecutar esta consulta, todos los filtros originales (si los hubiera) se restauran y todas las consultas posteriores funcionarán como se esperaba.
gmazzap
fuente