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 Все
  • Boocho

    Привет автору. Спасибо за статью и за работу.
    Но возник один вопросец. Можно ли сделать так, чтобы функция игнорировала <!--more--> и резала цитату нужной длины вне зависимости где он в статье стоит? Удалять из кучи статей его не очень интересное занятие. smile

    Ответить9.4 лет назад #
    • Kama7631

      Можно конечно. Удалите из функции строки 20-26 (включительно), т.е. вот это условие:

      if ($cont){ preg_match ('/(.*)<!--more-->/s',$out,$match);
      ...
      Ответить9.4 лет назад #
  • Boocho

    Спасибо большое, работает.

    Ответить9.4 лет назад #
  • Алексей

    да, очередное мерси.. налаживаю wp, и как то интуитивно начал брать рецепты с этого сайта... так functions.php пополнился function kama_postviews(), kama_get_most_viewed(), function kama_meta_title() и его два брата, (+ защита от спама, но еще сайт не на сервере, так что пока сказать о нем нечего) теперь и kama_excerpt()

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

    в связи с этим еще вопрос... использую плагин Get The Image (боялся, что kama_excerpt() не будет фурычить), он позволяет подгружать миниатюры к статьям и вставляет его к аноносам на главной - сайт красивше становится... есть какие-то мнения на счет рациональности использования данного плагина?

    Ответить9.2 лет назад #
    • Kama7631

      использую плагин Get The Image

      Не знаком с этим плагином.

      Моя функция цитаты kama_excerpt() всего лишь выдирает текст с различными условиями: сначала проверяется наличие "цитаты", потом тега more, если ничего этого нет, то выводится верхняя часть текста. Все теги при этом вырезаются, поэтому миниатюру выводить нужно отдельно. Работа с миниатюрами в функции не предусмотрена.

      Для миниатюр я использую свою функцию, точнее несколько функций. Вскоре выложу здесь, только соберу все это дело в боле менее компактный вид.

      Если есть время, можете подождать, станете "летчиком испытателем" smile

      Ответить9.2 лет назад #
  • Stranger

    Спасибо огромное, очень помогло.
    А подскажи пожалуйста, как сделать чтоб вместо "..." в конце текста выводилось "Подробнее" с ссылкой на этот пост?

    Ответить9.2 лет назад #
    • Kama7631

      Пожалуйста!

      А подскажи пожалуйста, как сделать чтоб вместо "..."

      замените:

      $out = join(' ', array_slice($words, 0, $maxwords)).' ...';

      на

      $out = join(' ', array_slice($words, 0, $maxwords)).'<p class="more">'.get_permalink($post->ID).'</p>';
      1
      Ответить9.2 лет назад #
  • Stranger

    Спасибо, немного не то, но ты подсказал правильное решение smile
    т.к. мне нужна была ссылка, я сделал так:

    $out = join(' ', array_slice($words, 0, $maxwords)).'<a href="'.get_permalink($post->ID).'">more...</a>';
    Ответить9.2 лет назад #
  • Stranger

    И еще вопрос, если в посте есть картинки, как сделать, чтоб твоя функция вытягивала первую картинку и ставила ее вместе с текстом в превьюхе поста?

    Ответить9.2 лет назад #
    • Kama7631

      Эта функция обрабатывает только текст, предварительно почистив его от html тегов, а значит и картинок.

      Чтобы картинка осталась, нужно использовать WordPress-овский тег more при написании поста, тогда функция будет выводить все что до more, с картинками и форматированием (ничего вырезаться не бдует).

      Ответить9.2 лет назад #
  • @ Валентин anokalintik.ru

    По ходу очень полезная штука
    Немного подробнее про этот момент можно:

    Чтобы заменить стандартный the_exerpt() нужно просто заменить the_exerpt(); на kama_excerpt(); Все это должно быть внутри цикла the loop. ВАЖНО! Парметр text при замене the_exerpt(); указывать не надо!

    Нужно заменить код функции the_exerpt() на код kama_excerpt() в файле\wp-admin\includes\template.php где прописана функция the_exerpt()?

    Или везде где упоминается the_exerpt() заменить на kama_excerpt()?
    Еще есть встречал такую фишку $output = get_the_excerpt(); тут что-то нужно менять или нет.

    Код вашей функции kama_excerpt(); я уже вставил в файл темы functions.php

    Заранее сенк

    Ответить9.2 лет назад #
    • Kama7631

      Нужно заменить код функции the_exerpt() на код kama_excerpt() в файле\wp-admin\includes\template.php где прописана функция the_exerpt()?

      Нет! Файлы движка трогать не нужно!
      Нужно менять the_exerpt() на код kama_excerpt() в шаблоне, везде где встречается.

      Еще есть встречал такую фишку $output = get_the_excerpt(); тут что-то нужно менять или нет.

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

      Ответить9.2 лет назад #
  • @ Апокалиптик anokalintik.ru

    Я в шаблоне вообще не нашел the_exerpt(). Сайт на этом шаблоне вот razgovorcnik.ru там очень рано обрезает пост возле превьюшек, вот сайт womantrick.ru на этом движке и там уже правильно обрезается, и в конце цитаты стоит "..."

    На одном тестовом сайте moloduelydi.ru я запостил текст на английском, там обрезалось гораздо позже, хотя все равно на пол слове оборвалось.

    Можешь помочь? Я этот шаблон купил в буржнете за 10 у.е. может вся проблема что он под английский заточен. Я могу на мыло кинуть шаблон + PSD ты глянешь и подскажешь как решить, ну и себе шаблон оставишь smile

    Ответить9.2 лет назад #
  • Lovedancer www.alliance.zp.ua

    Добрый день, если можете, подскажите пожалуйста, что нужно прописать и где, что-бы посты в разделе тэгов и в разделе архивов - не выводились целиком, тем самым дублируя основные посты, а только выводились названия постов....? Я в принципе знаю, что это делается с помощью функции php the_excerpt, которая в свою очередь прописывается например в tag.php ...но просто в этой теме нет отдельного tag.php, а если этот код прописать в archive.php, то тогда не полностью будут выводиться и тэги, и архивы и категории, а мне нужно только тэги и архивы. Помогите пожалуйста.

    Ответить9.1 лет назад #
    • Kama7631

      В этом файле (archive.php) замените the_excerpt(); на это:

      if(!is_tag() || !is_date()) the_excerpt();

      этим кодом мы как бы вырезаем функцию the_excerpt(); для станиц-типов меток (is_tag()) и всех видов дат (архивов) (is_date()).

      Про условные теги тут почитайте.

      Ответить9.1 лет назад #
      • Lovedancer www.alliance.zp.ua

        Спасибо вам огромное. Но я уже нашёл другое решение smile

        Ответить9.1 лет назад #
  • @ Alex nelsa.eu

    Привет!
    Скажи, ведь это решение просто обрезает посты на лету, т.е. при отображении, а можно ли его заточить так, чтобы посты резались прямо в базе, т.е. тег

    <!--more-->

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

    <!--more-->

    . Нечто подобное выполняет плагин "Search & Replace", но он делает это не на автомате, а когда его запускаешь. Дело в том, что мне нужно делать кросспост в ЖЖ, а посты заходят в вордпресс на автомате через внешний РСС - т.е. все автоматизировано, не хватает только этого решения с автообрезкой поста...

    Ответить9 лет назад #
    • Kama7631

      Вам нужно конкретное решение индивидуальной проблемы, как я понимаю. Сделать так как вы говорите конечно можно, только нужно подробнее вникнуть в суть вопроса, я не уверен, что вообще правильно понял что вам нужно smile

      Если проблема в том, что в ЖЖ нужно отдавать анонс (часть статьи), то отдавайте туда свой неполный RSS.

      Подробнее ответить не смогу, я вопроса не понял smile

      Ответить9 лет назад #
      • @ Alex nelsa.eu

        Да, извини, сам понимаю, что сумбурно все описал... Я тяну посты с внешнего рсс (через трубы), и затем отправляю их в ЖЖ при помощи LJXP (плагин для кросспостинга). Иногда попадаются очень длинные посты и их нужно резать непосредственно в вордпрессе тегом "more", чтобы LJXP уже передавал в ЖЖ обрезанные посты (он позволяет конвертировать вордпрессовский "more" в lj-cut). Все плагины, что мне встречались, режут пост только при отображении, но не в БД, т.е. в ЖЖ пост передается целым, как есть. Вот и нужно, чтобы посты резались при записи в БД по опр. параметрам (длинна символов или кол. абзацев). Где-то так...

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