Kann ich WP_Query zwingen, keine Ergebnisse zurückzugeben?

23

Ich arbeite an einer Website mit einer Suchfunktion, mit der Benutzer viele Post-Metas durchsuchen können. Es gibt ein bestimmtes Suchmuster, für das ich keine Ergebnisse erzwingen möchte. Die WP_Query findet technisch gesehen Ergebnisse in der Datenbank, aber ich möchte das irgendwie überschreiben, um sie dazu zu zwingen, keine Ergebnisse zurückzugeben, um das Fehlschlagen auszulösen if( $example->have_posts() ).

Gibt es eine Art von Parameter, den ich an WP_Query übergeben kann 'force_no_results' => true, der es zwingt, keine Ergebnisse zurückzugeben?

Brian
quelle
1
Es scheint, als würden Sie nach einer bereits festgelegten Implementierung fragen, anstatt zu fragen, wie Sie das Grundproblem lösen können. Wenn Sie zwischen den Zeilen lesen , denken Sie, was Sie wirklich fragen sollten: Wie mache ich ein bestimmtes Suchmuster unabfragbar? . Das WP_Query()Zurückgeben von Ergebnissen kann der beste Weg sein, diese Frage zu beantworten. Es kann auch hilfreich sein, wenn Sie das Suchmuster beschreiben , das Sie nicht abfragen möchten. Wenn Sie das Suchmuster kennen, können Sie möglicherweise eine Lösung finden.
Chip Bennett

Antworten:

28

Versuchen

'post__in' => array(0)

Einfach und auf den Punkt.

David Labbe
quelle
Mein erster Gedanke war - das muss irgendwo schief gehen, aber nach dem Überfliegen des zugehörigen Codes sollte das eigentlich recht gut funktionieren. :)
Rarst
5
Die Null ist sehr wichtig, da nur ein leeres Array die letzten Beiträge zurückliefert.
Mark Kaplun
Vielen Dank! Dies löste einen Fehler für mich, da post__inBeiträge zurückgegeben wurden, wenn ein leeres Array übergeben wurde ... array(0)funktioniert großartig! Das ist seltsam, aber es kann tatsächlich auf ein Problem zurückgeführt werden, das im WP-Kern als Fehler aufgetreten ist, aber dann so belassen wurde, wie es ist, weil zu viele Theme- / Plugin-Entwickler Funktionen darum herum erstellt haben. -_- core.trac.wordpress.org/ ticket / 28099
EranSch
3

Seltsamerweise gibt es keinen sauberen / expliziten Weg zum Kurzschließen WP_Query.

Wenn es sich um eine Hauptabfrage handelt, mit der Sie möglicherweise etwas anfangen WP->parse_request(), scheint es dort einen relativ neuen (3.5) do_parse_requestFilter zu geben.

Aber für WP_Querysich sind schmutzige Hacks normalerweise in Ordnung, wie das Kurzschließen von SQL-Abfragen durch Hinzufügen AND 1=0über posts_whereFilter usw.

Rarst
quelle
2
Danke für die Information. Es war übrigens eine Nebenschleife. Und ich habe gerade einen schmutzigen Hack gemacht, wie "post_type" => "break_loop"er nicht existiert.
Brian
2

Die Probleme beim Festlegen eines Abfrageparameters auf einen nicht vorhandenen Wert sind 2:

  • Die Abfrage wird ausgeführt, sodass auch wenn Sie bereits wissen, dass keine Ergebnisse vorliegen, ein geringer Preis für die Leistung zu zahlen ist
  • In WordPress-Abfragen gibt es 19 verschiedene 'posts_*'Filter-Hooks ( 'posts_where', 'post_join'usw.), die auf Abfragen einwirken. Sie können also nie sicher sein, dass eine einfache ORKlausel, die von einem Filter zurückgegeben wird, etwas zurückgibt, wenn Sie nicht vorhandene Parameter für die Abfrage zurückgeben .

Sie benötigen ein wenig Hardcore- Routine, um sicherzustellen , dass eine Abfrage kein Ergebnis zurückgibt und kein (oder nur sehr geringfügiges) Leistungsproblem vorliegt.

Um diese Routine auszulösen, können Sie jede Methode verwenden. Technisch gesehen können Sie jedes Argument an WP_QueryEreignisargumente übergeben, das nicht vorhanden ist.

Wenn Ihnen also etwas gefällt 'force_no_results' => true, können Sie es folgendermaßen verwenden:

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

und fügen Sie einen Rückruf hinzu, der ausgeführt wird und 'pre_get_posts'die harte Arbeit erledigt :

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

Was dieser Code tut, wird 'pre_get_posts'so spät wie möglich ausgeführt. Wenn das Argument 'force_no_results' in der Abfrage vorhanden ist, gilt Folgendes:

  1. Entfernen Sie zunächst alle möglichen Filter, die die Abfrage beeinträchtigen können, und speichern Sie sie in einem Hilfsarray
  2. Nachdem Sie sicher sind, dass der Filter ausgelöst wurde, fügen Sie einen Filter hinzu, der diese Art von Anforderung zurückgibt: SELECT ID FROM wp_posts WHERE 0 = 1Wenn alle Filter entfernt wurden, gibt es keine Möglichkeiten, diese Abfrage zu ändern. Sie ist sehr schnell und hat mit Sicherheit kein Ergebnis
  3. Unmittelbar nachdem diese Abfrage ausgeführt wurde, werden alle ursprünglichen Filter (sofern vorhanden) wiederhergestellt und alle nachfolgenden Abfragen funktionieren wie erwartet.
gmazzap
quelle