the_content y is_main_query

15

Estoy filtrando el contenido con el the_contentfiltro. Todo funciona perfecto, extracto de que mis cambios también se aplican a consultas personalizadas. Mis cambios también aparecen en la barra lateral si el widget utiliza una consulta personalizada

Para contrarrestar eso, estoy usando is_main_query()solo la consulta principal, pero no funciona. Los cambios simplemente se aplican a todas las consultas durante todo el proceso. Sin embargo, lo que es divertido, a todas las demás verificaciones condicionales les gusta is_single()y is_category()funciona si apunto a páginas específicas, excepto que todos los cambios afectan cualquier otra consulta personalizada en esa página, ya sea que la use is_main_query()o no.

Me estoy perdiendo de algo. ¿Cómo aplico mis cambios a la consulta principal solo usando el 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
fuente

Respuestas:

11

Para ser sincero, la función in_the_loop()es lo que está buscando:

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

Lo que in_the_loophace es verificar si es global para $wp_query(ese es el objeto de consulta principal) de la publicación actual -1 < $current_post < $post_count.

Eso sucede cuando la consulta principal está en bucle, porque antes de que comience el bucle, la publicación actual es -1, y después de que finaliza el bucle, la publicación actual se restablece a -1 nuevamente.

Entonces, si in_the_loop()es cierto, significa que el objeto de consulta principal está en bucle, que es lo que necesita en este caso (y es el mismo resultado de agregar loop_starty quitar la acción loop_end, como escribió la respuesta @ialocin; de hecho, funciona por la misma razón, y obtuve mi +1).

El beneficio del enfoque de @ialocin es cuando desea apuntar a un objeto de consulta diferente al principal, porque in_the_loop()solo funciona para la consulta principal.

gmazzap
fuente
En ninguna de mis búsquedas en el sitio o en línea, me encontré con esto. Una joya escondida que funciona. Cada solución utiliza is_main_query, realmente creo que nadie lo probó a fondo. Gracias por tu aporte, realmente apreciado
Pieter Goosen
1
@PieterGoosen Me alegro de que funcione. Esa es una función muy antigua, que viene directamente de tiempos en que is_main_queryno era una cosa.
gmazzap
Verás, aquí es donde me lo perdí, no soy un viejo temporizador :-), me uní a Wordpress en 3.3.
Pieter Goosen el
2
@GM, ¿te importaría agregar esto a tu respuesta? Esta es información útil para otros que podrían tropezar con esta respuesta. La mayoría de la gente, como yo, no lee los comentarios :-)
Pieter Goosen
1
@PieterGoosen hecho :)
gmazzap
7

Esto es simplemente una adición a la respuesta de @ Otto. Solo para hacerlo un poco mejor comprensible. Básicamente, lo que dice @Otto es que debes invertir la lógica, es decir: si puedes determinar de manera confiable la consulta principal, entonces puedes agregar, y eliminar, tu enganche en el the_contentfiltro.

Por ejemplo, la consulta principal se puede reconocer de manera confiable en pre_get_posts acción, por lo que esto funcionaría:

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 se supone que debe eliminar el filtro cuando ya no sea necesario, creo que la loop_endacción debería ser un buen lugar para eso y, como contrapartida, podemos usarlo loop_start. Que se vería así:

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
fuente
Pondrá a prueba este mañana. Gracias por tu explicación detallada.
Pieter Goosen
Mi placer como siempre @PieterGoosen Sin prisa, pero hazlo, porque no lo he hecho, al menos no lo suficiente.
Nicolai
1
¿Qué sucede si un shortcode está en uso dentro de the_content () y el shortcode inicia otra consulta que invoca the_content (), restablece el objeto de publicación actual y el ciclo continúa? Se aplicará todo el filtro. Muy complicado aquí, no salvado por la campana in_the_loop () ... Es por eso que sugiero, eliminar siempre los filtros únicos tan pronto como lo hayan hecho, según lo mencionado por @Nicolai
Jonas Lundman
5

Estás usando is_main_query()incorrectamente. La función global is_main_query () devuelve verdadero a menos que la variable global $ wp_query se haya redefinido.

Probablemente no haya una forma 100% confiable de saber, desde el interior del filtro the_content, si el bucle actual en el que se encuentra es o no la consulta principal. El filtro de contenido solo filtra el contenido. No tiene ninguna forma de saber para qué bucle se está utilizando.

En su lugar, debe agregar su filtro cuando lo necesite y luego eliminarlo cuando no lo necesite.

Otón
fuente
En realidad, es una decepción que no haya un medio directo para dirigir la consulta principal con the_contentfiltro
Pieter Goosen
Bueno, eso realmente no es sorprendente. Como cualquier otro filtro, solo filtra cosas. No conoce el contexto que lo rodea cuando se lo llama. Puede que ni siquiera se llame desde el interior de un bucle adecuado. No hay forma de que lo diga.
Otto