By default, WordPress strips out all the HTML tags from your post excerpts. I needed to allow hyperlinks, but there is a problem when WordPress tries to truncate the post’s content. The wp_trim_excerpt function is what WordPress uses to do all the trimming work, I simply copied the code, modified it, and stuck my new version in the mu-plugins directory (or you could add it to your functions.php).
The first line I needed to change was the PHP function call strip_tags(). I need to set it to allow the <a> tag… very simple to do:
Original Line:
1 |
$text = strip_tags($text); |
New Line:
1 |
$text = strip_tags($text, '<a>'); |
The second line I needed to change was where WordPress splits the excerpt up into separate words. This was a bit tricky because you run into an issue where you could be cutting of the </a>, which could screw up your entire page. I decided the best thing to do would be to treat the entire hyperlink as a single word. So, <a href=”http://lewayotte.com/”>My Website</a>, would count as a single word. By default, WordPress creates a 55 word excerpt. That is pretty easy to change as well.
Original Line:
1 |
$words = preg_split('/[\n\r\t ]', $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY ); |
New Line:
1 |
$words = preg_split('/(<a.*?a>)|\n|\r|\t|\s/', $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE ); |
Next, you simple need to remove the current wp_trim_excerpt filter and add a new one that points to your new function. Here is what the entire block of code looks like for me:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<?php function new_wp_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, '<a>'); $excerpt_length = apply_filters('excerpt_length', 55); $excerpt_more = apply_filters('excerpt_more', ' ' . '[...]'); $words = preg_split('/(<a.*?a>)|\n|\r|\t|\s/', $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE ); if ( count($words) > $excerpt_length ) { array_pop($words); $text = implode(' ', $words); $text = $text . $excerpt_more; } else { $text = implode(' ', $words); } } return apply_filters('new_wp_trim_excerpt', $text, $raw_excerpt); } remove_filter('get_the_excerpt', 'wp_trim_excerpt'); add_filter('get_the_excerpt', 'new_wp_trim_excerpt'); |
Regular Expression Explained
I changed /[\n\r\t\s ]/ to /(<a.*?a>)|\n|\r|\t|\s/ because I needed to capture everything in the <a> HTML tags and count it as a single word. \n, \r, \t, \s are all pretty basic regex characters that preg_split() is using to break up the content. (<a.*?a>) is what captures everything in the <a> tag. The .* means all “characters” adding the ? to .* makes it “non-greedy.” This for the case where there are multiple hyperlinks in the content. It prevents the regex from thinking <a href=”link1″>link 1</a>, <a href=”link2″>link 2</a> is a single word. The parenthesis simply group the <a.*?a> together, so it doesn’t try to split those items separately and then I needed to add PREG_SPLIT_DELIM_CAPTURE to preg_split, or preg_split would have just removed the link as garbage.
You should be able to use this as a pretty solid base for adding other HTML tags.
Great trick, thanks!
Hi, Thanks for this trick and i need to allow ,,<b> also. can you help me.
Thanks
Vaisakh,
Check out the strip_tags() documentation – http://us3.php.net/strip_tags The first example should get you to where you need to be :)
Lew
Hi Lew,
Thanks for your reply. but i need for this <ol>,<ul>,<b>.
Thanks
vaisakh
Vaisakh,
If you stick those tags into the allowable tags variable of the function it should work (see the aforementioned documentation).
Lew
Worked absolutely perfectly, I’ve tried so many different things to get this to work from other tutorials but none of them really explained why it wouldn’t display the links.
I crashed my functions page to begin with by putting the <?php tag at the beginning but after removing that everything worked perfectly. I'm not very big on php so a bit unsure why it would crash it.
Hi Gareth,
Yeah, if you already had an open <?php tag, it would have crashed.
Glad you found this post useful.
Lew
Hi lew,
I added this to my functions.php it worked for teh links in the excerpts but it seems to have disabled the read more links and replaced them with […] but not hyperlinked them.
Any ideas why this might happen?
Aaron,
The “[…]” is the standard WordPress excerpt text. You can change it to be hyperlinked by following these directions: http://codex.wordpress.org/Function_Reference/the_excerpt#Make_the_.22read_more.22_link_to_the_post
Lew
Great tip, thanks, you save me from installing another plugin.
No problem, glad to help.
This is great but a bit above my understanding…do i simply copy your last set of code into my functions.php file?
Yes, Joel.
Make sure you get in in before any ending ?>
Lew
You just made my day!
Thanks, this helped me alot, I was wondering why my links weren’t showing in my excerpts.
Thanks so much. This worked like a charm and saved me hours of research and trial and error.
Glad to help :)
Very useful and easy approach – Thank you!
Thank you so much for this tutorial. I have been looking for a solution for a while. It works great – but I am also using excerpts in my sidebar to show the latest posts and those stop at the point where the first link appears. So if the second word contains a link, the excerpt in the sidebar only shows the first word.
Do you have any idea how to allow links in the sidebar (or how to just show the full excerpts without links) ?
Hi Dennis, How are you displaying excerpts in your sidebar?
Hi Lew,
Thank you very much for your quick reply. To be honest, I have no idea how it works. I bought the Blogga theme and the theme comes with customized widgets.
Here’s the demo: http://themeforest.net/item/blogga-team-blogging-for-wordpress/full_screen_preview/2700562
The excerpts are below the tags in the right sidebar. Maybe I should ask them how to continue or I delete the excerpts in the sidebar. Having links in the post excerpts is worth more in my opinion.
Dennis
Dennis, If you want to send me a private email through my contact form with temporary admin credentials to your site, I can try to take a look for you to give you a better idea of what you need to do.
How to add multiple html tags, in this code we can able to add only <a>, suppose i need to add along with that.. how to do. Please suggest me.
How to add multiple html tags, in this code we can able to add only <a> tag, suppose i need to add along with that tag.. how to do. Please suggest me.
Vinoth, check out the PHP documentation for strip_tags (http://php.net/strip_tags). You’ll see that you can simply add new tags like $text = strip_tags($text, ‘<a><p>’);
Thanks, working very fine!
Perfect. Thank you for this!
I use this and it works very well. However, there is one bug that I don’t think anyone has commented on. Since this script counts the hyperlinks as a word and the script then adds a space after every word – when you have any punctuation mark immediately following a link (that’s not included in the hyperlink) it adds a space between the end of the last hyperlinked word and the punctuation mark. Like this This is an example .
My fix for this was to do a replace on the string for the punctuation marks and spaces after the implodes. There is probably a more elegant/better way to do this.
$text = str_replace(array(‘ ,’,’ .’,’ ?’,’ !’,’ )’,’ ;’), array(‘,’,’.’,’?’,’!’,’)’,’;’), $text);
Whoops, that code paste didn’t work. Let’s try again.
$text = str_replace(array(' ,',' .',' ?',' !',' )',' ;'), array(',','.','?','!',')',';'), $text);
Didn’t work either. I give up, Lew please help. :)
Justin I think I just figured this out. Where you put the (<a>) in the preg_split function, if you add that sequence followed by the punctuation you’ll think you might use, it works. You have to put the punctuation inside the last ) after the a>, sort of like this: (<a>,) and (<a>.) but separate them with the | symbol. my line of lew’s code looks like this:
$words = preg_split('/(<a>)|(<a>,)|(<a>.)|\n|\r|\t|\s/', $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE );
and is working so far :)
instead of ( <a> ), or rather, in addition to it, use ( <a> , ) and ( <a> . ) or ( <a> ! ) and remember to follow each with a | like the other things in that line
here is my last try to answer justin’s question: http://i.imgur.com/vgn1Yk3.png
How about a file url for a audio player?
There is a bug in the provided script. It does not close <a> tags. For example if <a> tag contains more words, it may remain unclosed if it is placed nearby ending of an excerpt. It will break the code…
Have you tested this? If I’m correct, the (<a.*/a>) should be treated as one word w/ the PREG_SPLIT_DELIM_CAPTURE flag set with preg_split.
Hi, I am wondering if I could add an image in the excerpt. I thinking an auto play button for a podcast in the associated post
I don’t see why not.
Great stuff Lew! I’m having one bit of trouble… is it just me, or does this add a space at the very end of an excerpt before the period if it’s shorter than the 55 limit? I have a link at the end of my sentence, so perhaps that’s the issue? I’m fighting it and perhaps just frustrating myself more than actually solving what’s probably a really easy issue. Thanks for your help!
Hey Justin, I don’t think there is anything in the code above that would add a space. Were you able to figure out the problem?
I did, thanks Lew – there was a sort of solution that I pieced together above in the comments that I completely missed the first time around. All the best!