apply_filters() и the_excerpt дают неожиданные результаты
Чувствую, что я упускаю что-то очевидное, но не могу заставить WordPress работать корректно.
Я генерирую Facebook OG теги с помощью функции. Всё работает нормально, кроме отрывка (excerpt).
После того, как get_the_excerpt($post->ID)
стал устаревшим, есть ли другой способ создать отрывок без необходимости создавать новый цикл? Мне кажется это избыточным.
Моей первой идеей было использовать apply_filters()
:
$description = apply_filters('the_excerpt', get_post($post->ID)->post_content);
Это дает мне полный пост, включая HTML-форматированный контент. Ладно, должно быть неправильно. Тогда я попробовал следующую логичную идею:
$description = apply_filters('get_the_excerpt', get_post($post->ID)->post_content);
Не работает. Теперь нет HTML, но всё равно выводится полный пост (что очень сбивает с толку).
Хорошо, нет проблем. Давайте пропустим все сложности и просто попробуем обрезанную запись:
$description = wp_trim_excerpt(get_post($post->ID)->post_content);
Никаких изменений.
Итак, мой вопрос: что здесь происходит? Может я что-то упускаю?
Я заглянул в ядро WP, чтобы понять, как работает the_excerpt()
, и похоже, что он идентичен моему вызову:
/**
* Отображает отрывок поста.
*
* @since 0.71
* @uses apply_filters() Вызывает хук 'the_excerpt' для отрывка поста.
*/
function the_excerpt() {
echo apply_filters('the_excerpt', get_the_excerpt());
}
У меня есть несколько вопросов на основе моих находок:
- Почему фильтр не применяется как ожидалось?
- Есть ли способ получить отрывок вне цикла без создания нового цикла?
- Я не сошел с ума?
Заранее спасибо за помощь. Я в довольно большом замешательстве.
Оказалось, ответ был в функции wp_trim_excerpt()
.
Она определена в файле wp-includes/functions.php:1879
:
/**
* Генерирует краткое описание (эксерпт) из содержимого, если необходимо.
*
* Количество слов в эксерпте по умолчанию — 55. Если текст длиннее,
* в конце будет добавлена строка ' [...]'. Если текст короче 55 слов,
* он возвращается без изменений.
*
* Лимит в 55 слов можно изменить с помощью фильтра excerpt_length.
* Строку ' [...]' можно изменить с помощью фильтра excerpt_more.
*
* @since 1.5.0
*
* @param string $text Опционально. Текст эксерпта. Если пустой — генерируется автоматически.
* @return string Краткое описание.
*/
function wp_trim_excerpt($text = '') {
$raw_excerpt = $text;
if ( '' == $text ) {
$text = get_the_content('');
$text = strip_shortcodes( $text );
$text = apply_filters('the_content', $text);
$text = str_replace(']]>', ']]>', $text);
$excerpt_length = apply_filters('excerpt_length', 55);
$excerpt_more = apply_filters('excerpt_more', ' ' . '[...]');
$text = wp_trim_words( $text, $excerpt_length, $excerpt_more );
}
return apply_filters('wp_trim_excerpt', $text, $raw_excerpt);
}
Таким образом, любой переданный текст не обрабатывается; функция работает только при вызове с пустым параметром.
Чтобы решить эту проблему, я добавил простой фильтр в свою тему:
/**
* Позволяет генерировать эксерпты вне цикла.
*
* @param string $text Текст для обрезки
* @return string Обрезанный текст
*/
function rw_trim_excerpt( $text='' )
{
$text = strip_shortcodes( $text );
$text = apply_filters('the_content', $text);
$text = str_replace(']]>', ']]>', $text);
$excerpt_length = apply_filters('excerpt_length', 55);
$excerpt_more = apply_filters('excerpt_more', ' ' . '[...]');
return wp_trim_words( $text, $excerpt_length, $excerpt_more );
}
add_filter('wp_trim_excerpt', 'rw_trim_excerpt');
Это несколько избыточно, но мне нравится это решение больше, чем создание новых циклов каждый раз, когда нужно сгенерировать эксерпт.

