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.