WordPress как на ладони
Недорогой хостинг для сайтов на WordPress: wordpress.jino.ru WPmentor - Ищем топовых специалистов по WordPress, чтобы помочь вам заработать

Обрезка текста и/или замена стандартной функции 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.5
 */
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'   => 'Читать дальше...', // Текст ссылки `Читать дальше`.
		'ignore_more' => false, // нужно ли игнорировать <!--more--> в контенте
	), $args );

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

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

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

	// <!--more-->
	if( ! $rg->ignore_more  &&  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.5 - Параметр ignore_more
 * 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 - это количество оставляемых символов.

144 коммента
Полезные 4 Вопросы 2 Все
  • Валера, твой час настал!
    /*/ для тега <!--more-->  
    		if( !$post->post_excerpt && strpos($post->post_content, '<!--more-->') ){  
    			preg_match ('/(.*)<!--more-->/s', $out, $match);  
    			$out = str_replace("\r", '', trim($match[1], "\n"));  
    			$out = preg_replace( "!\n\n+!s", "</p><p>", $out );  
    			$out = "<p>". str_replace( "\n", "<br />", $out ) ."</p>";  
    			if ($echo)  
    				return print $out;  
    			return $out;  
    		}  */

    если сделать так, то убивает картинки, но мне нужно до тега more выводить.

    Ответить20.Июл.2012 в 22:05 #
  • Валера, твой час настал!

    сделал так, мало ли кому понадобится)

    // для тега <!--more-->  
    		if( !$post->post_excerpt && strpos($post->post_content, '<!--more-->') ){  
    			preg_match ('/(.*)<!--more-->/s', $out, $match); 
    		}           
    			$out = str_replace("\r", '', trim($match[1], "\n"));  
    			$out = preg_replace( "!\n\n+!s", "</p><p>", $out );  
    			$out = "<p>". str_replace( "\n", "<br />", $out ) ."</p>";  
    			/*if ($echo)  
    				return print $out;  
    			return $out;  
    		}  */
    Ответить20.Июл.2012 в 22:35 #
  • Timur

    Приветствую Тимур! Не пойму в чем дело..при обрезке с помощью этой функции выдержки в кастом пост тайпе в конце вечно добавляется "1"(т.е. укажу например макс.кол-во символов 100, в конце будет "...1"), что только не перепробовал, все равно появляется( Может ты сталкивался?

    Ответить25.Авг.2012 в 15:12 #
    • Timur

      ОТМЕНА. Проблема в плохом знании php, пытался функцию kama_excerpt добавить в переменную, дабы если выдержки нет - ничего не выводить, но потом понял, что-то это проверка уже имеется в функции( поэтому извиняюсь..

      Ответить25.Авг.2012 в 15:24 #
  • Сергей webmasterprof.ru

    Привет. А такой вопрос, а можно ли в анонсе с тегом "more" вырезать все ссылки?

    Тоесть длина текста обозначена, но нужно, что бы ссылки на нем стали не активны.

    Ответить07.Сен.2012 в 00:41 #
  • vlad

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

    Ответить01.Дек.2012 в 01:27 #
  • BG bigresult.ru

    Спавибо! Все супер работает.
    Сделал вашей функцией в блоке http://bigresult.ru/razdelnoe-pitanie-vsyo-chto-nuzhno-znat, чем на главной выводится. Теперь у меня 2 функции the_excerpt() и kama_excerp (). Блин, а до этого я голову ломал как это сделать..

    Ответить10.Фев.2013 в 13:07 #
  • Олег

    А почему после

    $out = $text.$out;

    не добавили

    $out = preg_replace ("!\[/?.*\]!U", '', $out );

    ?
    Ведь тогда, если передавать текст через переменную, шорткоды не убираются.

    Ответить03.Июн.2013 в 22:27 #
  • Андрей gamestrong.ru

    Красавчик, искал долго только такой код смог вывести по кол символов респектос

    Ответить14.Сен.2013 в 10:24 #
  • adward7 cimetrica.ru

    Была идея обрезать текст до первой точки.
    Сложно такое реализовать

    Ответить27.Сен.2013 в 01:45 #
    • Kama7682
      $text = "Мама на даче, ключ на столе, 
      завтрак можно не делать. 
      Скоро каникулы, восемь лет, 
      в августе будет девять.";
      
      preg_match('~^[^\.]+\.~s', $text, $match);
      $text = $match[0];
      echo $text;

      Вернет

      Мама на даче, ключ на столе, 
      завтрак можно не делать.
      Ответить27.Сен.2013 в 12:44 #
      • adward7 cimetrica.ru

        Спасибо! -)

        Ответить27.Сен.2013 в 13:56 #
      • Витаха remenbest.com

        А чтоб после первой (второй) точки? Так ведь тоже можно

        Ответить27.Сен.2013 в 16:00 #
        • Kama7682

          Ну да, тоже самое почти:

          $text = "11111 1111111 11. 
          Скоро каникулы, восемь лет, 
          в августе будет девять.
          11111 11111 111.";
          
          preg_match('~\.([^\.]+\.)~s', $text, $match);
          $text = trim($match[1]);
          echo $text;

          Вернет:

          Скоро каникулы, восемь лет, 
          в августе будет девять.
          Ответить27.Сен.2013 в 17:04 #
        • adward7 cimetrica.ru

          Как правило, для грамотной аннотации достаточно первого предложения.

          Едиснтвенный вопрос, который тут возникает - это может случиться так, что статья начинается не с предложения, а, к примеру, с таблицы, у которой 100500 строк. И в этом случае - наш своеобразный "эксерпт" будет длинным и бесмысленным.

          Тут надо расширить задачу, думаю, до следующего условия:
          1) если присутствует у поста цитату - использовать её;
          2) если нет - использовать первое предложение;
          3) если первое предложение длиннее 160 символов (что весьма вероятно в случае с таблицей) - обрезать до первого пробела после 160 символов.

          вот такой, своеобразный kama_excerpt, я считаю, будет идеальным решением wink

          Ответить27.Сен.2013 в 17:07 #
          • Otshelnik-Fm228 otshelnik-fm.ru

            если вы обрежете таблицу - верстка поплывет, т.к. обрежется.

            Я думаю что если есть такие специфические частные случаи - то не стоит их внедрять в функцию предназначенною для масс. А то получится как с плагином - сначала он выполняет свою задачу, а потом вырастает до монстра. Описание к которому состоит из 100 страниц

            Ответить27.Сен.2013 в 19:28 #
  • @ Виктор stat-krasivoi.ru

    А можно как-то подправить регулярное выражение, чтобы убиралась вся строка?

    [caption id="attachment_1109"]<a href="#"><img src="http://**.jpg"/></a> уход за волосами[/caption]

    Остается подпись к картинке, т.е. "уход за волосами". Или подскажите откуда взять в параметр text вашей функции полностью очищенный текст от форматирования и ссылок(как в rss).

    Ответить28.Сен.2013 в 22:27 #