Conditional Excerpt Function
I use this function on practically every site that has any posts/archives section. This enables us to display a standardized excerpt inside or outside the Loop.
Arguments (all optional):
$ex_length the word count
$postref the post or text to excerpt. Can be an ID, a post object, a block of text, or if called within the Loop, null or not given
$addmore_keyThe text/html to display when there is additional content. I like to set this to something unique (like the default ‘<!–wpcx_more–>’) and str_replace within the caller instance.
$include_p Whether to include paragraphs within the excerpt
$user_break If false, return no more than the maximum word count; if true, use the entire user-defined excerpt or user-defined ‘<!–more–>’ break
$apply_shortcodes True to apply shortcode formatting within the excerpt
Note: this function always retains b, strong, i and em tags.
View comments within code for detailed explanations.
function conditional_excerpt( $ex_length=80, $postref=null, $addmore_key='<!--wpcx_more-->', $include_p=false, $user_break=false, $apply_shortcodes=false ) { // retrieve or build post object from $postref input (can be // post object, ID, text, or current loop post if not defined/null) // check if whole $post object was passed if ( is_object( $postref ) ) : $postob = $postref; // check if it's a post ID ( integer or string-format number ) : elseif ( is_numeric( $postref ) ) : $postob = get_post( $postref ); // otherwise assume it's text, define a minimal object with just the properties we need: elseif ( is_string( $postref ) && !empty( $postref ) ) : $postob = ( object )array( 'ID' => 0, 'post_content' => $postref ); // finally, if empty / null / not defined, assume we're in The Loop: elseif ( empty( $postref ) ) : $postob = get_post( get_the_ID() ); endif; // bail if none of the above tests passed: if ( !is_object( $postob ) ) return; // now, check if there is a user-defined excerpt, and act upon it if ( $postob->ID && ! empty( $postob->post_excerpt ) ) : $featex = $postob->post_excerpt; $addmore = $addmore_key; if ( $user_break ) : return $featex.$addmore; endif; // no user-defined excerpt, so construct it else : $addmore = ''; // strip out any javascript $stripped = preg_replace( '@<script[^>]*?>.*?</script>@si', '', $postob->post_content ); // strip out shortcodes if dictated by $apply_shortcodes: if ( !$apply_shortcodes ) { $stripped = strip_shortcodes( $stripped ); } // if '<!--more-->' is not there ( user did not specify a break ), // $content_split array will only contain one item. $content_split = explode( '<!--more-->', $stripped ); $featex = $content_split[0]; if ( count( $content_split ) > 1 ) : $addmore = $addmore_key; endif; // this is the recommended way to convert raw post_content; // shortcodes will be applied herein if not stripped out earlier: $featex = apply_filters( 'the_content', $featex ); $featex = str_replace( ']]>', ']]>', $featex ); // prepare argument for strip_tags() (standard PHP function) $exclude_open = '<b><i><em><strong><a>'; if ( $include_p ) : $exclude_open .= '<p><br><h1><h2><h3><h4>'; endif; $featex = strip_tags( $featex, $exclude_open ); // will append closing tags to excerpt so any that have been // truncated will be properly closed $exclude_close = '</b></i></em></strong></a>'; if ( $include_p ) : $exclude_close .= '</p></h1></h2></h3></h4>'; endif; endif; if ( !$user_break || count( $content_split ) < 2 ) : $words = explode( ' ', $featex, $ex_length + 1 ); if ( count( $words ) > $ex_length ) : array_pop( $words ); $featex = implode( ' ', $words ); $addmore = $addmore_key; endif; endif; return $featex . $exclude_close . $addmore; }
Coders note:
Lines 29 & 30: Why did I test ! empty( $postob->post_excerpt ), and then set $featex = $postob->post_excerpt;? Wouldn’t it be better to use the WordPress functions has_excerpt() and get_the_excerpt()?
No, for two reasons:
- This function can become part of a filter so all excerpts are structured this way (see below), hooked into get_the_excerpt — which is applied to the output of the get_the_excerpt() function. If I used get_the_excerpt() herein, I’d create an infinite recursion.
- Looking at the core code, has_excerpt() goes to the database for the post object, then simply returns the ->post_excerpt property if it exists. Similarly, get_the_excerpt() simply returns the ->post_excerpt property. Since I already have a post object, why increase overhead with another database call?
How to use it:
Make sure this function is in your functions.php file. Then, you can edit / create your theme files to call this function wherever you see the_excerpt() or get_the_excerpt() (likely archive.php, category.php, search.php and other ‘list’ templates).
Or, hook into the get_the_excerpt filter, which is encountered by both the_excerpt() and get_the_excerpt(), always within The Loop. Add this to your functions.php file.
add_filter( 'get_the_excerpt', 'wpcx_excerpt_filter' ); function wpcx_excerpt_filter( $excerpt ) { return conditional_excerpt( 50 ); // ... or your preferred word count }