Warum gibt WP_Query :: is_date () false zurück, wenn das Argument ‘date_query’ gesetzt ist?

WordPress 3.7 führte das Argument ‘date_query’ für WP_Query .

Das ist sehr nützlich und erlaubt sehr komplexe WP_Query Abfragen, jedoch passiert etwas Seltsames, wenn man bedingte WP_Query Methoden für Abfragen verwendet, die dieses Argument verwenden.

Beispiel:

 $args = array( 'tax_query'=> array( 'relation' => 'AND', array( 'taxonomy' => 'category', 'field' => 'slug', 'terms' => 'uncategorized' ), array( 'taxonomy' => 'post_tag', 'field' => 'slug', 'terms' => array('foo', 'bar') ) ), 'date_query' => array( array( 'year' => $today["year"], 'month' => $today["mon"], 'day' => $today["mday"], ) ) ); $query = new WP_Query( $args ); 

Die Abfrage sollte Posts zurückgeben, die heute veröffentlicht wurden und die Kategorie “nicht kategorisiert” oder “foo” und “bar” enthalten. Und es tut so weit so gut.

Betrachten Sie nun die folgenden bedingten Methoden:

 $query->is_archive(); // returns true, as guessable $query->is_category(); // returns true, as guessable $query->is_tag(); // returns true, as guessable 

aber

 $query->is_date(); // returns false $query->is_day(); // returns false $query->is_month(); // returns false $query->is_year(); // returns false 

Ich dachte, dass das Problem durch die Tatsache verursacht werden kann, dass ich “tax_query” und “date_query” mixe, aber das ist nicht das Problem, Beweis:

 $args = array( 'date_query' => array( array( 'year' => $today["year"], 'month' => $today["mon"], 'day' => $today["mday"], ) ) ); $query = new WP_Query( $args ); $query->is_date(); // returns false $query->is_day(); // returns false $query->is_month(); // returns false $query->is_year(); // returns false $query->is_archive(); // returns false this time 

Ist das ein Fehler oder fehlt mir etwas? (Ich habe WP Trac gesucht, aber nichts gefunden).

Solutions Collecting From Web of "Warum gibt WP_Query :: is_date () false zurück, wenn das Argument ‘date_query’ gesetzt ist?"

Die Werte, die durch die is_date() , is_day(), usw. abgerufen werden is_day(), werden innerhalb der parse_query Methode gesetzt und sie scheinen wirklich für die Hauptabfrage gedacht zu sein, egal ob explizit angegeben (beabsichtigt) oder nicht. Der Code analysiert die öffentlichen Abfragevariablen, um diese Einstellungen zu bestimmen .

Meine Interpretation ist, dass diese Werte nicht wirklich für sekundäre Abfragen gedacht sind und auch für sekundäre Abfragen nicht sehr sinnvoll sind. Sie haben gerade die Abfrage ausgeführt, Sie wissen, dass es sich um eine Abfrage Datum / Steuern / was auch immer handelt. Dieser Teil muss nicht durch Analyse der Abfragevariablen für Sie bestimmt werden.

Um etwas tiefer zu gehen, würde ich sagen, dass WP_Query ein wenig schizophren ist. Es analysierte die Anfrage, um zu bestimmen, welche Seite geladen werden sollte, anstatt nur ein Werkzeug zu sein, um die database nach Posts abzufragen. Es macht zwei Jobs statt einer, die meiner Meinung nach schlechtes Design ist. Ich denke, eindeutiger Code sollte die Anfrage analysieren und dann Argumente an WP_Query . Vielleicht ist das nur ich.

Ist es ein Fehler? Ich würde es so nennen, zumindest “komisches Design”. Wenn WP_Query beide Jobs WP_Query soll, sollte es zumindest die classnvariablen konsistent setzen oder die class in zwei classn mit jeweils einem einzigen Zweck aufteilen. Natürlich kann ich etwas nicht als “Bug” deklarieren oder nicht 🙂

Hinweis: Dies ist nur eine Ergänzung zu @s_ha_dum Antwort (die von den upvotes wahrscheinlich nördlich von diesem sein).

Alle “Conditional Tags” / Abfragemethoden, die den Status bestimmen, z

  • is_date
  • is_day
  • is_hour
  • is_nanosecond

… sind alle alt, also neigen die Menschen dazu, ihre Existenz zu vergessen. Und seien wir ehrlich: Sie waren nie sehr beliebt. Wie viele stündliche Archive sind Ihnen bei Ihren digitalen Reisen in den Interwebs begegnet?

Was aber interessant ist und oft benötigt wird, sind Datumsbereiche, die als völlig unabhängig von Datum is_ interpretiert werden können – und das ist, was die Bedingungen sind. So könnte ich mir vorstellen, dass diejenigen, die die date_query Teile geschrieben haben, genau gesehen keine Verbindung zwischen date_query oder zeitbasierten Archiven und den entsprechenden Abfragen gesehen haben.

Stellen Sie sich die folgende Situation vor:

WTF! Warum zum Teufel kickt meine stündliche Archivvorlage, wenn alles was ich wollte, Beiträge waren, paginiert nach Woche auf meiner Titelseite?

