WordPress как на ладони
Недорогой хостинг для сайтов на WordPress: wordpress.jino.ru

Обрезка текста и/или замена стандартной функции the_excerpt()

Обратил внимание, что функция WordPress the_excerpt() громоздкая. На её выполнение уходит много времени и ресурсов. Потому что она вызывает get_the_excerpt(), the_content() и ко всем ним, включая сам the_excerpt(), применяются различные хуки. В итоге получается немало операций - это нужно далеко не всегда. Я например, к цитатам отношусь просто - коротко сказать о чем статья, вырезав небольшой её кусок - достаточно просто текста.

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

Результат замены the_excerpt() меня порадовал: генерация страницы уменьшилась в среднем с 0,850 сек до 0,550 сек, при 9 вызовах the_excerpt() (это время на компьютере, на сервере обычно оно меньше). 9 вызовов - это количество выводимых постов в рубрике, к каждому из которых применялся the_excerpt().

Ниже функция, которой можно заменить стандартную функцию WordPress the_excerpt().

/**
 * Обрезка текста (excerpt). Шоткоды вырезаются. Минимальное значение maxchar может быть 22.
 *
 * @param string/array $args Параметры.
 *
 * @return string HTML
 *
 * @ver 2.6.4
 */
function kama_excerpt( $args = '' ){
	global $post;

	if( is_string($args) )
		parse_str( $args, $args );

	$rg = (object) array_merge( array(
		'maxchar'   => 350,   // Макс. количество символов.
		'text'      => '',    // Какой текст обрезать (по умолчанию post_excerpt, если нет post_content.
							  // Если в тексте есть `<!--more-->`, то `maxchar` игнорируется и берется все до <!--more--> вместе с HTML.
		'autop'     => true,  // Заменить переносы строк на <p> и <br> или нет?
		'save_tags' => '',    // Теги, которые нужно оставить в тексте, например '<strong><b><a>'.
		'more_text' => 'Читать дальше...', // Текст ссылки `Читать дальше`.
	), $args );

	$rg = apply_filters( 'kama_excerpt_args', $rg );

	if( ! $rg->text )
		$rg->text = $post->post_excerpt ?: $post->post_content;

	$text = $rg->text;
	$text = preg_replace( '~\[([a-z0-9_-]+)[^\]]*\](?!\().*?\[/\1\]~is', '', $text ); // убираем блочные шорткоды: [foo]some data[/foo]. Учитывает markdown
	$text = preg_replace( '~\[/?[^\]]*\](?!\()~', '', $text ); // убираем шоткоды: [singlepic id=3]. Учитывает markdown
	$text = trim( $text );

	// <!--more-->
	if( strpos( $text, '<!--more-->') ){
		preg_match('/(.*)<!--more-->/s', $text, $mm );

		$text = trim( $mm[1] );

		$text_append = ' <a href="'. get_permalink( $post ) .'#more-'. $post->ID .'">'. $rg->more_text .'</a>';
	}
	// text, excerpt, content
	else {
		$text = trim( strip_tags($text, $rg->save_tags) );

		// Обрезаем
		if( mb_strlen($text) > $rg->maxchar ){
			$text = mb_substr( $text, 0, $rg->maxchar );
			$text = preg_replace( '~(.*)\s[^\s]*$~s', '\\1...', $text ); // убираем последнее слово, оно 99% неполное
		}
	}

	// Сохраняем переносы строк. Упрощенный аналог wpautop()
	if( $rg->autop ){
		$text = preg_replace(
			array("/\r/", "/\n{2,}/", "/\n/",   '~</p><br ?/?>~'),
			array('',     '</p><p>',  '<br />', '</p>'),
			$text
		);
	}

	$text = apply_filters( 'kama_excerpt', $text, $rg );

	if( isset($text_append) )
		$text .= $text_append;

	return ( $rg->autop && $text ) ? "<p>$text</p>" : $text;
}
/* Сhangelog:
 * 2.6.4 - Убрал пробел между словом и многоточием
 * 2.6.3 - Рефакторинг
 * 2.6.2 - Добавил регулярку для удаления блочных шорткодов вида: [foo]some data[/foo]
 * 2.6   - Удалил параметр 'save_format' и заменил его на два параметра 'autop' и 'save_tags'.
 *       - Немного изменил логику кода.
 */

