The problem:
Whilst working on an aggregation site recently I needed to find a way to truncate the length of aggregated posts so that they only showed the first 200 or so characters of the post. However, I also wanted the split point in the post to occur at the end of a whole word, as opposed to part way through a word, and add some visual indication that there was more still to read.
The solution:
I'll first show the entire solution and then walk through how it works afterwards.
In your theme's node.tpl.php file the node content will most usually be output using code similar to:
<div class="content">
<?php print $content ?>
</div>Find this code and replace it with the following code (minus the opening and closing php tags which are just used here to improve the formatting):
<?php
<div class="content">
<?php
$mywords = explode(" ", $content);
$finalstring = "";
foreach($mywords as $word) {
if(strlen($finalstring) <= 197) {
$finalstring = $finalstring . " " . $word;
} else {
$finalstring = $finalstring . " <strong>[...]</strong>";
break;
}
}
echo $finalstring;
?>
</div>
?>The explanation:
OK, so how does it work?
1. Opening div tag.
<div class="content">2. Opening php tag.
<?php3. Set up a varible ($mywords) which will hold an array containing all of our node's content ($content) which has been split (explode) at each space (" ") in the original content ($content).
$mywords = explode(" ", $content);4. Set up a second variable ($finalstring) which currently contains nothing ("").
$finalstring = "";5. Loop through our array of content, which is being held in $mywords, one item at a time, and do some stuff.
foreach($mywords as $word) {6. Firstly, check to see if the current $finalstring variable is less than or equal to 197 characters.
if(strlen($finalstring) <= 197) {7. If it is, then append both a space (" ") and the next word in the array ($word).
$finalstring = $finalstring . " " . $word;8. If it isn't
} else {9. then append some html (" [...]")
$finalstring = $finalstring . " <strong>[...]</strong>";10. and stop the loop.
break;
}11. End the foreach loop.
}12. Echo out the final contents of $finalstring.
echo $finalstring;13. Closing php tag.
?>14. Closing div tag.
</div>Your node's content will now be truncated if it is longer than 197 characters, and the break will occur at the end of a word. If it does truncate, a handy bit of html [...] will be added to ensure that users realise there is more to the post.
You can achieve this using the truncate_utf8 function, calling it like that:
truncate_utf8($content, 200, TRUE, TRUE);The third argument is a flag whether to truncate at last space within the upper limit and the fourth a flag whether to add trailing dots. The dots won't be wrapped in strong tags though, but this could then be done by using preg_replace;
$content = preg_replace ("/\.{3}$/", '<strong>[...]</strong>', $content);It makes much more sense not to use preg_replace but to do it like that:
$content = truncate_utf8($content, 200, TRUE, FALSE);
$content .= ' [...]';
How about this:
<?php$mywords = split(" ", $content);
$mywords = join(" ", array_splice($mywords, 0, 197));
$finalstring = $mywords . "<strong>...</strong>";
print $finalstring;
?>
Sorry, I miss read the spec... truncate_utf8 is the best option for 197 words...
This is what I was aiming at anyway...!
$mywords = str_split($content);
$mywords = array_splice($mywords, 0, 197);
while($char != " ") {
$char = array_pop($mywords);
}
$finalstring = join("", $mywords);
print $finalstring . "...";
It saves looping though the string loads, at least...!
there are other places where this truncate functionality would be helpful, please contribute your solutions to the drupal project.
this is one issue for example
http://drupal.org/node/269911
Messy for loops ...
function truncate_string ($string, $maxlength, $extension) {// Set the replacement for the "string break" in the wordwrap function
$cutmarker = "**cut_here**";
if (strlen($string) > $maxlength) {
// Using wordwrap() to set the cutmarker
// NOTE: wordwrap (PHP 4 >= 4.0.2, PHP 5)
$string = wordwrap($string, $maxlength, $cutmarker);
// Exploding the string at the cutmarker, set by wordwrap()
$string = explode($cutmarker, $string);
// Add $extension to the first value of the array $string at our marker.
$string = $string[0] . $extension;
}
return $string;
}
Have y'all seen the node_teaser function?
http://api.drupal.org/api/function/node_teaser
Thanks for all the suggestions :)
Also, I've updated the code filter module which has hopefully fixed the code posting problem - sorry about that.
Thank you, you have saved me some work - I was just about to look into how to do this myself.
I use node teaser to help with this.
I used to come here all the time and read, but lately I don't anymore. You're site takes way to long to load, and you never update anymore. I really think you should update more and remove all the glitz-and-glamour. Content is King : )
@Chad - sorry to hear that you feel that way. The site loading time is something that people commented on in the initial redesign launch post, and I did try to address the issue by doing a couple of things (including cutting down the background image size). I am also currently looking at moving the site across to a new (faster) server which should help things.
As for updating, I agree that I could update more frequently but I've always aimed to release high quality posts which provide real value, and the fact is that for me these simply take longer to write than general opinion or haircut posts. However, I would still rather publish these kinds of posts, albeit less frequently, as opposed to just blogging general thoughts more frequently for the sake of it.
great articel! @all thanks for the infos! really helpfull.
Fantastic article, great function, and brilliant explanations! I'm looking for exactly this optinion without inserting the tags into my posts, or amending any posts already posted. I'll put it on my aggregator site www.bradcast-news.co.uk.
Thank you so much for sharing!
Good post. I am wondering if HTML will have to be stripped here? What if, for instance you truncate in the middle of an HTML tag: </div or don't close a tag... you would devalidate an XHTML layout, let alone wreck a page design.
I could definitely see a useful drupal module that creates auto-teasers at an exact character count and I could also see use for an addon to Views that truncates... Views Truncate.
It's great you shared this resource, thank you! Apparently using Drupal comes with different solutions that met the standards of the most demanding webmasters. This is the kind of web content management solutions that placed Drupal on top rankings.