apply_filters() и the_excerpt дают неожиданные результаты

31 дек. 2011 г., 19:23:58
Просмотры: 29.1K
Голосов: 10

Чувствую, что я упускаю что-то очевидное, но не могу заставить 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());
}

У меня есть несколько вопросов на основе моих находок:

  1. Почему фильтр не применяется как ожидалось?
  2. Есть ли способ получить отрывок вне цикла без создания нового цикла?
  3. Я не сошел с ума?

Заранее спасибо за помощь. Я в довольно большом замешательстве.

3
Комментарии

Функция get_the_excerpt() не устарела, просто дополнительный параметр, который раньше в нее передавался, больше не используется.

Milo Milo
31 дек. 2011 г. 19:47:17

Извините, именно это я и имел в виду. Спасибо за уточнение.

jlengstorf jlengstorf
31 дек. 2011 г. 20:55:57

Ты сумасшедший!.. Как и я, лол

pythonian29033 pythonian29033
7 окт. 2016 г. 11:15:11
Все ответы на вопрос 3
5
16

Оказалось, ответ был в функции 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');

Это несколько избыточно, но мне нравится это решение больше, чем создание новых циклов каждый раз, когда нужно сгенерировать эксерпт.

1 янв. 2012 г. 20:12:04
Комментарии

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

hakre hakre
2 янв. 2012 г. 10:08:46

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

jlengstorf jlengstorf
2 янв. 2012 г. 21:56:31

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

Eric K Eric K
26 авг. 2015 г. 19:33:39

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

jlengstorf jlengstorf
1 сент. 2015 г. 20:07:54

уф! отличный вариант с точки зрения новичка в wpress, спасибо

pythonian29033 pythonian29033
7 окт. 2016 г. 11:45:08
5

Попробуйте:

   get_post($post->ID)->post_excerpt
                        ^^^^^^^^^^^^

Смотрите: get_postКодекс для всех доступных возвращаемых членов.

31 дек. 2011 г. 20:09:46
Комментарии

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

jlengstorf jlengstorf
31 дек. 2011 г. 21:00:08

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

hakre hakre
31 дек. 2011 г. 21:11:49

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

Я хочу имитировать это поведение вне цикла.

jlengstorf jlengstorf
31 дек. 2011 г. 22:14:44

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

hakre hakre
1 янв. 2012 г. 00:07:42

Спасибо за ссылку. Я знал, что могу настроить дополнительный цикл, но это кажется избыточным. Моим решением было добавление фильтра. Я рассматриваю это как небольшие усилия сейчас для гораздо меньшего количества кода в будущем.

jlengstorf jlengstorf
1 янв. 2012 г. 20:14:50
0

Вы можете использовать мою пользовательскую функцию для фильтрации контента (она из 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') . '">  ' . __( 'Читать далее &#187;', 'narga' ) . ' </a></p>');
            $content = implode(' ', $words);
        endif;
        $content = '<p>' . $content . '</p>';
        endif;
        endif;
        # Обязательно возвращаем контент
        return $content;
        }
        // Добавляем фильтр к the_content
        add_filter('the_content', 'narga_excerpts');
    
15 мая 2013 г. 16:49:28