web-dev-qa-db-fra.com

Quelle est la méthode correcte pour déterminer 'is_front_page' lors de l'utilisation de filtres tels que 'pre_get_posts' et 'posts_where'?

Sur mon site, plusieurs filtres doivent être appliqués si l'utilisateur visualise la page d'accueil statique. Je crois comprendre que is_front_page() devrait déterminer si tel est bien le cas.

Cependant, chaque fois que j'utilise la fonction, je constate que parfois, elle renvoie true (par exemple, posts_orderby) mais la plupart du temps, elle renvoie false (par exemple, pre_get_posts, posts_fields, posts_join et posts_where). Indépendamment du résultat, je reçois toujours la notification suivante -

Essayer d'obtenir la propriété de non-objet dans {mon chemin}\wp-includes\query.php à la ligne 4373

La méthode contenant la ligne fautive est 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;
}

Pour lutter contre ce problème, j'ai créé ma propre fonction, comme ci-dessous, mais cela semble "sale" d'avoir dû le faire. Ma question est donc la suivante: existe-t-il une meilleure façon de procéder?

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

}

Modifier

Après une enquête plus poussée, il semble que la ligne incriminée soit en réalité 4369 (wp-includes/querey.php) - $page_obj = $this->get_queried_object();

$page_obj est retourné sous la forme null, ce qui signifie que la vérification de $q->is_front_page() échoue. Cela semble faux et, à moins que quiconque soit en mesure d'expliquer comment un tel comportement pourrait être attendu, je vais ouvrir un ticket sur Trac.


Mettre à jour

J'ai maintenant modifié la fonction ci-dessus. Utiliser le second argument transmis à tous les filtres que j'utilise (l'instance WP_Query), comme indiqué par @birgire , m'a permis de supprimer le filtre global.

Cependant, en prenant l'exemple ci-dessous, je reçois toujours l'avis susmentionné (et le résultat de false) lors de la vérification de $q->is_front_page() -

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;

}

Remplacer $q->is_front_page() par fgw_is_front_page($q) fonctionne, mais encore une fois, il est déplacé de devoir utiliser une solution personnalisée alors qu’il en existe apparemment une qui existe déjà.

5
David Gard

En ce qui concerne les hooks posts_orderby, posts_where, posts_join et posts_clauses, l'objet \WP_Query actuel est disponible via l'argument second input.

Voici les parties pertinentes de la classe \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 ) );

tous en utilisant apply_filters_ref_array function et &$this est l'instance actuelle de \WP_Query. Le Codex dit ce qui suit à propos de cette fonction:

Cette fonction est identique à apply_filters, mais les arguments transmis aux fonctions rattachées à $ tag sont fournis à l'aide d'un tableau.

Vous pouvez accéder au deuxième argument avec par exemple:

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

vous n'avez donc pas à vous fier à l'objet global $wp_query.

Après avoir tracé cette trace dans WP_Query, nous avons trouvé la raison pour laquelle l'appel de la méthode is_front_page() ne fonctionne pas dans ces rappels de filtre. Il y a un problème dans la méthode is_page() qui tente d'utiliser la méthode get_queried_object() qui n'a toujours pas d'objet à renvoyer.

La méthode is_home() fonctionne en revanche et n'appelle pas la méthode is_page().

Mettre à jour:

Il semble y avoir au moins deux billets Trac, # 27015 et # 21790 , liés à ce problème.

Dans # 27015, il y a une suggestion patch by @mattonomics, qui modifie l'objet queried_object dans la méthode parse_query().

Alors, pourquoi ne pas essayer ces modifications dans notre cas, mais via le crochet parse_query à la place:

/**
 * 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' );
    }
} );

Nous devrions pouvoir ajouter d'autres modifications de cette façon, à partir de ce correctif.

5
birgire

au lieu de

$query->is_front_page()

essayez d'utiliser

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

(Dans le contexte:)

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

Cette solution est à partir d'ici: https://core.trac.wordpress.org/ticket/21790#comment:11

0
squarecandy