the_content e is_main_query

15

Estou filtrando o conteúdo com o the_contentfiltro. Tudo funciona perfeitamente, exceto que minhas alterações também são aplicadas a consultas personalizadas. Minhas alterações também aparecem na barra lateral se o widget usar uma consulta personalizada

Para combater isso, estou usando is_main_query()apenas a consulta principal, mas ela não está funcionando. As alterações ainda são simplesmente aplicadas a todas as consultas. O que é engraçado, porém, todas as outras verificações condicionais gostam is_single()e is_category()estão funcionando se eu segmentar páginas específicas, exceto que todas as alterações afetam qualquer outra consulta personalizada nessa página, se eu uso is_main_query()ou não

Estou faltando alguma coisa aqui. Como aplico minhas alterações à consulta principal usando apenas o the_contentfiltro

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
fonte

Respostas:

11

Para ser honesto, a função in_the_loop()é o que você está procurando:

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

O que in_the_loopfaz é verificar se é global $wp_query(esse é o principal objeto de consulta) da postagem atual -1 < $current_post < $post_count.

Isso acontece quando a consulta principal está em loop, porque antes do início do loop, a postagem atual é -1 e, após o término do loop, a postagem atual é redefinida para -1 novamente.

Portanto, se in_the_loop()for verdade, significa que o objeto de consulta principal está em loop, o que é necessário neste caso (e é o mesmo resultado da adição loop_starte remoção da ação loop_end, como a resposta que @ialocin escreveu; na verdade funciona pelo mesmo motivo e recebi o meu +1).

O benefício da abordagem do @ ialocin é quando você deseja direcionar um objeto de consulta diferente do principal, porque in_the_loop()funciona apenas para a consulta principal.

gmazzap
fonte
Em nenhuma das pesquisas em meu site ou online, eu me deparei com isso. Uma jóia escondida que funciona. Toda solução usa is_main_query, realmente acha que ninguém testou isso completamente. Obrigado pelo seu contributo, muito apreciado
Pieter Goosen
1
@PieterGoosen Fico feliz que ele funciona. Essa é uma função muito antiga, vinda diretamente de tempos em que is_main_querynão era nada.
gmazzap
Veja bem, é aqui que eu errei, não sou um veterano :-), entrei para o Wordpress no 3.3.
Pieter Goosen
2
@ GM, você se importaria de adicionar isso à sua resposta. Esta é uma informação útil para outras pessoas que podem encontrar essa resposta. A maioria das pessoas, como eu, não ler os comentários :-)
Pieter Goosen
1
@PieterGoosen done :)
gmazzap
7

Isso é apenas uma adição à resposta de @ Otto. Apenas para torná-lo um pouco melhor compreensível. Basicamente, o que @Otto está dizendo, você precisa reverter a lógica, o que significa: se você pode determinar com segurança a consulta principal, pode adicionar - e remover - sua conexão ao the_contentfiltro.

Por exemplo, a consulta principal pode ser reconhecida com segurança na pre_get_postsação, portanto, isso funcionaria:

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

Como você deve remover o filtro quando não for mais necessário, acho que a loop_endação deve ser um bom lugar para isso e, como contrapartida, podemos usar loop_start. O que ficaria assim:

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
fonte
Testará este amanhã. Obrigado pela sua explicação detalhada.
Pieter Goosen
O meu prazer como sempre @PieterGoosen Não tem pressa, mas faça-o, porque não tenho - pelo menos não o suficiente.
Nicolai
1
E se um código curto estiver em uso dentro de the_content () e o shortcode iniciar outra consulta que, chamando the_content (), redefinir o objeto de postagem atual e o loop continuar? Todo o filtro será aplicado. Bastante complicado aqui, não é salvo pelo sino in_the_loop () ... É por isso que sugiro que sempre remova filtros exclusivos assim que eles fizerem, conforme abordado por @Nicolai
Jonas Lundman
5

Você está usando is_main_query()incorretamente. A função global is_main_query () retorna true, a menos que a variável global $ wp_query tenha sido redefinida.

Provavelmente, não há uma maneira 100% confiável de informar, de dentro de um filtro the_content, se o Loop atual em que você está ou não é a consulta principal ou não. O filtro de conteúdo apenas filtra o conteúdo. Ele não tem nenhuma forma de capacidade de saber para que loop está sendo usado.

Em vez disso, você deve adicionar seu filtro quando precisar e removê-lo quando não precisar.

Otto
fonte
É realmente um let-down que não há meios straighforward para direcionar a consulta principal com the_contentfiltro
Pieter Goosen
Bem, isso realmente não é surpreendente. Como qualquer outro filtro, apenas filtra as coisas. Ele não conhece o contexto em que está sendo chamado. Pode nem ser chamado de dentro de um loop adequado. Não há como dizer.
Otto