Puis-je forcer WP_Query à ne renvoyer aucun résultat?

20

Je travaille sur un site Web doté d'une fonctionnalité de recherche qui permet aux utilisateurs d'effectuer une recherche dans de nombreuses méta-publications. Il existe un modèle de recherche spécifique pour lequel je souhaite ne renvoyer aucun résultat. WP_Query, techniquement, trouvera des résultats dans la base de données, mais je voudrais le remplacer pour le forcer à ne renvoyer aucun résultat, ce qui entraînera l’échec de if( $example->have_posts() ) .

Existe-t-il une sorte de paramètre que je peux transmettre à WP_Query, tel que 'force_no_results' => true , qui l'obligera à ne renvoyer aucun résultat?

    
posée Brian 08.04.2014 - 22:01

3 réponses

25

Essayez

'post__in' => array(0)

Simple et précis.

    
réponse donnée David Labbe 09.04.2014 - 03:39
3

Curieusement, il n’existe aucun moyen propre / explicite de court-circuiter WP_Query .

S'il s'agit d'une requête main , vous pourriez trouver une solution autour de WP->parse_request() , il semble y avoir un filtre relativement récent (3.5) do_parse_request .

Mais pour WP_Query lui-même, les hacks sont corrects, par exemple court-circuiter une requête SQL en ajoutant AND 1=0 via posts_where filter, etc.

    
réponse donnée Rarst 08.04.2014 - 22:46
2

Les problèmes pour définir un paramètre de requête sur une valeur non constante sont 2:

  • La requête s'exécutera. Ainsi, même si vous savez déjà qu'il n'y aura aucun résultat, il y a un petit prix de performance à payer
  • Les requêtes WordPress ont 19 crochets de filtre 'posts_*' ( 'posts_where' , 'post_join' , etc.) différents qui agissent sur la requête. Vous ne pouvez donc jamais être sûr que même si vous définissez une param non-inexistante, la requête ne renvoie aucun résultat. La clause OR retournée par un filtre fait retourner quelque chose.

Vous avez besoin d'une petite routine hardcore pour être sûr , une requête ne renvoie aucun résultat et il n'y a aucun problème de performances (ou très minime).

Pour déclencher cette routine, vous pouvez utiliser toutes les méthodes. Techniquement, vous pouvez passer n'importe quel argument à WP_Query , des arguments d'événement qui n'existent pas.

Donc, si vous aimez quelque chose comme 'force_no_results' => true , vous pouvez l'utiliser comme suit:

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

et ajoutez un rappel en cours d'exécution sur 'pre_get_posts' qui fait le travail dur:

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

Ce code ne s'exécute que le plus tard possible sur 'pre_get_posts' . Si l'argument 'force_no_results' est présent dans la requête, alors:

  1. commence par supprimer tous les filtres susceptibles d'interférer avec la requête, puis les stocke dans un tableau d'assistance
  2. après vous être assuré que les filtres sont déclenchés, ajoutez un filtre qui renvoie ce type de requête: SELECT ID FROM wp_posts WHERE 0 = 1 une fois tous les filtres supprimés, il n'y a plus de possibilité que cette requête soit modifiée et elle est très rapide, et n'a aucun résultat à coup sûr
  3. immédiatement après l'exécution de cette requête, tous les filtres d'origine (le cas échéant) sont restaurés et toutes les requêtes suivantes fonctionneront comme prévu.
réponse donnée gmazzap 09.04.2014 - 05:26

Lire d'autres questions sur les étiquettes