Как работает функция

  1. Обрезать до определенного количества символов. Указывается в параметре maxchar.

  2. Понимает тег <!--more--> в записи. Если он присутствует желаемое количество выводимых символов игнорируется и выводится все что выше  <!--more--> с сохранением HTML разметки.

  3. Можно указать сохранять переносы строк или писать весь текст в одну строку. По умолчанию переносы сохраняются, если нужен "сплошняк" ставим параметр autop=0.

  4. Можно указан какие HTML теги не нужно вырезать, например мы хотим оставить тег stront или em, тогда указываем их в параметре save_tags: save_tags=<strong><em>

  5. Также, можно использовать функцию, чтобы обрезать любой текст, который ей будет передан через параметр text.

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

Использование

Вставляем указанный выше код в файл functions.php вашего шаблона. И где нужно вывести обрезанный текст вызываем функцию так:

<?php echo kama_excerpt( array('maxchar'=>100, 'text'=>'бла бла') ); ?>

Чтобы заменить стандартный the_excerpt() нужно просто заменить the_excerpt() на kama_excerpt() Все это должно быть внутри цикла the loop.

ВАЖНО: Параметр text при замене the_excerpt(); указывать не надо!

Пример использования функции, как обрезка любого текста (в любом месте шаблона):

$str = "Функцию [foo]some text[/foo] [foo]some text[/foo] обрезки текста для Worpress, 
можно применять [foo url='bar'] и на других движках.";

echo esc_html( kama_excerpt([ 'text'=>$str, 'maxchar'=>70 ]) );

Получим:

<p>Функцию   обрезки текста для Worpress,<br />
можно применять  и на других ...</p>

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

Очень простой пример обрезки текста

Если вы не хотите использовать функцию и вам нужно просто обрезать текст не сохранения html теги и прочее, то можно воспользоваться такой короткой строкой внутри цикла WordPress:

<?php 
$text = strip_tags( get_the_content() );
echo mb_substr( $text, 0, 152 );
?>

где 152 - это количество оставляемых символов.

