Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

Here is the excerpt of the post on my home page. I want to end the excerpt with a sentence. In this case it is ' opportunities. '. I know how to modify the length but it won't do what i want.

enter image description here

Here is excerpt from other website. Here you see excerpt ending with a proper sentence unlike the above which ends with the first word of next sentence 'Proactively'.

enter image description here

After Implementing the solution by G.M. :-

enter image description here

share|improve this question
    
Please explain your issue better than that. From the answers and comments on them, it's hard to understand what you want to achieve. –  kaiser Aug 3 '13 at 14:03
    
@kaiser I have updated the details. –  Mohit Aug 3 '13 at 14:20
    
@Mohit have you tryed my code? –  G. M. Aug 3 '13 at 14:25
    
Yes, excerpt ends with sentence but 'Read More' is gone. –  Mohit Aug 3 '13 at 14:31
    
@G.M. Alright i have to add the read more in the return. –  Mohit Aug 3 '13 at 14:34
show 1 more comment

2 Answers

up vote 9 down vote accepted

This requires PHP 5.3+ (WP requires PHP 5.2.4+)

add_filter('get_the_excerpt', 'end_with_sentence');

function end_with_sentence($excerpt) {
  $allowed_end = array('.', '!', '?', '...');
  $exc = explode( ' ', $excerpt );
  $found = false;
  $last = '';
  while ( ! $found && ! empty($exc) ) { 
    $last = array_pop($exc);
    $end = strrev( $last );
    $found = in_array( $end{0}, $allowed_end );
  }
  return (! empty($exc)) ? $excerpt : rtrim(implode(' ', $exc) . ' ' .$last);
}

Edit

After @kaiser comment I try to run this on save/update to prevent page slow down on showing a lot of posts. This should be tested

add_filter('wp_insert_post_data', 'end_with_sentence_on_save', 20, 2);

function end_with_sentence_on_save($data, $postarr) {
  if ( ! empty( $data['post_content'] ) && $data['post_status'] != 'inherit' && $data['post_status'] != 'trash' ) {
    $text = strip_shortcodes( $data['post_content'] );
    $text = apply_filters('the_content', $text );
    $text = str_replace(']]>', ']]>', $text );
    $excerpt_length = apply_filters('excerpt_length', 55);
    $data['post_excerpt'] = wp_trim_words($text, $excerpt_length, '');
  } else {
    return $data;
  }
  $allowed_end = array('.', '!', '?', '...');
  $exc = explode(' ', $data['post_excerpt']);
  $found = false;
  $last = '';
  while ( ! $found && ! empty($exc) ) { 
    $last = array_pop($exc);
    $end = strrev( $last );
    $found = in_array( $end{0}, $allowed_end );
  }
  if (! empty($exc)) $data['post_excerpt'] = rtrim(implode(' ', $exc) . ' ' .$last);
  return $data; 
}
share|improve this answer
1  
sure about that: $end{0}? Btw, you could just return or break when something is found. Additional note: It might better to that when saving the post, so it's not regenerated during runtime, which can get quite slow if you're displaying lots of posts. –  kaiser Aug 3 '13 at 14:02
    
@kaiser cite: Strings may also be accessed using braces, as in $str{42}, for the same purpose. php.net docs To find something I had to find last char of last string. Using $found I break the cycle and check last string, so no need to break. –  G. M. Aug 3 '13 at 14:10
    
Completely missed that it's a while checking for false. +1 –  kaiser Aug 3 '13 at 14:16
    
@kaiser +1 for the second part of your comment, now I edit the code to run on save –  G. M. Aug 3 '13 at 14:31
1  
Sure @jessica was a bad edit (in the original version it was ok). Thanks, fixed. –  G. M. Apr 12 at 10:05
show 6 more comments

Here is my version, keeping all html tags and also trimming the content after the last word in of a sentence

if ( ! function_exists( 'pietergoosen_custom_wp_trim_excerpt' ) ) : 

    function pietergoosen_custom_wp_trim_excerpt($pietergoosen_excerpt) {
    global $post;
    $raw_excerpt = $pietergoosen_excerpt;
        if ( '' == $pietergoosen_excerpt ) {

            $pietergoosen_excerpt = get_the_content('');
            $pietergoosen_excerpt = strip_shortcodes( $pietergoosen_excerpt );
            $pietergoosen_excerpt = apply_filters('the_content', $pietergoosen_excerpt);
            $pietergoosen_excerpt = str_replace(']]>', ']]>', $pietergoosen_excerpt);

            //Set the excerpt word count and only break after sentence is complete.
                $excerpt_word_count = 75;
                $excerpt_length = apply_filters('excerpt_length', $excerpt_word_count); 
                $tokens = array();
                $excerptOutput = '';
                $count = 0;

                // Divide the string into tokens; HTML tags, or words, followed by any whitespace
                preg_match_all('/(<[^>]+>|[^<>\s]+)\s*/u', $pietergoosen_excerpt, $tokens);

                foreach ($tokens[0] as $token) { 

                    if ($count >= $excerpt_word_count && preg_match('/[\?\.\!]\s*$/uS', $token)) { 
                    // Limit reached, continue until  ? . or ! occur at the end
                        $excerptOutput .= trim($token);
                        break;
                    }

                    // Add words to complete sentence
                    $count++;

                    // Append what's left of the token
                    $excerptOutput .= $token;
                }

            $pietergoosen_excerpt = trim(force_balance_tags($excerptOutput));

                $excerpt_end = ' <a href="'. esc_url( get_permalink() ) . '">' . '&nbsp;&raquo;&nbsp;' . sprintf(__( 'Read more about: %s &nbsp;&raquo;', 'pietergoosen' ), get_the_title()) . '</a>'; 
                $excerpt_more = apply_filters('excerpt_more', ' ' . $excerpt_end); 

                //$pos = strrpos($pietergoosen_excerpt, '</');
                //if ($pos !== false)
                // Inside last HTML tag
                //$pietergoosen_excerpt = substr_replace($pietergoosen_excerpt, $excerpt_end, $pos, 0);
                //else
                // After the content
                $pietergoosen_excerpt .= $excerpt_end;

            return $pietergoosen_excerpt;   

        }
        return apply_filters('pietergoosen_custom_wp_trim_excerpt', $pietergoosen_excerpt, $raw_excerpt);
    }

endif; 

remove_filter('get_the_excerpt', 'wp_trim_excerpt');
add_filter('get_the_excerpt', 'pietergoosen_custom_wp_trim_excerpt'); 
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.