kylewm/brevity
Brevity is a URL shortener for Laravel: create short links, redirect visitors, and track hits. It offers a simple, self-hosted alternative to third-party services, with configurable length and custom slugs.
kylewm/brevity is not the link shortener the package description claims — it is a small, dependency-free text truncation utility (a port of the Known/Clearbit "brevity" algorithm). It trims a block of plain text to a target length while trying to avoid chopping words, URLs, @mentions, or #hashtags mid-token. There is no service provider, facade, config file, or Artisan command. Treat it as a leaf library you call from your own code, not a framework component.
Minimal steps:
composer require kylewm/brevity
src/ before writing code against it. The repo is unmaintained and thinly documented; confirm the exact namespace and the shorten() signature (typically shorten(string $text, int $limit): string) rather than trusting the README.php artisan tinker
>>> \Kylewm\Brevity\Brevity::shorten('A long post with a link https://example.com/a/very/long/path and trailing words', 100);
Try it with a URL, an emoji, and CJK text before you commit to the dependency.Post accessor. That gets you value with near-zero blast radius.If the spike above shows bad behaviour on your real content, stop and vendor the file (see Gotchas) — the algorithm is ~40 lines and CC0-1.0 means you can copy it into app/Support/ with no attribution obligation.
Wrap it, don't sprinkle it. Because there is no Laravel integration, bind a thin application-owned service in a provider so you can swap the implementation without touching product code:
// app/Support/Text/PostTruncator.php
namespace App\Support\Text;
class PostTruncator
{
public function shorten(string $text, int $limit = 280): string
{
// Brevity assumes plain text — normalise first
$text = trim(strip_tags($text));
return \Kylewm\Brevity\Brevity::shorten($text, $limit);
}
}
Inject this into controllers, jobs, and Blade components. Never call the vendor class from models, jobs, or templates directly — that is the one integration decision that determines how cheap replacement will be later.
Model accessor for previews. Expose a tweet-length preview without mutating stored content:
protected function tweetPreview(): Attribute
{
return Attribute::get(fn () => app(PostTruncator::class)
->shorten($this->body, 280));
}
Shorten once, at the point of dispatch. In a cross-post job, compute the truncated string immediately before you hand it to the outbound payload and persist it there. If the Blade preview and the job each recompute independently, the user can see one string and the platform can receive another.
Chained limits are fine. Rendering both a 160-char card description and a 280-char tweet? Shorten at the longer limit once and again at the shorter one. The algorithm is cheap, and double-truncation of already-truncated text generally behaves — just watch for the double-ellipsis case noted below.
Notifications and SMS. The URL-preservation behaviour matters most here: a Notification body capped at ~140 chars with a chopped https://… link is worse than no link. Shorten the body, then append the link separately if you can.
Blade layout component. The OG tag is the canonical home:
<meta property="og:description"
content="{{ app(\App\Support\Text\PostTruncator::class)->shorten($post->excerpt ?? $post->body, 160) }}">
Sequencing when migrating existing truncation. If you currently use substr or Str::limit, introduce the wrapper behind a feature flag and diff outputs on production-shaped content (URLs, emoji, CJK, HTML) before rolling it into any persistence or publishing path.
composer require for a "short, shareable links" library will get you a truncation helper. Read the source on day one; don't build a redirect table around it.mbstring is installed — the package relies on mb_* functions and will misbehave on byte-oriented fallbacks.strip_tags() or a renderer's text output first. Passing HTML counts tag characters and can chop inside a tag, producing mangled output downstream.Str::limit($result, $limit, '') after it as a belt-and-braces check — there is no guarantee it never exceeds the limit by a character on edge cases.mb_strlen($text) before and after, plus mb_strlen($output). The recurring bugs are whitespace-only or very short inputs round-tripping oddly, and a double ellipsis when you shorten already-shortened text.composer update will not bring fixes. Run your suite on your target PHP version and accept ownership.app/Support/ with a credit comment is often safer than a Packagist dependency you must keep patching around, and it removes the "unmaintained transitive dep" conversation from future security reviews.How can I help you explore Laravel packages today?