Installation:
composer require judev/php-htmltruncator
Ensure dom, intl, and mbstring PHP extensions are enabled (check php -m).
First Use Case: Truncate a blog post excerpt in a Laravel controller:
use HtmlTruncator\Truncator;
$postContent = '<p>This is a <strong>sample</strong> post with HTML.</p>';
$truncated = Truncator::truncate($postContent, 5); // Keep 5 words
// Output: "<p>This is a <strong>sample</strong> post…</p>"
Blade Integration:
Add a helper in app/Helpers/html.php:
if (!function_exists('truncate_html')) {
function truncate_html($html, $words, $ellipsis = '…') {
return \HtmlTruncator\Truncator::truncate($html, $words, $ellipsis);
}
}
Use in Blade:
{!! truncate_html($post->content, 10) !!}
Word-Based Truncation (Default):
// Truncate to 3 words, default ellipsis
Truncator::truncate("<p>Hello world, this is a test.</p>", 3);
// => "<p>Hello world, this…</p>"
Character-Based Truncation:
Truncator::truncate($html, 20, ['length_in_chars' => true]);
Custom Ellipsis:
// Text ellipsis
Truncator::truncate($html, 5, " (read more)");
// HTML ellipsis (e.g., a link)
Truncator::truncator($html, 5, '<a href="/read-more">…</a>');
Extending Ellipsable Tags:
Truncator::$ellipsable_tags[] = "blockquote";
Truncator::truncate("<blockquote>Content here.</blockquote>", 2);
Dynamic Previews (API/Blade):
// API Response
return response()->json([
'excerpt' => Truncator::truncate($article->body, 8),
]);
// Blade (with caching)
@php
$truncated = cache()->remember("truncated_{$post->id}", now()->addHours(1), function () use ($post) {
return truncate_html($post->content, 10);
});
@endphp
{!! $truncated !!}
Search Results:
// In a Scout search result formatter
public function toArray($model)
{
return [
'title' => $model->title,
'excerpt' => Truncator::truncate($model->content, 5),
];
}
Database Storage:
// Observer for posts
public function saved(Post $post)
{
$post->update([
'truncated_excerpt' => Truncator::truncate($post->content, 15),
]);
}
Laravel Service Provider: Bind the truncator for DI:
$this->app->singleton('truncator', function () {
return new class {
public function __invoke($html, $words, $ellipsis = null) {
return Truncator::truncate($html, $words, $ellipsis);
}
};
});
Usage:
$this->app->make('truncator')($post->content, 7);
Form Request Validation:
public function rules()
{
return [
'content' => 'required|string|max:10000', // Ensure HTML isn't too large
];
}
Testing:
public function test_truncate_html()
{
$html = '<p>Test <strong>HTML</strong> truncation.</p>';
$truncated = Truncator::truncate($html, 2);
$this->assertStringContainsString('Test', $truncated);
$this->assertStringContainsString('…', $truncated);
}
DOM Parsing Overhead:
Malformed HTML5:
<div><p>) without html5-php.masterminds/html5 and use:
$dom = new \Masterminds\HTML5();
$dom->loadHTML($html);
Unicode/Emoji Handling:
mbstring required for accurate word counting in non-Latin scripts.mbstring.func_overload = 0 in php.ini.Nested Tags:
<table>).Truncator::$ellipsable_tags or pre-process HTML to wrap content in allowed tags.PHP 8.x Compatibility:
public static function truncate(string $html, int $words, ?string $ellipsis = null): string
Log Input/Output:
$html = '<p>Debug <em>this</em> HTML.</p>';
$truncated = Truncator::truncate($html, 2);
\Log::debug("Input: $html");
\Log::debug("Output: $truncated");
Fallback for Failures:
try {
return Truncator::truncate($html, $words);
} catch (\Exception $e) {
\Log::error("Truncation failed: " . $e->getMessage());
return Str::limit(strip_tags($html), $words * 5) . '…';
}
Validate HTML First:
use Symfony\Component\DomCrawler\Crawler;
if (!Crawler::createFromHtml($html)->count()) {
throw new \InvalidArgumentException("Invalid HTML provided");
}
Ellipsable Tags:
['p', 'ol', 'ul', 'li', 'div', 'header', 'article', 'nav', 'section', 'footer', 'aside', 'dd', 'dt', 'dl'].blockquote or figure if needed:
Truncator::$ellipsable_tags = array_merge(Truncator::$ellipsable_tags, ['blockquote']);
Character vs. Word Length:
length_in_chars option for fixed-length truncation (e.g., Twitter-style):
Truncator::truncate($html, 140, ['length_in_chars' => true]);
HTML5 Parsing:
html5-php for non-standard HTML5. Install via:
composer require masterminds/html5
$dom = new \Masterminds\HTML5();
$dom->loadHTML($html);
$truncated = Truncator::truncate($dom->saveHTML(), $words);
Custom Truncator Class: Extend the core class for Laravel-specific logic:
class LaravelTruncator extends \HtmlTruncator\Truncator {
public static function truncateWithCache($html, $words, $cacheKey) {
return cache()->remember($cacheKey, now()->addHours(1), function () use ($html, $words) {
return parent::truncate($html, $words);
});
}
}
Blade Component:
Create a reusable component (resources/views/components/truncate.blade.php):
@props(['html', 'words', 'ellipsis' => '…'])
{!! \HtmlTruncator\Truncator::truncate($html, $words, $ellipsis) !!}
Usage:
@truncate(html: $post->content, words: 8)
Eloquent Accessor: Add to
How can I help you explore Laravel packages today?