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.

This is what I added in my theme's functions.php file to enable formatting for excerpts in Wordpress (source of the tip):

remove_filter('get_the_excerpt', 'wp_trim_excerpt');
add_filter('get_the_excerpt', 'bwp_trim_excerpt');

function bwp_trim_excerpt($text)
{
    $raw_excerpt = $text;
    if ( '' == $text ) {
        $text = get_the_content('');
        $text = strip_shortcodes( $text );
        $text = apply_filters('the_content', $text);
        $text = str_replace(']]>', ']]>', $text);
        $text = strip_tags($text, '<em><strong><i><b><a><code>');
        $excerpt_length = apply_filters('excerpt_length', 55);
        $excerpt_more = apply_filters('excerpt_more', ' ' . '[...]');
        $words = preg_split("/[\n\r\t ]+/", $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY);
        if ( count($words) > $excerpt_length ) {
            array_pop($words);
            $text = implode(' ', $words);
            $text = $text . $excerpt_more;
        } else {
            $text = implode(' ', $words);
        }
    }
    return apply_filters('wp_trim_excerpt', $text, $raw_excerpt);
}

The problem with enabling formatting in post excerpts seems to be that, if the text that is formatted by a tag (be it <b>, <strong>, <i>, <em>, or any other for that matter) is cut off by the excerpt in between, your whole page's formatting will be overridden by that tag. Take a look at this screenshot for instance:

Screenshot

I believe that’s the reason why formatting for excerpts isn’t enabled by default. Is there anyway to fix this? Is something wrong with the code?

Hope I can get some help here. Thanks!

share|improve this question
    
IMPORTANT! Make sure that 'HTML Minification' is turned off, if you are using W3 Total Cache plugin. This is weird, but that's how it is. :) –  its_me Apr 9 '12 at 15:11
    
No solution ever works. You'll somehow end up finding some issue with enabling formatting in excerpts. So I'd recommend anyone to not waste time -- either go with the normal excerpts, or full posts. Just my $0.02. –  its_me Jan 12 '13 at 13:25

2 Answers 2

up vote 5 down vote accepted

This is one of the reasons why HTML markup is removed from excerpts in the first place, to prevent such issues like this from occurring however, where there's a will, there's a way...

You can, through using regular expression, close the open tags applicable to the excerpt only and you might want to take a look at the following link for some ideas,

Close HTML Tags

Or alternatively you can use this plugin ready made for WordPress,

Advanced Excerpt

Or if you feel so inclined you can modify it or sample its structure and apply it to your function.

UPDATE

I decided to run a test, however please note that I've used a different function that I often use when creating excerpts with customizable lengths on the fly;

Put this into your functions.php file,

function content($limit) {
global $content;
  $content = explode(' ', get_the_content(), $limit);
  if (count($content)>=$limit) {
    array_pop($content);
    $content = implode(" ",$content).'...';
  } else {
    $content = implode(" ",$content);
  } 
  $content = preg_replace('/\[.+\]/','', $content);
  $content = apply_filters('the_content', $content); 
  $content = str_replace(']]>', ']]&gt;', $content);
  return $content;
}

followed by,

function closetags($html) {

  #put all opened tags into an array
  $content = $result;
  preg_match_all('#<([a-z]+)(?: .*)?(?<![/|/ ])>#iU', $html, $result);
 $openedtags = $result[1];   #put all closed tags into an array
  preg_match_all('#</([a-z]+)>#iU', $html, $result);
  $closedtags = $result[1];
  $len_opened = count($openedtags);
  # all tags are closed
  if (count($closedtags) == $len_opened) {
    return $html;
  }

  $openedtags = array_reverse($openedtags);
  # close tags
  for ($i=0; $i < $len_opened; $i++) {
    if (!in_array($openedtags[$i], $closedtags)){
      $html .= '</'.$openedtags[$i].'>';
    } else {
      unset($closedtags[array_search($openedtags[$i], $closedtags)]);    }
  }  
    return $html;
} 

Then in your theme you would do the following,

<?php echo closetags( content(55) );?>  

Where 55 = the length in words that you want your excerpt to be.

If you want to make use of the ACTUAL excerpt box within the post edit screen then you can also add this snippet to your functions file,

