webentwicklung-frage-antwort-db.com.de

Was ist die richtige Methode zur Bestimmung von 'is_front_page', wenn Filter wie 'pre_get_posts' und 'posts_where' verwendet werden?

Auf meiner Site sollten mehrere Filter angewendet werden, wenn der Benutzer die statische Homepage anzeigt. Meines Wissens nach sollte is_front_page() feststellen, ob dies tatsächlich der Fall ist.

Wenn ich die Funktion verwende, stelle ich jedoch fest, dass sie manchmal true (z. B. posts_orderby) zurückgibt, aber meistens false (z. B. pre_get_posts, posts_fields, posts_join und posts_where). Ungeachtet des Ergebnisses erhalte ich jedoch immer den folgenden Hinweis:

Es wurde versucht, die Eigenschaft eines Nicht-Objekts in {mein_Pfad}\wp-includes\query.php in Zeile 4373 abzurufen

Die Methode, die die beleidigende Zeile enthält, ist WP_Query::is_front_page() -

public function is_front_page() {
    // most likely case
    if ( 'posts' == get_option( 'show_on_front') && $this->is_home() )
        return true;
    /** The offending line */ elseif ( 'page' == get_option( 'show_on_front') && get_option( 'page_on_front' ) && $this->is_page( get_option( 'page_on_front' ) ) )
        return true;
    else
        return false;
}

Um dieses Problem zu bekämpfen, habe ich wie unten beschrieben eine eigene Funktion erstellt, aber es scheint "schmutzig" zu sein, dies tun zu müssen. Meine Frage lautet also: Gibt es einen besseren Weg, dies zu tun?

function fgw_is_front_page($q){

    if(!is_a($q, 'WP_Query'))
        return false;

    return (get_option('show_on_front') == 'page' && get_option('page_on_front') && $q->get('page_id') == get_option('page_on_front'));

}

Bearbeiten

Nach weiteren Untersuchungen sieht es so aus, als ob die beleidigende Zeile tatsächlich 4369 ist (wp-includes/querey.php) - $page_obj = $this->get_queried_object();

$page_obj wird als null zurückgegeben, was bedeutet, dass die Überprüfung auf $q->is_front_page() fehlschlägt. Dies scheint falsch zu sein, und wenn niemand erklären kann, wie dies in irgendeiner Weise zu erwarten ist, werde ich versuchen, ein Ticket für Trac zu eröffnen.


Aktualisieren

Ich habe jetzt die obige Funktion geändert. Die Verwendung des zweiten Arguments, das an alle von mir verwendeten Filter (die WP_Query-Instanz) übergeben wurde, wie von @birgire erwähnt, hat es mir ermöglicht, das globale zu beseitigen.

Im folgenden Beispiel erhalte ich jedoch weiterhin den oben genannten Hinweis (und das Ergebnis von false), wenn ich $q->is_front_page() prüfe.

add_filter('posts_fields','fgw_index_posts_fields', 10, 2);
function fgw_index_posts_fields($fields, $q){

    global $wpdb;

    if(!is_admin() && is_main_query() && (is_home() || $q->is_front_page($q)))
        $fields.= $wpdb->prepare(', %1$s.name as category_name', $wpdb->terms);

    return $fields;

}

Das Ersetzen von $q->is_front_page() durch fgw_is_front_page($q) funktioniert, aber es fühlt sich wiederum schmutzig an, eine benutzerdefinierte Lösung verwenden zu müssen, wenn anscheinend bereits eine vorhanden ist.

5
David Gard

In Bezug auf die Hooks posts_orderby, posts_where, posts_join und posts_clauses ist das aktuelle \WP_Query-Objekt über das second input-Argument verfügbar.

Dies sind die relevanten Teile aus der Klasse \WP_Query:

$orderby = apply_filters_ref_array( 'posts_orderby', array( $orderby, &$this ) );
$where   = apply_filters_ref_array( 'posts_where', array( $where, &$this ) );
$join    = apply_filters_ref_array( 'posts_join', array( $join, &$this ) );
$clauses = (array) apply_filters_ref_array( 'posts_clauses', array( compact( $pieces ), &$this ) );

alle, die die Funktion apply_filters_ref_array und &$this verwenden, sind die aktuellen \WP_Query-Instanzen. Der Kodex sagt folgendes über diese Funktion:

Diese Funktion ist identisch mit apply_filters, aber die Argumente, die an die mit $ tag verknüpften Funktionen übergeben werden, werden über ein Array bereitgestellt.

Sie können auf das zweite Argument zugreifen, zum Beispiel mit:

add_filter( 'posts_where', function( $where, \WP_Query $q )
{
    if( $q->is_front_page() ) <-- This method won't work here with a static front-page!!!
    {
        // ...
    }
}, 10, 2 );

sie müssen sich also nicht auf das globale Objekt $wp_query verlassen.

Nachdem wir dies in WP_Query nachverfolgt haben, haben wir den Grund gefunden, warum das Aufrufen der is_front_page() -Methode in diesen Filterrückrufen nicht funktioniert. Das Problem liegt in der is_page() -Methode, die versucht, die get_queried_object() -Methode zu verwenden, die noch kein zurückzugebendes Objekt hat.

Die Methode is_home() funktioniert dagegen und ruft die Methode is_page() nicht auf.

Aktualisieren:

Es scheint mindestens zwei Trac-Tickets zu geben, # 27015 und # 21790 , die mit diesem Problem zusammenhängen.

In # 27015 gibt es ein vorgeschlagenes patch von @mattonomics, das das queried_object -Objekt innerhalb der parse_query()-Methode ändert.

Probieren Sie diese Änderungen in unserem Fall aus, aber verwenden Sie stattdessen den Hook parse_query:

/**
 * A workaround for the is_front_page() check inside pre_get_posts and later hooks.
 *
 * Based on the patch from @mattonomics in #27015
 *
 * @see http://wordpress.stackexchange.com/a/188320/26350
 */

add_action( 'parse_query', function( $q )
{
    if( is_null( $q->queried_object ) && $q->get( 'page_id' ) )
    {
        $q->queried_object    = get_post( $q->get( 'page_id' ) );
        $q->queried_object_id = (int) $q->get( 'page_id' );
    }
} );

Wir sollten in der Lage sein, auf diese Weise weitere Änderungen von diesem Patch hinzuzufügen.

5
birgire

anstatt

$query->is_front_page()

versuchen Sie es mit

$query->get('page_id') == get_option('page_on_front')

(im Zusammenhang:)

function custom_pre_get_posts( $query ) {
    if ( $query->get('page_id') == get_option('page_on_front') ) {
        // do stuff
    }
}
add_action('pre_get_posts', 'custom_pre_get_posts');

Diese Lösung ist von hier: https://core.trac.wordpress.org/ticket/21790#comment:11

0
squarecandy