Here is a different solution, which uses Wordpress in-built wp_trim_words() function to determine roughly how long the text should be, and then truncates the text at the end of that sentence (a little longer than the number of words specified).
Usage: echo im_trim_sentences($very_long_text, 90);
A custom "strpos_array()" function has also been included in this answer, because PHP's strpos() function only accepts a string as the $needle, but we want to search for different sentence endings (full stop, or exclamation mark, etc).
function strpos_array($haystack, $needles, $offset = 0) {
if (is_array($needles)) {
$positions = array();
foreach ($needles as $str) {
$pos = strpos($haystack, $str, $offset);
if ($pos !== false) {
$positions[] = $pos;
}
}
return (count($positions) ? min($positions): false);
} else {
return strpos($haystack, $needles, $offset);
}
}
function im_trim_sentences($text, $number_of_words = 55, $more = null) {
$allowed_end = array('.', '!', '?', '...');
$text_no_html = strip_tags($text);
$trimmed_text = wp_trim_words($text, $number_of_words, $more);
$trimmed_text_length = strlen($trimmed_text);
$sentence_end_position = strpos_array($text_no_html, $allowed_end, $trimmed_text_length);
$text_with_html = (($sentence_end_position !== false) ? substr($text_no_html, 0, ($sentence_end_position + 1)) : $trimmed_text);
return wpautop($text_with_html);
}