function excerpt($limit) {
global $excerpt;
  $excerpt = explode(' ', get_the_excerpt(), $limit);
  if (count($excerpt)>=$limit) {
    array_pop($excerpt);
    $excerpt = implode(" ",$excerpt).'...';
  } else {
    $excerpt = implode(" ",$excerpt);
  } 
  $excerpt = preg_replace('/\[.+\]/','', $excerpt);
  $excerpt = apply_filters('the_excerpt', $excerpt);
  $excerpt = str_replace(']]>', ']]&gt;', $excerpt);
  return $excerpt;
}

And its usage would be,

<?php echo closetags( excerpt(55) );?>  

However if using the ACTUAL excerpt box in the post edit screen you would have to manually write your <strong>,<em>,<i>,<a>,etc.. tags of course! Unless you modify the default TinyMCE for the excerpt box.

So there you have it, you are covered in both instances, either...

1) grabbing an excerpt from the_content() 2) grabbing an excerpt from the_excerpt()

NOTE There might be a more efficient way to go about this by writing the functionality of the Close HTML Tags example by Milan in-case you wish to investigate that further.

share|improve this answer
    
yes, I actually just found a more efficient, simpler way. I will post it shortly. Thanks for trying to help. :) –  its_me Apr 7 '12 at 16:38
1  
@geekpanth3r How did you go? I'd be interested see your alternative solution and how or where it is more efficient than the above. It'd be useful to all who come across this thread. –  userabuser Apr 8 '12 at 10:25
    
Actually, I thought I had found one (see my answer), it seemed to work, but it doesn't. I'm working on implementing yours now. Sorry about that. –  its_me Apr 9 '12 at 11:00
    
No problem mate... I had a look at your answer yesterday but did not get a chance to test it. I wonder if the problem lay within force_balance_tags as I noticed that some other people had issues with that. That aside my solution above does work and gives you access to either the_content or the_excerpt should you wish to use either. Additionally in instances where you might want to remove formatting entirely you could call <?php echo strip_tags(content('55')) ;?> or <?php echo strip_tags(excerpt('55')) ;?> for maximum flexibility when accessing content through out your theme. –  userabuser Apr 9 '12 at 11:43
    
Thanks, I am trying your now. –  its_me Apr 9 '12 at 13:23

It's as simple as adding this function to your theme's functions.php file. The code has been commented clearly, so it's self-explanatory:

function better_trim_excerpt($text)
{
    $raw_excerpt = $text;
    if ( '' == $text ) {
        $text = get_the_content('');
        $text = strip_shortcodes( $text );
        $text = apply_filters('the_content', $text);
        $text = str_replace(']]>', ']]&gt;', $text);

        // Removes any JavaScript in posts (between <script> and </script> tags)
        $text = preg_replace('@<script[^>]*?>.*?</script>@si', '', $text);

        // Enable formatting in excerpts - Add HTML tags that you want to be parsed in excerpts, default is 55
        $text = strip_tags($text, '<strong><b><em><i><a><code><kbd>');

        // Set custom excerpt length - number of words to be shown in excerpts
        $excerpt_length = apply_filters('excerpt_length', 55);

        // Modify excerpt more string at the end from [...] to ...
        $excerpt_more = apply_filters('excerpt_more', ' ' . '...');

        $words = preg_split("/[\n\r\t ]+/", $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY);
        if ( count($words) > $excerpt_length ) {
            array_pop($words);
            $text = implode(' ', $words);

            // IMPORTANT! Prevents tags cutoff by excerpt (i.e. unclosed tags) from breaking formatting
            $text = force_balance_tags( $text );

            $text = $text . $excerpt_more;
        } else {
            $text = implode(' ', $words);
        }
    }
    return apply_filters('wp_trim_excerpt', $text, $raw_excerpt);
}

// Remove the native excerpt function, and replace it with our improved function
remove_filter('get_the_excerpt', 'wp_trim_excerpt');
add_filter('get_the_excerpt', 'better_trim_excerpt');

EDIT: And make sure, HTML minification is turned off in W3 Total Cache (if you are using it).

[Source Article]

share|improve this answer

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.