143 коммента
Полезные 4 Вопросы 3 Все
  • Андрей chernil.com.ua

    А есть возможность как-то прикрутить к Вашей функции параметр offset? Просто бывают случаи на одном сайте, когда в некоторых анонсах надо отрезать первое слово, например, "Характеристики:", а в других анонсах этого делать не надо.

    Ответить6 лет назад #
    • MingONE

      А через стандартную ПХП-функцию explode() не покатит? Вот для примера

      $rrr = "Функция для обрезки текста для Worpress. Также можно применять и на других движках.";  
      kama_excerpt("text=$rrr&maxchar=50");  
      	//Выведет: Функция для обрезки текста для Worpress. Также ... 
      $text=explode('Функция ', $rrr); 
      echo $text[1];
      	//По идее выведет так: для обрезки текста для Worpress. Также ...
      Ответить6 лет назад #
  • Александр

    Прекрасно работает, огромное спасибо, функция очень помогла.

    Ответить6 лет назад #
  • Юлия

    Спасибо огромное!!!!!!!! clapping

    Ответить6 лет назад #
  • Герман xa24.ru

    По умолчанию save_format=0, тач то лучше вызывать так:
    kama_excerpt("maxchar=200&save_format=1");

    Автор, респект!

    Ответить5.7 лет назад #
  • Gerz

    Очень помогло спасибо

    Ответить5.6 лет назад #
  • Вадим

    т.е. тэг

    Ответить5.6 лет назад #
  • Alex 3d-kstudio.com

    Спасибо за ваши посты.
    Взял эту функцию за основу и доработал с возможностью автозакрытия HTML тэгов для обрезанного поста.
    Использовал Tidy HTML.
    Вот доработанный вариант.
    http://3dkstudio.blogspot.com/2014/04/auto-excerpt-wordpress.html

    Ответить5.5 лет назад #
  • маленькая переделка

    static function kama_excerpt($args = array()) {
    		$defaults = array(
    		'maxchar' => 350,
    		'text' => '',
    		'save_format' => false,
    		'echo' => false,
    		'more_tag' => '<!--more-->',
    		'text_finish' => '\\1 ...',
    		);
    		extract(wp_parse_args($args, $defaults));
    
    		if (!$text) {
    		global $post;
    		$text = $post->post_excerpt ? $post->post_excerpt : $post->post_content;
    		}
    		if (!$pos = strpos($text, '<!--more-->')) {
    
    		$text = preg_replace("!\[/?.*\]!U", '', $text); //убираем шоткоды, например:[singlepic id=3]
    		$text = strip_tags($text, $save_format);
    
    		if (iconv_strlen($text, 'utf-8') > $maxchar) {
    			$text = iconv_substr($text, 0, $maxchar, 'utf-8');
    			$text = preg_replace('@(.*)\s[^\s]*$@s', $text_finish, $text); //убираем последнее слово, ибо оно в 99% случаев неполное
    		}
    
    		if ($save_format) {
    			$text = str_replace("\r", '', $text);
    			$text = preg_replace("!\n\n+!", "</p><p>", $text);
    			$text = "<p>" . str_replace("\n", "<br />", trim($text)) . "</p>";
    		}
    		} else {
    		$text = substr($text, 0, $pos);
    		}
    		if ($echo)
    		return print $text;
    		return $text;
    	}
    Ответить5.2 лет назад #
  • Игорь

    Спасибо, полезная функция, пользуюсь. Но есть недостаток, не обрезает caption у изображений.

    Ответить5.2 лет назад #
    • veeXit vasily.pw

      Тоже столкнулся с тем, что kama excerpt упорно выводит caption изображения. Пофиксил следующим образом:

      Заменил строку с вырезанием шоткодов

      $text = preg_replace ("~\[/?.*?\]~", '', $text ); // убираем шоткоды, например:[singlepic id=3]

      на wpшную функцию.

      $text = strip_shortcodes( $text ); // убираем шоткоды, например:[singlepic id=3]

      Kama, спасибо за рецепт для excerpt. Если я не прав с фиксом - поправь меня.

      1
      Ответить4.3 года назад #
  • Евгений

    Доброго времени суток!

    Подскажите пожалуйста, тут уже был вопрос без ответа в коментах о том, как обрезать текст из дополнительных/произвольных полей wp.

    Я вывожу в шаблон текст из поля следующим образом:

    <?php echo (get_post_meta($post->ID, 'Описание', true)); ?>

    и не разбираясь в php, не могу никак сообразить, как использовать этот пример:

    $rrr = "Функцию обрезки текста для Worpress, можно применять и на других движках.";
    kama_excerpt("text=$rrr&maxchar=50");

    ведь нельзя сделать так:

    $rrr = "<?php echo (get_post_meta($post->ID, 'Описание', true)); ?>";
    kama_excerpt("text=$rrr&maxchar=50");

    метод тыка не помогает совсем)) объясните пожалуйста

    1
    Ответить5.1 лет назад #
    • Kama7631
      <?php
      $text = get_post_meta( $post->ID, 'Описание', 1);
      kama_excerpt("text=$text&maxchar=50");
      ?>
      Ответить5.1 лет назад #
      • Евгений

        Благодарю Kama, всё работает, теперь первые 3 слова осталось удалить)) В методе тыка всё таки недостаточно попыток былоmosking

        Ответить5.1 лет назад #
Здравствуйте, !     Войти . Зарегистрироваться