the_content та is_main_query


15

Я фільтрую вміст за допомогою the_contentфільтра. Все працює бездоганно, витяг, що мої зміни застосовуються і до спеціальних запитів. Мої зміни відображаються і на бічній панелі, якщо у віджеті використовується спеціальний запит

Щоб протистояти цьому, я використовую is_main_query()для націлювання лише на головний запит, але він не працює. Зміни просто все ще застосовуються до всіх запитів наскрізь. Що смішно, хоча всі інші умовні перевірки люблять is_single()і is_category()працюють, якщо я націлюю певні сторінки, за винятком того, що всі зміни впливають на будь-який інший спеціальний запит на цій сторінці, використовую я is_main_query()чи ні

Чи щось мені тут не вистачає Як застосувати зміни до основного запиту лише за допомогою the_contentфільтра

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

Відповіді:


11

Якщо чесно, функція in_the_loop()полягає в тому, що ви шукаєте:

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

Що in_the_loopпотрібно перевірити, чи є глобальним для $wp_query(це головний об'єкт запиту) поточної публікації -1 < $current_post < $post_count.

Це трапляється, коли основний запит є циклічним, оскільки перед початком циклу поточна публікація дорівнює -1, а після закінчення циклу поточна публікація знову скидається на -1.

Отже, якщо in_the_loop()це правда, це означає, що основним об’єктом запиту є циклічність, що вам потрібно в цьому випадку (і це той самий результат додавання дії loop_startта видалення loop_end, як написав відповідь @ialocin; насправді це працює з тієї ж причини і отримав мій +1).

Перевага підходу @ ialocin полягає в тому, коли ви хочете націлити на інший об’єкт запиту, ніж основний, оскільки in_the_loop()він працює лише для основного запиту.


Ні в одному з пошукових запитів на моїх веб-сайтах чи в пошуку в Інтернеті я цього не зустрічав. Прихований дорогоцінний камінь, який працює. Кожне рішення використовує is_main_query, дійсно думайте, ніхто цього не ретельно перевіряв. Дякую за ваш внесок, дуже вдячний
Пітер Гузен

1
@PieterGoosen Рада, що це працює. Це дуже стара функція, яка виходить прямо з часів, коли is_main_queryце не було річчю.
gmazzap

Розумієте, це я там пропустив, я не старий таймер :-), приєднався до Wordpress в 3.3.
Пітер Гусен

2
@GM ви б проти, щоб додати це до своєї відповіді. Це корисна інформація для інших, яка може натрапити на цю відповідь. Більшість людей, як я, не читають коментарів :-)
Пітер Гусен

1
@PieterGoosen done :)
gmazzap

7

Це лише доповнення до відповіді @ Отто. Просто, щоб зробити це трохи краще зрозумілим. В основному те, що говорить @Otto, ви повинні змінити логіку, це означає: якщо ви зможете надійно визначити основний запит, то ви можете додати - і видалити - підключення до the_contentфільтра.

Наприклад, основний запит можна надійно розпізнати під час pre_get_postsдії, так що це спрацює:

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

Оскільки ви повинні видалити фільтр, коли він більше не потрібен, я думаю, що loop_endдія повинна бути хорошим місцем для цього, і як його аналог ми можемо використовувати loop_start. Що б виглядало так:

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

Випробує цей завтрашній день. Дякуємо за ваше детальне пояснення.
Пітер Гусен

Моє задоволення, як завжди @PieterGoosen Не поспішайте, але робіть це, бо я цього не зробив - принаймні недостатньо.
Миколай

1
Що робити, якщо короткий код використовується в межах__content (), і короткий код запускає інший запит, що викликає the_content (), скидає поточний об'єкт публікації і цикл продовжується? Буде застосовано весь фільтр. Тут досить хитро, не врятував дзвіночок in_the_loop () ... Ось чому я пропоную завжди видаляти унікальні фільтри, як тільки вони це зробили, як звернувся @Nicolai
Йонас Лундман

5

Ви використовуєте is_main_query()неправильно. Глобальна функція is_main_query () повертає значення true, якщо глобальну змінну $ wp_query не було визначено повторно.

Напевно, не існує 100% надійного способу сказати з фільтра the_content, чи основний запит чи ні поточний цикл, у якому ви перебуваєте. Фільтр вмісту просто фільтрує вміст. Він не має жодної форми здатності знати, для якого циклу він використовується.

Натомість слід додати свій фільтр, коли він вам потрібен, а потім видалити його, коли цього не потрібно.


Це насправді невдача, що немає прямих засобів для націлювання на головний запит з the_contentфільтром
Pieter Goosen

Що ж, насправді це не дивно. Як і будь-який інший фільтр, він просто фільтрує речі. Він не знає, що оточує контекст, коли його викликають. Це навіть не може бути викликано зсередини належного циклу. Немає цього сказати.
Отто
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.