bp_create_excerpt( string $text, int $length = 225, array $options = array() )

Truncate text.


Description Description

Cuts a string to the length of $length and replaces the last characters with the ending if the text is longer than length.

This function is borrowed from CakePHP v2.0, under the MIT license. See http://book.cakephp.org/view/1469/Text#truncate-1625


Parameters Parameters

$text

(Required) String to truncate.

$length

(Optional) Length of returned string, including ellipsis. Default: 225.

Default value: 225

$options

(Optional) An array of HTML attributes and options. Each item is optional.

  • 'ending'
    (string) The string used after truncation. Default: ' […]'.
  • 'exact'
    (bool) If true, $text will be trimmed to exactly $length. If false, $text will not be cut mid-word. Default: false.
  • 'html'
    (bool) If true, don't include HTML tags when calculating excerpt length. Default: true.
  • 'filter_shortcodes'
    (bool) If true, shortcodes will be stripped. Default: true.
  • 'strip_tags'
    (bool) If true, HTML tags will be stripped. Default: false. Only applicable if $html is set to false.
  • 'remove_links'
    (bool) If true, URLs will be stripped. Default: false. Only applicable if $html is set to false.

Default value: array()


Top ↑

Return Return

(string) Trimmed string.


Top ↑

Source Source

File: bp-core/bp-core-template.php

