Fixing The Excerpt In WordPress

WordPress theme designers, as well as “hobbyist” designers will most likely be familiar with WordPress’ the_excerpt() Template Tag; a post excerpt is displayed as a summary of the post wherever the_excerpt() is used. However it does have some limitations, such as stripping HTML tags, and not stripping JavaScript.

The best solution we have found to these limitations was provided by Aaron Russell, but this also had just a couple of stumbling blocks, as evidenced by reading through the comments section of Aaron’s post.

We here at Palehorse have come up with solutions to two of the weak points brought to light by Aaron’s readers, and have updated the function for WordPress 2.9 and above.

The two upgrades to the function deal with un-closed HTML tags, and adding a “read more” link (or some sort of anchor tag) to the ‘[...]‘ string at the end of the excerpt.

Here is Aaron’s original solution:

function improved_trim_excerpt($text) {
	global $post;
	if ( '' == $text ) {
		$text = get_the_content('');
		$text = apply_filters('the_content', $text);
		$text = str_replace(']]>', ']]>', $text);
		$text = preg_replace('@<script[^>]*?>.*?</script>@si', '', $text);
		$text = strip_tags($text, '<p>');
		$excerpt_length = 80;
		$words = explode(' ', $text, $excerpt_length + 1);
		if (count($words)> $excerpt_length) {
			array_pop($words);
			array_push($words, '[...]');
			$text = implode(' ', $words);
		}
	}
	return $text;
}
remove_filter('get_the_excerpt', 'wp_trim_excerpt');
add_filter('get_the_excerpt', 'improved_trim_excerpt');

Our upgrades include the new (in WordPress 2.9) excerpt_more filter hook, to which we have added a permalink in order to get a “read more” link. Of course we had come up with an elegant solution for this, only to discover that the designers were once again one step ahead of us. So the function has been updated with the new hook. I hate love it when that happens.

Next, in order to prevent any “snipped” HTML tags, we added this line:

$text = force_balance_tags( $text );

That will balance any open tags automatically.

Putting it all together is a bit involved, but is achieved by just “plugging in” a few lines of code. Instead of explaining the whole thing line-by-line, I will just post the final code in toto, with comments where we have added the fixes. If anyone has any questions, just leave a comment and I’ll explain further, if required.

The completed, augmented improved_trim_excerpt() function:

/**
 * Generates an improved excerpt from the content, if needed
 *
 * The excerpt word amount will be 80 words and if the amount is greater than
 * that, then the string '[...]' will be appended to the excerpt. If the string
 * is less than 80 words, then the content will be returned as is.
 *
 * The 80 word limit can be modified by plugins/themes using the excerpt_length filter
 * The '[...]' string can be modified by plugins/themes using the excerpt_more filter
 *
 * @link http://www.aaronrussell.co.uk/blog/improving-wordpress-the_excerpt/
 * @link http://palehorseinformation.com/2009/12/23/fixing-the-wordpress-excerpt/
 *
 * @param string $text The excerpt. If set to empty an excerpt is generated.
 * @return string The excerpt.
 */
function improved_trim_excerpt( $text ) {
	if ( '' == $text ) {
		$permalink = get_permalink();	// my addition
		$text = get_the_content( '' );
		$text = strip_shortcodes( $text );
		$text = apply_filters( 'the_content', $text );
		$text = preg_replace( '@<script[^>]*?> . *?</script>@si', '', $text );
		$text = str_replace( ']]>', ']]>', $text );
		$text = strip_tags( $text, '<b><em><i><p><strong><sub><sup>' ); // allowed tags (change as needed)
		$excerpt_length = apply_filters( 'excerpt_length', 80 );
		$excerpt_more = apply_filters('excerpt_more', ' ' . '<em><a href="' . $permalink . '">[...]</a></em>');	// my addition
		$words = explode( ' ', $text, $excerpt_length + 1 );
		if ( count( $words ) > $excerpt_length ) {
			array_pop( $words );
			$text = implode( ' ', $words );
			$text = $text . $excerpt_more;
			$text = force_balance_tags( $text );	// my addition
		}
	}
	return $text;
}
remove_filter( 'get_the_excerpt', 'wp_trim_excerpt' );
add_filter( 'get_the_excerpt', 'improved_trim_excerpt' );

If you would like, you can change the ‘[...]‘ string and/or the HTML <em> tags in this line to your liking:

$excerpt_more = apply_filters('excerpt_more', ' ' . '<em><a href="' . $permalink . '">[...]</a></em>');

That’s all for now. Let us know what you think, if you have any problems with our revisions, or if you have any improvements of your own by leaving a comment. Thanks for reading, and thanks especially to Aaron for his original solution!