Auch wenn viel core oft “Design by Accident” zu sein scheint, ist dieser tatsächlich nicht. Sehen Sie sich die tax_query Teile von WP_Query::get_posts() :

 $this->parse_tax_query( $qv ); foreach ( $this->tax_query->queries as $tax_query ) { if ( 'NOT IN' != $tax_query['operator'] ) { switch ( $tax_query['taxonomy'] ) { case 'category': $this->is_category = true; break; case 'post_tag': $this->is_tag = true; break; default: $this->is_tax = true; } } } unset( $tax_query ); 

Lass mich dich mit zwei Fragen verlassen:

  1. Was bedeutet das obige Snippet?
  2. Willst du das wirklich?

Ich werde versuchen, etwas Ordnung zu schaffen, und alle meine Gedanken auf eine Antwort konzentrieren, anstatt die 2 guten Antworten von @s_ha_dum und @kaiser zu kommentieren (ich habe beide hochgestuft).

Zuerst müssen wir angeben, dass es in WordPress zwei Arten von Abfragen gibt: Haupt- und Zweitanfragen .

Beide sind Instanzen derselben class, WP_Query erste Unterschied besteht jedoch darin, dass das Hauptabfrageobjekt von WordPress installiert und in der globalen Variablen $wp_query wird. Alle sekundären Abfragen müssen durch benutzerdefinierten Code instanziiert werden.

Aber es gibt einen weiteren großen Unterschied: Um Posts zu erhalten, muss WP_Query einige Argumente erhalten: In der Hauptabfrage werden diese Argumente in sekundären Abfragen von der URL übernommen, Argumente müssen explizit an den Konstruktor oder an get_posts Methode get_posts werden.

Eine direkte Konsequenz von vorherigem ist, dass für die Hauptabfrage die Abfrageargumente, die von URL stammen, nur skalare Variablen sein können : Strings, Integer und Booleans: Abfrageargumente, deren Werte Arrays sind, können nicht über URLs gesetzt werden Skalare Variable wird aus Abfrageargumenten entfernt, die über URLs festgelegt werden .

Also haben wir auch zwei Arten von Abfrageargumenten, “skalare Argumente” und “Array-Argumente”.

WordPress verwendet skalare Argumente zum Einrichten von Vorlagen-Tags. Infotext WordPress Workflow ist:

  1. Richten Sie Abfrageargumente mithilfe von URL-Argumenten ein
  2. Konfigurieren Sie bedingte Vorlageneigenschaften (alle is_* ) im globalen $wp_query Objekt
  3. Bekommen Sie die Beiträge basierend auf Abfrageargumenten
  4. Verwenden Sie diese bedingten Vorlageneigenschaften, um eine bestimmte Vorlage zu laden

Bemerkenswert ist, dass selbst wenn die Verwendung von URL nicht möglich ist, nicht-skalare Argumente zu setzen, es möglich ist, den 'pre_get_posts' zu verwenden 'pre_get_posts' damit die Hauptabfrage nicht-skalare Variablen wie tax_query , meta_query , date_query usw. verwendet.