А, мне было не совсем понятно, что вам нужна только текстовая операция (без выборки из БД).

Не переживайте. Я всегда боюсь, что мои вопросы звучат бессмысленно. Я действительно брал данные из базы, но не хотел запускать ещё один цикл, поскольку у меня уже были доступны такие функции, как get_the_title($post->ID)
. Итоговая строка кода получилась такой: $description = wp_trim_excerpt(get_post($post->ID)->post_content);

Чувствую себя глупо, спрашивая об этом, но как вызывать этот новый фильтр? Я пробовал $content = apply_filters( 'rw_trim_excerpt', $content );
и $content = rw_trim_excerpt($content);
, но ни один вариант не сработал (первый не обрезал вывод, а второй выдал ошибку).

@QuantumDynamix Это предназначено для изменения обработки get_the_excerpt
, чтобы имитировать поведение the_excerpt
, поэтому вы можете вызывать: apply_filters('get_the_excerpt', $content);
.

Попробуйте:
get_post($post->ID)->post_excerpt
^^^^^^^^^^^^
Смотрите: get_post
Кодекс для всех доступных возвращаемых членов.

Это возвращает пустую строку, если для записи не было введено краткое описание. Мне нужно имитировать поведение get_the_excerpt() (создавать краткое описание, если оно не существует).

Применение фильтра этого не сделает, так что вы задаёте не тот вопрос. Непонятно, зачем вам нужно краткое описание, если его нет. get_the_excerpt()
этого не имитирует, посмотрите исходный код - он просто обращается к переменной-члену $post
, которая называется post_excerpt
. См. также ссылку на кодекс в ответе.

Из статьи в Кодексе о the_excerpt
: "оно выведет автоматическое краткое описание, которое формируется из первых 55 слов содержимого записи."
Я хочу имитировать это поведение вне цикла.

Временно создайте второй цикл и запросите этот файл по его ID для быстрого решения. Смотрите Дополнительные циклы - http://codex.wordpress.org/Function_Reference/query_posts#Secondary_Loops

Вы можете использовать мою пользовательскую функцию для фильтрации контента (она из NARGA Framework)
- Если запись имеет пользовательское краткое описание (excerpt), отображать его вместо контента
- Автоматически генерировать краткое описание из контента, если у записи нет пользовательского excerpt
Автоматически обрезать шорткоды, HTML-код, удалять [...], добавлять текст "Читать далее" (переводимый)
/** * Автоматически генерирует краткое описание из контента, если у записи нет пользовательского excerpt * @from NARGA Framework - http://www.narga.net/narga-core * @param $excerpt_lenght Максимальное количество слов в генерируемом excerpt * @coder: Nguyễn Đình Quân a.k.a Narga - http://www.narga.net **/ function narga_excerpts($content = false) { # Если это главная страница, архив или страница поиска if(is_front_page() || is_archive() || is_search()) : global $post; $content = $post->post_excerpt; $content = strip_shortcodes($content); $content = str_replace(']]>', ']]>', $content); $content = strip_tags($content); # Если excerpt задан в поле "Краткое описание" if($content) : $content = apply_filters('the_excerpt', $content); # Если excerpt не задан else : $content = $post->post_content; $excerpt_length = 50; $words = explode(' ', $content, $excerpt_length + 1); if(count($words) > $excerpt_length) : array_pop($words); array_push($words, '...<p><a class="more-link" href="' . get_permalink() . '" title="' . the_title_attribute('echo=0') . '"> ' . __( 'Читать далее »', 'narga' ) . ' </a></p>'); $content = implode(' ', $words); endif; $content = '<p>' . $content . '</p>'; endif; endif; # Обязательно возвращаем контент return $content; } // Добавляем фильтр к the_content add_filter('the_content', 'narga_excerpts');
