the_content et is_main_query

15

Je filtre le contenu avec le the_contentfiltre. Tout fonctionne parfaitement, sauf que mes modifications sont également appliquées aux requêtes personnalisées. Mes modifications apparaissent également dans la barre latérale si le widget utilise une requête personnalisée

Pour contrer cela, j'utilise is_main_query()pour cibler la requête principale uniquement, mais cela ne fonctionne pas. Les modifications sont tout simplement toujours appliquées à toutes les requêtes. Ce qui est drôle cependant, toutes les autres vérifications conditionnelles aiment is_single()et is_category()fonctionnent si je cible des pages spécifiques, sauf que toutes les modifications affectent toute autre requête personnalisée sur cette page, que j'utilise is_main_query()ou non

Est-ce que j'ai râté quelque chose. Comment appliquer mes modifications à la requête principale uniquement à l'aide du the_contentfiltre

add_filter('the_content', 'custom_content');

function custom_content($content){

    if(is_main_query()){ // << THIS IS NOT WORKING
        // My custom content that I add to the_content()    
    }
    return $content;
}
Pieter Goosen
la source

Réponses:

11

Pour être honnête, la fonction in_the_loop()est ce que vous recherchez:

add_filter( 'the_content', 'custom_content' );

function custom_content( $content ) {
    if ( in_the_loop() ) {
        // My custom content that I add to the_content()    
    }
    return $content;
}

Qu'est in_the_loop- ce que c'est de vérifier si global pour $wp_query(c'est-à-dire l'objet de requête principal) de la publication actuelle est -1 < $current_post < $post_count.

Cela se produit lorsque la requête principale est en boucle, car avant le début de la boucle, la publication actuelle est -1 et après la fin de la boucle, la publication actuelle est réinitialisée à -1.

Donc, si in_the_loop()c'est vrai, cela signifie que l'objet de requête principal est en boucle, ce dont vous avez besoin dans ce cas (et est le même résultat de l'ajout loop_startet de la suppression de l'action loop_end, comme l'a écrit @ialocin; en fait, cela fonctionne pour la même raison, et j'ai obtenu mon +1).

L'avantage de l'approche de @ ialocin est lorsque vous souhaitez cibler un objet de requête différent de l'objet principal, car cela in_the_loop()ne fonctionne que pour la requête principale.

gmazzap
la source
Dans aucune de mes recherches de site ou de recherche en ligne, je n'ai rencontré cela. Un joyau caché qui fonctionne. Chaque solution utilise is_main_query, pense vraiment que personne ne l'a testé à fond. Merci pour votre contribution, vraiment appréciée
Pieter Goosen
1
@PieterGoosen Heureux que cela fonctionne. C'est une fonction très ancienne, venant tout droit de l'époque où ce is_main_queryn'était pas une chose.
gmazzap
Vous voyez, c'est là que je l'ai manqué, je ne suis pas un vieux temporisateur :-), a rejoint Wordpress en 3.3.
Pieter Goosen
2
@GM voudriez-vous ajouter ceci à votre réponse. Ces informations sont utiles à d'autres qui pourraient tomber sur cette réponse. La plupart des gens, comme moi, ne lisent pas les commentaires :-)
Pieter Goosen
1
@PieterGoosen done :)
gmazzap
7

Ceci n'est qu'un ajout à la réponse de @ Otto. Juste pour le rendre un peu plus compréhensible. Fondamentalement, ce que @Otto dit, vous devez inverser la logique, cela signifie: si vous pouvez déterminer de manière fiable la requête principale, vous pouvez ajouter - et supprimer - votre accrochage dans le the_contentfiltre.

Par exemple, la requête principale peut être reconnue de manière fiable lors de l' pre_get_postsaction, donc cela fonctionnerait:

function wpse162747_the_content_filter_callback( $content ) {
    return $content . 'with something appended';
}

add_action( 'pre_get_posts', 'wpse162747_pre_get_posts_callback' );
function wpse162747_pre_get_posts_callback( $query ) {
    if ( $query->is_main_query() ) {
        add_filter( 'the_content', 'wpse162747_the_content_filter_callback' );
    }
}

Comme vous êtes censé retirer le filtre lorsqu'il n'est plus nécessaire, je pense que l' loop_endaction devrait être un bon endroit pour cela et que nous pouvons utiliser comme contrepartie loop_start. Qui ressemblerait à ceci:

add_action( 'loop_start', 'wpse162747_loop_start_callback' );
function wpse162747_loop_start_callback( $query ) {
    if ( $query->is_main_query() ) {
        add_filter( 'the_content', 'wpse162747_the_content_filter_callback' );
    }
}

add_action( 'loop_end', 'wpse162747_loop_end_callback' );
function wpse162747_loop_end_callback( $query ) {
    if ( $query->is_main_query() ) {
        remove_filter( 'the_content', 'wpse162747_the_content_filter_callback' );
    }
}
Nicolai
la source
Testera ce demain. Merci pour votre explication détaillée.
Pieter Goosen du
Mon plaisir comme toujours @PieterGoosen Pas pressé, mais faites-le, parce que je n'ai pas - du moins pas assez.
Nicolai
1
Que se passe-t-il si un shortcode est utilisé dans the_content () et que le shortcode démarre une autre requête qui appelle the_content (), réinitialise l'objet de publication actuel et la boucle continue? Tous les filtres s'appliqueront. Assez délicat ici, pas sauvé par la cloche in_the_loop () ... C'est pourquoi je suggère de toujours supprimer les filtres uniques dès qu'ils le font, comme approché par @Nicolai
Jonas Lundman
5

Vous utilisez is_main_query()mal. La fonction globale is_main_query () renvoie true sauf si la variable globale $ wp_query a été redéfinie.

Il n'y a probablement aucun moyen fiable à 100% de savoir, depuis l'intérieur d'un filtre the_content, si la boucle actuelle dans laquelle vous vous trouvez est la requête principale ou non. Le filtre de contenu filtre uniquement le contenu. Il n'a aucune forme de capacité à savoir pour quelle boucle il est utilisé.

Au lieu de cela, vous devez ajouter votre filtre lorsque vous en avez besoin, puis le supprimer lorsque vous ne le faites pas.

Otto
la source
C'est en fait une déception qu'il n'y a aucun moyen direct de cibler la requête principale avec un the_contentfiltre
Pieter Goosen
Eh bien, ce n'est vraiment pas surprenant. Comme tout autre filtre, il filtre simplement les choses. Il ne connaît pas le contexte entourant son appel. Il pourrait même ne pas être appelé de l'intérieur d'une boucle appropriée. Pas moyen de le dire.
Otto