alt-three/emoji
Alt Three Emoji is a Laravel package that integrates the Emoji One library, making it easy to convert emoji shortcodes to Unicode and render emoji as images. It includes a service provider and facade for quick setup, so you can add rich emoji support to user-generated content.
The package is a thin Laravel wrapper around the EmojiOne PHP client. It gives you a single injectable translator plus an Emoji facade that turns emoji into shortcodes, shortcodes into unicode, or emoji into <img> tags.
composer require alt-three/emoji
On Laravel 5.5+ the AltThree\Emoji\EmojiServiceProvider is auto-discovered. On 5.1–5.4 add it to config/app.php providers and register the AltThree\Emoji\Facades\Emoji alias. The illuminate/support constraint is pinned to the Laravel 5 era, so on Laravel 6+ expect to either fork the constraint or skip the package entirely — this is the first thing to verify before committing to it.
Where to look first:
vendor/alt-three/emoji/src/ — the service provider shows exactly what is bound into the container (a singleton translator); the facade just resolves that binding.vendor/emojione/emojione/lib/php/ — the underlying client. Most of the behaviour you will actually care about (image URLs, sprite mode, ASCII conversion) lives here, not in the Laravel package.First use case: user-submitted content. Accept raw emoji in a comment box, store it as shortcode with Emoji::toShort($text), and render it back with Emoji::toUnicode() in plain-text surfaces or Emoji::toImage() in HTML surfaces. That input-store-render split is the pattern the package is designed around.
use AltThree\Emoji\Facades\Emoji;
Emoji::toShort('Hello 😀'); // "Hello :grinning:"
Emoji::toUnicode('Hello :grinning:'); // "Hello 😀"
Emoji::toImage('Hello 😀'); // "Hello <img class="emojione" ...>"
Pick one canonical storage form and stick to it. Store shortcodes (:smile:) in the database, not raw unicode. Shortcodes survive utf8 (3-byte) columns, are greppable in SQL, and are stable across emoji-set upgrades. Convert on input with toShort(), convert on output. Storing unicode means you need utf8mb4 on every column, connection, and index that might touch the field — a migration you do not want to run twice.
Render at the edge, not at write time. Keep the model accessor pattern:
public function getBodyHtmlAttribute()
{
return Emoji::toImage(e($this->body));
}
Note the e() before toImage(). The EmojiOne client only rewrites emoji tokens — it does not escape surrounding HTML. Passing raw user input through {!! !!} after toImage() is a straight XSS hole.
Match the output format to the channel. HTML views get toImage(); emails, SMS, push notifications, JSON APIs, and log lines get toUnicode(). Image tags in a plain-text mail are noise, and unicode in an HTML mail renders inconsistently across clients.
Order matters in a markdown/HTML pipeline. If you run CommonMark or Parsedown, do emoji conversion after markdown rendering and before any HTML purifier — or configure the purifier to allow the <img> tags and classes EmojiOne emits. Run it before markdown and your :shortcode: syntax can collide with markdown emphasis; run it after purifying and every emoji gets stripped.
A Blade directive keeps views clean:
Blade::directive('emoji', fn ($expr) => "<?php echo \\AltThree\\Emoji\\Facades\\Emoji::toImage(e($expr)); ?>");
For search and indexing, run toShort() and then strip /:([a-z0-9_+-]+):/ so emoji do not pollute full-text matches, or keep the shortcodes and let users search :fire: — that is often a nicer feature than you'd expect.
Resolve from the container, not the facade, in jobs and services. The translator is a singleton; injecting it makes tests trivial and avoids the facade root being unset in unusual bootstrap paths.
emojione/emojione is abandoned, and EmojiOne itself relicensed into JoyPixels (with a different licence and no maintained PHP client under the old name). Pin both packages to exact versions in composer.json, commit the lockfile, and treat any emoji-set refresh as a fork-and-patch task rather than a composer update.toImage() points at a CDN by default. In air-gapped, intranet, or offline-CI environments you get broken images. Publish/copy the EmojiOne assets locally and point the client at them, or use sprite mode if you're rendering long feeds and care about request count.toUnicode(toShort($x)) === $x.mbstring is mandatory. These conversions walk multibyte strings. Missing extension or an mb_internal_encoding mismatch produces mangled output that looks like a data problem.Emoji alias, resolution order decides which one wins. Check config/app.php aliases if behaviour changes after adding a dependency.toImage() on a 5,000-comment thread is not free. Wrap it: hash the stored body, cache the rendered HTML, invalidate on save. The translator being a singleton does not memoize anything for you.php artisan config:cache in deploy. A stale cached config after flipping image mode is the classic "why are my emoji still PNGs" bug.fake(). Bind a mock AltThree\Emoji\EmojiTranslator into the container in your test case, or just assert against real conversions — they are deterministic and fast enough.How can I help you explore Laravel packages today?