Aber 'pre_get_posts' läuft zwischen # 3 und # 4 im oben beschriebenen Workflow. Selbst wenn es möglich ist, array-basierte Abfrageargumente zu verwenden, sind die bedingten Template-Eigenschaften bereits eingerichtet, also einfach mit einer tax_query oder einem anderen nicht-skalaren Abfrageargument Innerhalb von pre_get_posts wirken sich die bedingten Tags der Vorlage (und damit auch die geladene Vorlage) nicht aus, es sei denn, man setzt explizit is_* properties:

 add_action( 'pre_get_posts', function( $query ) { if ( $query->is_main_query() && ! is_admin() ) { $tax_query = array ( array( 'taxonomy' => 'category', 'field' => 'slug', 'terms' => 'foo') ); // this will affect query, but will NOT affect the template loaded $query->query_vars['tax_query'] = $tax_query; // this will affect the template loaded, instead $query->is_category = TRUE; } } ); 

Das scheint logisch und legitim zu sein, dass nicht-skalare Abfrageargumente wie 'date_query' nicht zum Setzen von Template-Tags verwendet werden. Daher stellt sich die Frage, warum WordPress-Argumente tax_query analysieren, auch wenn sie keine Auswirkungen auf Templates haben.

Auch wenn diese Frage an Core-Entwickler gestellt werden sollte, habe ich eine Idee.

Hinweis: Die nächsten 2 Codeschnipsel sind schlecht, hier nur für den Proof of Concept: Tu das nicht zu Hause.

 add_action( 'template_redirect', function() { $args = array( 'tax_query' => array( array( 'taxonomy' => 'category', 'terms' => array( 16, 17 ) ) ) ); $GLOBALS['wp_query'] = new WP_Query( $args ); } ); 

Im vorherigen Code habe ich die globale wp_query durch eine andere Abfrage ersetzt, die eine Steueranfrage verwendet. Es kann seltsam erscheinen, aber es funktioniert wie erwartet, und die geladene Vorlage ist category.php weil WordPress Schablonentags für 'tax_query' (in Fakten und $GLOBALS['wp_query']->is_category() wird true ).

Wenn ich dasselbe mit einer 'date_query' :

 add_action( 'template_redirect', function() { $args = array( 'date_query' => array( array( 'month' => 3, 'year' => 2014 ) ) ); $GLOBALS['wp_query'] = new WP_Query( $args ); } ); 

Die Posts werden erwartungsgemäß abgerufen (ab März 2014), aber das geladene Template wird nicht date.php und $GLOBALS['wp_query']->is_date() wird false .

Meine Vermutung – und das ist nur eine Vermutung – ist, dass Core-Devs in älterem Code über die Möglichkeit nachgedacht haben, das globale $wp_query Objekt mit einem nicht-skalaren Argument zu überschreiben und damit die Template-Hierarchie in diesem Fall funktionieren zu lassen. Aber in moderneren Code (und “date_query” erscheinen nur auf WP 3.7) sorgen sich Core-Entwickler nicht darum, weil sie wahrscheinlich dachten, dass es keinen Grund gibt, sich über schlechte Praktiken Sorgen zu machen …

Im Wesentlichen ist für corefunktionen nicht seltsam, dass date_query keine bedingten Eigenschaften für die Vorlage festlegt, aber seltsam ist, dass tax_query tut.

Nur zwei zusätzliche Notizen.

Betrachtet man die Vorlagenhierarchie , haben einige bedingte Schablonen-Tags keine Auswirkungen, zB is_time und viele andere haben keinen Einfluss auf die Vorlagenauswahl.

Also, was ist die Nützlichkeit von bedingten Template-Tags, die sich nicht auf die Template-Auswahl auswirken?

Wenn wir antworten: “none”, dann müssen wir zugeben, dass sie nur aus einem historischen oder mysteriösen Grund da sind, ansonsten, wenn ein bedingtes Tag nützlich ist, auch wenn es die Template-Auswahl nicht beeinflusst, müssen wir zugeben, dass es nützlich sein wird Wenn WP bedingte Eigenschaften für alle nicht skalaren Argumente festlegen würde und nicht nur für 'tax_query' .

Außerdem verwende ich manchmal in meinem Code meine eigene class, die WP_Query ( und ich bin nicht die einzige ). Auch wenn in den meisten Fällen die Verwendung von benutzerdefinierten WP_Query classn für Sekundärabfragen gilt, ist es möglich, dass man sie auch für die Hauptabfrage verwenden möchte (weit davon entfernt, unmöglich zu sein, weil es nur darum geht, eine globale Variable zu überschreiben).

Sicher ist eine sehr schlechte Praxis, $wp_query überschreiben, nachdem bereits Posts abgefragt wurden, aber wenn man einen frühen Hook wie 'setup_theme' , dann ist global $wp_query nur ein leeres Objekt und kann ohne $wp_query überschrieben werden. WP_Query Hauptobjekt WP_Query anpassen, können Sie die Verwendung von nicht skalaren Argumenten für die Hauptabfrage ermöglichen und diese erst festlegen, bevor die Eigenschaften der bedingten Vorlage festgelegt werden. In diesem Fall wäre es nicht sinnvoll, dass WP_Query alle nicht skalaren Argumente analysiert und die bedingten Vorlageneigenschaften entsprechend einstellt.

Meiner Meinung nach, ja, es wäre nützlich, aber bis der core stark auf der WP_Query coreklasse basiert (und das ist eng für immer ), macht es wahrscheinlich keinen Sinn, dies im core zu haben.


Bonus

Wenn jemand aus irgendeinem Grund 'date_query' analysieren und bedingte Vorlagen-Tags 'date_query' möchte, kann folgender Code verwendet werden:

 add_action( 'parse_query', function ( \WP_Query $q ) { $cond = array( 'hour' => 'is_time', 'minute' => 'is_time', 'second' => 'is_time', 'year' => 'is_year', 'month' => 'is_month', 'day' => 'is_day', 'dayofweek' => 'is_day', 'week' => 'is_date', 'before' => 'is_date', 'after' => 'is_date' ); $date_query = isset( $q->query_vars['date_query'] ) ? $q->query_vars['date_query'] : FALSE; if ( empty( $date_query ) ) return; $found = 0; foreach ( $date_query as $i => $query ) { if ( ! is_array( $query ) ) continue; foreach ( $query as $key => $val) { if ( is_numeric($key) || ! isset( $cond[$key] ) ) continue; if ( in_array( $key, array( 'before', 'after' ) ) ) { $q->is_time = $q->is_year = $q->is_month = $q->is_day = FALSE; $q->is_date = $q->is_archive = TRUE; return; } $found++; $q->$cond[$key] = TRUE; } } if ( $found < = 0 ) return; // a query can't be is_time, is_year, is_month and is_day in same time $q->is_year = $q->is_year && ! $q->is_time && ! $q->is_month && ! $q->is_day; $q->is_month = $q->is_month && ! $q->is_time && ! $q->is_day; $q->is_day = $q->is_day && ! $q->is_time; $q->is_date = $q->is_archive = TRUE; $q->is_home = FALSE; });