function bp_create_excerpt( $text, $length = 225, $options = array() ) {

	// Backward compatibility. The third argument used to be a boolean $filter_shortcodes.
	$filter_shortcodes_default = is_bool( $options ) ? $options : true;

	$r = bp_parse_args( $options, array(
		'ending'            => __( ' […]', 'buddypress' ),
		'exact'             => false,
		'html'              => true,
		'filter_shortcodes' => $filter_shortcodes_default,
		'strip_tags'        => false,
		'remove_links'      => false,
	), 'create_excerpt' );

	// Save the original text, to be passed along to the filter.
	$original_text = $text;

	/**
	 * Filters the excerpt length to trim text to.
	 *
	 * @since 1.5.0
	 *
	 * @param int $length Length of returned string, including ellipsis.
	 */
	$length = apply_filters( 'bp_excerpt_length',      $length      );

	/**
	 * Filters the excerpt appended text value.
	 *
	 * @since 1.5.0
	 *
	 * @param string $value Text to append to the end of the excerpt.
	 */
	$ending = apply_filters( 'bp_excerpt_append_text', $r['ending'] );

	// Remove shortcodes if necessary.
	if ( ! empty( $r['filter_shortcodes'] ) ) {
		$text = strip_shortcodes( $text );
	}

	// When $html is true, the excerpt should be created without including HTML tags in the
	// excerpt length.
	if ( ! empty( $r['html'] ) ) {

		// The text is short enough. No need to truncate.
		if ( mb_strlen( preg_replace( '/<.*?>/', '', $text ) ) <= $length ) {
			return $text;
		}

		$totalLength = mb_strlen( strip_tags( $ending ) );
		$openTags    = array();
		$truncate    = '';

		// Find all the tags and HTML comments and put them in a stack for later use.
		preg_match_all( '/(<\/?([\w+!]+)[^>]*>)?([^<>]*)/', $text, $tags, PREG_SET_ORDER );

		foreach ( $tags as $tag ) {
			// Process tags that need to be closed.
			if ( !preg_match( '/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s',  $tag[2] ) ) {
				if ( preg_match( '/<[\w]+[^>]*>/s', $tag[0] ) ) {
					array_unshift( $openTags, $tag[2] );
				} elseif ( preg_match('/<\/([\w]+)[^>]*>/s', $tag[0], $closeTag ) ) {
					$pos = array_search( $closeTag[1], $openTags );
					if ( $pos !== false ) {
						array_splice( $openTags, $pos, 1 );
					}
				}
			}

			$truncate     .= $tag[1];
			$contentLength = mb_strlen( preg_replace( '/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $tag[3] ) );

			if ( $contentLength + $totalLength > $length ) {
				$left = $length - $totalLength;
				$entitiesLength = 0;
				if ( preg_match_all( '/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', $tag[3], $entities, PREG_OFFSET_CAPTURE ) ) {
					foreach ( $entities[0] as $entity ) {
						if ( $entity[1] + 1 - $entitiesLength <= $left ) {
							$left--;
							$entitiesLength += mb_strlen( $entity[0] );
						} else {
							break;
						}
					}
				}

				$truncate .= mb_substr( $tag[3], 0 , $left + $entitiesLength );
				break;
			} else {
				$truncate .= $tag[3];
				$totalLength += $contentLength;
			}
			if ( $totalLength >= $length ) {
				break;
			}
		}
	} else {
		// Strip HTML tags if necessary.
		if ( ! empty( $r['strip_tags'] ) ) {
			$text = strip_tags( $text );
		}

		// Remove links if necessary.
		if ( ! empty( $r['remove_links'] ) ) {
			$text = preg_replace( '#^\s*(https?://[^\s"]+)\s*$#im', '', $text );
		}

		if ( mb_strlen( $text ) <= $length ) {
			/**
			 * Filters the final generated excerpt.
			 *
			 * @since 1.1.0
			 *
			 * @param string $truncate      Generated excerpt.
			 * @param string $original_text Original text provided.
			 * @param int    $length        Length of returned string, including ellipsis.
			 * @param array  $options       Array of HTML attributes and options.
			 */
			return apply_filters( 'bp_create_excerpt', $text, $original_text, $length, $options );
		} else {
			$truncate = mb_substr( $text, 0, $length - mb_strlen( $ending ) );
		}
	}

	// If $exact is false, we can't break on words.
	if ( empty( $r['exact'] ) ) {
		// Find the position of the last space character not part of a tag.
		preg_match_all( '/<[a-z\!\/][^>]*>/', $truncate, $_truncate_tags, PREG_OFFSET_CAPTURE );

		// Rekey tags by the string index of their last character.
		$truncate_tags = array();
		if ( ! empty( $_truncate_tags[0] ) ) {
			foreach ( $_truncate_tags[0] as $_tt ) {
				$_tt['start'] = $_tt[1];
				$_tt['end']   = $_tt[1] + strlen( $_tt[0] );
				$truncate_tags[ $_tt['end'] ] = $_tt;
			}
		}

		$truncate_length = mb_strlen( $truncate );
		$spacepos = $truncate_length + 1;
		for ( $pos = $truncate_length - 1; $pos >= 0; $pos-- ) {
			// Word boundaries are spaces and the close of HTML tags, when the tag is preceded by a space.
			$is_word_boundary = ' ' === $truncate[ $pos ];
			if ( ! $is_word_boundary && isset( $truncate_tags[ $pos - 1 ] ) ) {
				$preceding_tag    = $truncate_tags[ $pos - 1 ];
				if ( ' ' === $truncate[ $preceding_tag['start'] - 1 ] ) {
					$is_word_boundary = true;
					break;
				}
			}

			if ( ! $is_word_boundary ) {
				continue;
			}

			// If there are no tags in the string, the first space found is the right one.
			if ( empty( $truncate_tags ) ) {
				$spacepos = $pos;
				break;
			}

			// Look at each tag to see if the space is inside of it.
			$intag = false;
			foreach ( $truncate_tags as $tt ) {
				if ( $pos > $tt['start'] && $pos < $tt['end'] ) {
					$intag = true;
					break;
				}
			}

			if ( ! $intag ) {
				$spacepos = $pos;
				break;
			}
		}

		if ( $r['html'] ) {
			$bits = mb_substr( $truncate, $spacepos );
			preg_match_all( '/<\/([a-z]+)>/', $bits, $droppedTags, PREG_SET_ORDER );
			if ( !empty( $droppedTags ) ) {
				foreach ( $droppedTags as $closingTag ) {
					if ( !in_array( $closingTag[1], $openTags ) ) {
						array_unshift( $openTags, $closingTag[1] );
					}
				}
			}
		}

		$truncate = rtrim( mb_substr( $truncate, 0, $spacepos ) );
	}
	$truncate .= $ending;

	if ( !empty( $r['html'] ) ) {
		foreach ( $openTags as $tag ) {
			$truncate .= '</' . $tag . '>';
		}
	}

	/** This filter is documented in /bp-core/bp-core-template.php */
	return apply_filters( 'bp_create_excerpt', $truncate, $original_text, $length, $options );
}

Top ↑

Changelog Changelog

Changelog
Version Description
2.6.0 Added 'strip_tags' and 'remove_links' as $options args.
1.0.0 Introduced.

Top ↑

User Contributed Notes User Contributed Notes

You must log in before being able to contribute a note or feedback.