[wp-hackers] Post excerpts within the_content filter callback functions

John Blackbourn johnbillion+wp at gmail.com
Wed Jun 16 02:55:57 UTC 2010


In short: How can a plugin fetch the post excerpt from within a
'the_content' filter callback function?

In long:

This is technically a bug, but I'm not sure it can be fixed easily, so
recommendations for how it can be worked around would be appreciated.

A plugin of mine adds a filter to 'the_content'. In the callback
function for this filter, I'd like to get the post excerpt. We could
just use the $post->post_excerpt property, but this will only give us
an excerpt if one has been explicitly set; it won't give us a
generated excerpt. So we use get_the_excerpt() like we should. Problem
is, the following code will not work:

function my_content_callback( $content ) {
	global $post;
	$excerpt = get_the_excerpt( $post->ID );
	// do something with $excerpt
	return $content;
}
add_filter( 'the_content', 'my_content_callback' );

The reason this doesn't work is because this will cause an infinite
loop in PHP if the post's post_excerpt field is empty. Why? When
get_the_excerpt() is called, if the post's post_excerpt field is empty
then wp_trim_excerpt() will generate an excerpt using the post
content, and this post content has the_content filter applied to it,
giving us our infinite loop.

Not to worry, we can get around this by removing our content filter
before fetching the excerpt, then re-applying the filter after we get
it:

function my_content_callback( $content ) {
	global $post;
	remove_filter( 'the_content', 'my_content_callback' );
	$excerpt = get_the_excerpt( $post->ID );
	add_filter( 'the_content', 'my_content_callback' );
	// do something with $excerpt
	return $content;
}
add_filter( 'the_content', 'my_content_callback' );

This is far from ideal, but it works.

So we've got around this problem, but we now introduce another
problem. Somehow, somewhere, our shortcodes have all broken. Our
shortcodes are simply not parsed and the body of our post just
displays the raw shortcodes (eg [myshortcode]).

Why is this happening? The do_shortcode() function (which is a filter
applied to the_content in order to parse all our shortcodes) uses
preg_replace_callback(). Because we're calling get_the_excerpt() from
within a function which is itself a callback function for the
'the_content' filter, it means we have nested use of
preg_replace_callback(), and that doesn't work (it's a PHP bug:
http://bugs.php.net/bug.php?id=16040). This is (I *think*) why our
shortcodes are not being parsed in this situation.

So to recap: get_the_excerpt() uses wp_trim_excerpt() which applies
'the_content' filter. Calling get_the_excerpt() from within a
'the_content' filter callback function causes nested use of
do_shortcode() which in turn causes nested use of
preg_replace_callback() which causes a PHP bug, and this breaks
shortcodes.

How then do we get the post excerpt from within a 'the_content' filter
callback function without breaking shortcodes?

A plugin could use its own version of the get_the_excerpt() function
which doesn't apply the 'the_content' filter - is this the only way?

Caveat: preg_replace_callback() might not be to blame, but if it's not
then I don't know what is.

John


More information about the wp-hackers mailing list