19 Responses to “Fixing The Excerpt In WordPress”

  1. Thanks so much Duncan. I read through all of the comments on Aaron’s post and finally came to your comment and I am so glad that I waited to implement the solution until reading your post. This has saved me a lot of headaches. Thanks for taking time to address these two issues.

  2. tribsel

    hi, thanks for this. unfortunatelly white screen occurs on my installation when I add your function into my function.php (wp 2.9)

    and following error is in my server error log :

    PHP Fatal error: Call to undefined function remove_filter()

    • Not sure what to tell you tribsel, I’ve got the function added to the theme here, and all is well. Check your edits to make sure everything is correct. If everything is OK, remove the function to make sure that the problem lies with this particular function.

      If you still have trouble, then perhaps there is a conflict with another plugin. If you need any more help with this, get in touch with me through the contact form.

      I have never ran into any issues like this in my testing, so it may be limited to your configuration. If anyone else runs into this problem, please let me know, so that we can chase down the cause.

  3. Robert

    Okay, this is probably kind of a noob question but anyway. I don’t have a functions.php file yet and if I add one, the code of your solution just shows up at the top of my page. I started with creating an functions.php file in notepad, copied your code into it and uploaded it to my template folder (where the index.php and the stylesheet reside aswell.) What am I missing? Thanks in advance for helping me out.

    • Hi Robert,

      Did you make sure to add <?php as the very first line in the file, and ?> as the very last line?

      From the PHP Manual:
      When PHP parses a file, it looks for opening and closing tags, which tell PHP to start and stop interpreting the code between them.

      Here’s an example:

      <?php
          echo 'This is a test';
      ?>
      

      Does that help any?

  4. Robert

    I thought I did, but trying it again made clear I didn’t, or at least not properly. Thanks a lot! It works like a charm.

    p.s. Putting an excerpt from the php manual in really wasn’t necessary, you don’t have to rub it in :-)

  5. Duncan, wanted to let you know there’s a plugin called Advanced Excerpt http://wordpress.org/extend/plugins/advanced-excerpt/ which does pretty much everything your functions.php approach does, including balancing tags, custom ending and # of words and selective tag stripping.

    I’ve been using it for a bit and it does exactly what is needed in an efficient manner.

    • Good to know. Thanks, Artem, for the heads up.

      I personally prefer to rely more on functions.php than an externally written plugins, but that’s just my personal preference. I’m glad there is an alternative for those who feel differently.

  6. Thank you for this. :) It was really helpful.

  7. Hi there

    I’ve added this to my theme function.php file and it’s not working. It’s still stripping out formatting. I’ve got a post that contains a link and this does not display as a link within the excerpt on the blog homepage, but with in the astual post it does display as a link.

    What am I doing wrong?

    Thanks

    • I can’t be sure without seeing the function as installed in your functions.php file. Make sure that you have added <a> to the exemptions line, like this:

      ....
      $text = strip_tags( $text, '<a><b><em><i><strong>' ); // allowed tags (change as needed)
      ....
      

      If you have already added that tag, and it’s still not working, let me know, and drop a link to the page with the excerpt in your response, so I can check out the outputted code, and then we’ll go from there. :)

  8. This is very informative? How long have you been making this kind of articles? It looks like you have been doing this for decades. You are exceptional. 

  9. a34r

    Hi Duncan MacLeod, I am new to php.

    could you please tell me how I would call this function in my index.php?

    I’ve tried the followings and didn’t work:
    improved_trim_excerpt('');

    the_excerpt();

    • You shouldn’t need to do anything differently than you would normally do when calling the_excerpt(). Just copy and paste the function described above into your theme’s functions.php file, then call the_excerpt(); where you want the excerpt to be shown (in your index.php or wherever).

      Just remember that the the_excerpt(); template tag needs to be used within The Loop. It also needs to be wrapped in php tags, like this:

      <?php the_excerpt(); ?>

      Hope that helps.

      • a34r

        Thank you for the prompt reply….all sorted now.

        I didn’t realises I already had the following in my functions.php at very top of the page. (provided by theme author)

        remove_filter( ‘get_the_excerpt’, ‘wp_trim_excerpt’ );
        add_filter( ‘get_the_excerpt’, ‘custom_excerpt’ );

        Now I removed the “custom_excerpt” and using your…..works like a dream.

        cheers

      • Great! Glad you got it sorted out.

  10. Erik

    I would like the manual excerpt to display something like <a href="permalink" rel="nofollow">link</a> Is it possible so that when I write in custom excerpt (under the create post in admin) so that something like "%link %something%" becomes "<a href="http://www.domain.com/2010/03/name-of-a-post" rel="nofollow"></a>"? I’m thinking with help of an function in functions.php?

    • Sorry, Erik, this function doesn’t touch the manual Excerpt creation (the field under the post edit box) in any way, it only modifies the way the standard automatic Excerpt is created.

      However, if I understand your question correctly, you can try something like the following to give you a “Read More…” type link at the end of a manually created Excerpt. Just add this where appropriate in place of the the_excerpt() tags in your template files:

      <?php the_excerpt(); ?>
      	<?php if ( has_excerpt() ) { ?>
      		<p><a href="<?php the_permalink() ?>" rel="nofollow" title="Continue Reading <?php the_title_attribute(); ?>...">Read the rest of <?php the_title(); ?> &raquo;</a></p>
      	<?php } ?>
      

      Try that, and let me know if that was what you are looking for. Good luck!

Leave a Reply




Spill your guts:

XHTML tags allowed in comments:
<a href="" title=""> <strong> <b> <em> <i> <code> <pre> <del> <abbr title=""> <acronym title=""> <cite> <q cite="">

image