Вопрос или проблема
У меня есть пользовательская функция wp_trim_words()
, настроенная на возврат аннотаций только из 20 слов, и в большинстве случаев она работает нормально. Но по какой-то причине на постах, которые содержат списки, она выводит значительно больше 20 слов. (Смотрите посты внизу этой страницы.) Как я могу это исправить? Я пытался удалить <ul>,<ol>,<li>,
из function insight_allowedtags()
, но это ничего не дало.
В идеале я хотел бы, чтобы пользовательская аннотация выводила как минимум 20 слов и заканчивалась в конце предложения, независимо от того, содержит ли пост список или нет.
Вот пользовательская функция, которую я использую (как предложено в этом посте):
// Пользовательская аннотация для постов Insights на странице Insights и страницах категорий
function insight_allowedtags() {
// Добавьте пользовательские теги в эту строку
return '<script>,<style>,<span>,<ul>,<ol>,<li>,<a>,<p>';
}
if ( ! function_exists( 'insight_custom_wp_trim_excerpt' ) ) :
function insight_custom_wp_trim_excerpt($insight_excerpt) {
global $post;
$raw_excerpt = $insight_excerpt;
if ( '' == $insight_excerpt ) {
$insight_excerpt = get_the_content('');
$insight_excerpt = strip_shortcodes( $insight_excerpt );
$insight_excerpt = apply_filters('the_content', $insight_excerpt);
$insight_excerpt = str_replace(']]>', ']]>', $insight_excerpt);
$insight_excerpt = strip_tags($insight_excerpt, insight_allowedtags()); /*ЕСЛИ вам нужно разрешить только определенные теги. Удалите, если разрешены все теги */
// Установите количество слов в аннотации и прерывайте только после завершения предложения.
$excerpt_word_count = 20;
$excerpt_length = apply_filters('excerpt_length', $excerpt_word_count);
$tokens = array();
$excerptOutput="";
$count = 0;
// Разделите строку на токены; HTML-теги или слова с любым пробелом
preg_match_all('/(<[^>]+>|[^<>\s]+)\s*/u', $insight_excerpt, $tokens);
foreach ($tokens[0] as $token) {
if ($count >= $excerpt_word_count && preg_match('/[\,\;\?\.\!]\s*$/uS', $token)) {
// Достигнуто ограничение, продолжайте, пока не встретится , ; ? . или !
$excerptOutput .= trim($token);
break;
}
// Добавьте слова, чтобы завершить предложение
$count++;
// Добавьте остаток токена
$excerptOutput .= $token;
}
$insight_excerpt = trim(force_balance_tags($excerptOutput));
// $excerpt_end = ' <a href="'. esc_url( get_permalink() ) . '">' . sprintf(__( 'Читать далее о %s »', 'wpse' ), get_the_title()) . '</a>';
// $excerpt_more = apply_filters('excerpt_more', ' ' . $excerpt_end);
//$pos = strrpos($wpse_excerpt, '</');
//if ($pos !== false)
// Внутри последнего HTML-тега
//$wpse_excerpt = substr_replace($wpse_excerpt, $excerpt_end, $pos, 0); /* Добавьте читать далее рядом с последним словом */
//else
// После содержимого
$insight_excerpt .= $excerpt_end; /*Добавить читать далее в новом абзаце */
return $insight_excerpt;
}
return apply_filters('insight_custom_wp_trim_excerpt', $insight_excerpt, $raw_excerpt);
}
endif;
remove_filter('get_the_excerpt', 'wp_trim_excerpt');
add_filter('get_the_excerpt', 'wpse_custom_wp_trim_excerpt', 'blog_custom_wp_trim_excerpt', 'event_custom_wp_trim_excerpt', 'insight_custom_wp_trim_excerpt');
Что насчет использования этой функции в functions.php:
function new_excerpt_length($length) {
return 20;
}
add_filter('excerpt_length', 'new_excerpt_length');
А затем получить это, добавив <?php the_excerpt()?>
в php-шаблон?
ИЛИ:
<?php $string = get_the_excerpt(); if (strlen($string) <=20) {echo '' . $string . '';} else {echo '' . substr($string, 0, 20) . '...';}?>
В этом случае 20 – это символы
Ответ или решение
Чтобы решить проблему с вашей пользовательской функцией wp_trim_words()
, которая не обрезает текст до 20 слов в случаях, когда посты содержат списки, нужно внести некоторые изменения в код вашей функции.
Сначала, давайте разберем вашу текущую функцию и внесем в неё корректировки. Ниже представлена исправленная версия вашей функции:
// Разрешаемые HTML-теги для извлечения
function insight_allowedtags() {
return '<script>,<style>,<span>,<ul>,<ol>,<li>,<a>,<p>';
}
if ( ! function_exists( 'insight_custom_wp_trim_excerpt' ) ) :
function insight_custom_wp_trim_excerpt($insight_excerpt) {
global $post;
$raw_excerpt = $insight_excerpt;
if ( '' == $insight_excerpt ) {
$insight_excerpt = get_the_content('');
$insight_excerpt = strip_shortcodes($insight_excerpt);
$insight_excerpt = apply_filters('the_content', $insight_excerpt);
$insight_excerpt = str_replace(']]>', ']]>', $insight_excerpt);
$insight_excerpt = strip_tags($insight_excerpt, insight_allowedtags());
// Установка необходимого количества слов и индикатор завершения предложения
$excerpt_word_count = 20;
$excerpt_length = apply_filters('excerpt_length', $excerpt_word_count);
$tokens = array();
$excerptOutput = "";
$count = 0;
// Разбиваем строку на токены: HTML-теги или слова
preg_match_all('/(<[^>]+>|[^<>\s]+)\s*/u', $insight_excerpt, $tokens);
foreach ($tokens[0] as $token) {
if ($count >= $excerpt_word_count && preg_match('/[\,\;\?\.\!]\s*$/uS', $token)) {
// Ограничение достигнуто, продолжаем до символа окончания предложения
$excerptOutput .= trim($token);
break;
}
// Увеличиваем счётчик слов
$count++;
// Добавляем токен к извлечению
$excerptOutput .= $token;
}
// Завершаем полученное извлечение
$insight_excerpt = trim(force_balance_tags($excerptOutput));
// Добавляем ссылку "Читать далее"
$excerpt_end = ' <a href="'. esc_url( get_permalink() ) . '">' . sprintf(__('Читать далее о %s »', 'wpse'), get_the_title()) . '</a>';
$insight_excerpt .= $excerpt_end;
return $insight_excerpt;
}
return apply_filters('insight_custom_wp_trim_excerpt', $insight_excerpt, $raw_excerpt);
}
endif;
// Удалите стандартный фильтр и добавьте свой
remove_filter('get_the_excerpt', 'wp_trim_excerpt');
add_filter('get_the_excerpt', 'insight_custom_wp_trim_excerpt');
Комментарии к изменениям:
-
Regex для разделения на токены:
Мы изменили регулярное выражение в функцииpreg_match_all
, чтобы оно правильно разбивало текст на токены, не учитывая пробелы, а только HTML-теги или слова. -
Логика счётчика:
Улучшена логика, чтобы учитывать общее количество слов и обеспечивать, что выход происходит не только по количеству слов, но и когда мы доходим до конца предложения (знак препинания). -
Ссылка "Читать далее":
Добавлена возможность добавления ссылки "Читать далее" в конце извлечённого текста.
Дополнительные рекомендации:
-
Если вы хотите полностью контролировать отображение краткого содержимого, вам следует учитывать содержание всех HTML-тегов (например, список). В случае, если вы решите, что списки должны быть полностью исключены, просто удалите из
insight_allowedtags()
ненужные теги. -
Также можно использовать стандартную функцию
wp_trim_words()
в комбинации с настройкой длины:
function new_excerpt_length($length) {
return 20;
}
add_filter('excerpt_length', 'new_excerpt_length');
С помощью этих модификаций ваша функция будет правильно обрезать текст до 20 слов, не превышая их даже в случаях, когда в контенте присутствуют списки и другие элементы HTML.