Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Twig Extensions Laravel Package

nucleos/twig-extensions

Nucleos Twig Extensions adds a practical set of Twig filters, functions, and tests for everyday templating. It integrates smoothly with Twig-based PHP projects, helping you keep templates concise, readable, and maintainable without custom extension boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is a bag of Twig extensions (filters, functions, tests). Laravel ships Blade, not Twig, so the first decision is whether you actually run Twig anywhere. Two realistic entry points:

  1. You already use Twig in a Laravel app via rcrowe/twigbridge. Then this is a drop-in.
  2. You render templates outside Laravel's Blade pipeline — queue workers generating HTML emails, PDF invoices via a Twig-based renderer, a static/CLI build step. Here you can use it directly with plain Twig.

Install:

composer require nucleos/twig-extensions

Then read src/ before the README — each extension is a small class exposing getFilters(), getFunctions(), and/or getTests(). That's the fastest way to see the actual surface area and which ones pull in optional dependencies.

First use case: pick the extensions that replace code you've already written by hand — byte formatting (1.2 MB), humanized durations (2 hours ago), Markdown-to-HTML for stored content, number/ordinal formatting. Register just those two or three first; don't wire up the whole set.

With TwigBridge:

// config/twigbridge.php
'extensions' => [
    \Nucleos\Twig\Extension\BytesExtension::class,
    \Nucleos\Twig\Extension\DurationExtension::class,
    \Nucleos\Twig\Extension\MarkdownExtension::class,
],

Then in a template: {{ filesize|format_bytes }}.

Implementation Patterns

Register per-extension, not wholesale. The package is a collection, and several extensions only work if a suggested package is installed (Markdown parser, phone number lib, intl). Cherry-picking keeps unrelated features from breaking boot.

Wrap it in your own extension when you need defaults. If you always render durations in a specific format, or always set a locale, subclass or compose:

final class AppTwigExtension extends AbstractExtension
{
    public function getFilters(): array
    {
        return [
            new TwigFilter('ago', fn ($d) => $this->format($d)),
        ];
    }
}

This also gives you a single place to swap the library out later — important for a package with 5 stars and no dependents.

Bridge high-value filters to Blade if you're not going all-in on Twig. You don't need to run two template engines to benefit; expose the same output via a Blade directive or view composer:

Blade::directive('bytes', fn ($expr) => "<?php echo app('twig.bytes')->format($expr); ?>");

Use it in feature tests by rendering real templates. With TwigBridge, Twig::render('...') works inside PHPUnit/Pest. Assert on rendered output rather than on the extension classes — that catches locale and escaping surprises.

Compose with intl. Most formatting filters defer to PHP's Intl or NumberFormatter. Set app()->setLocale() early in the request (or \Locale::setDefault() in a service provider) so amounts, dates, and ordinals come out right without passing a locale on every call.

Non-HTTP contexts are the sweet spot. Report generation, invoice PDFs, and queued email HTML benefit most — the filters cut the "format this number/date/size" boilerplate that otherwise lives in view models.

Gotchas and Tips

  • Twig vs. Blade is the real cost. Adding TwigBridge to a Blade app means two template languages, two caches, two escaping models, and two sets of team conventions. Justify it with more than one nice filter. If it's a single format_bytes call, write ten lines of PHP instead.
  • Optional dependencies fail at runtime, not install time. An extension can register fine and then throw inside render() because the underlying library is missing. Check composer.json suggest and require-dev to see what each extension quietly assumes. Wrap risky filters or don't register them.
  • Escaping surprises. Any filter returning HTML (Markdown, HTML truncation) needs |raw in templates, and that's an XSS decision you should make consciously per call site. Prefer filtering the Markdown through an HTML sanitizer in the pipeline.
  • intl and locale drift. Formats differ between environments if intl is present in one and absent in another. Pin the extension in composer.json and assert on locale-sensitive output in tests, not on env-dependent behavior.
  • Debug what's actually registered. dump($twig->getFilters()) after boot, or Symfony's debug:twig. Don't assume a filter exists because the README lists it — the class may only register it conditionally.
  • Twig 3 has no getName(). If you extend any of these classes, don't copy old Symfony-style naming boilerplate; it's removed or deprecated depending on your Twig version.
  • Pin versions on both sides. This package's Twig constraint and TwigBridge's must overlap. A composer update that bumps Twig can leave you with a non-booting app; commit the lock file and test the upgrade path.
  • Cache directories differ. TwigBridge has its own cache config separate from Blade's compiled views. Stale-template bugs usually mean you cleared the wrong directory.
  • Time-based filters and Carbon::setTestNow(). These extensions typically operate on raw DateTimeInterface, so Laravel's frozen clock may not apply. Pass explicit timestamps in tests rather than relying on global time freezing.
  • Extension point worth knowing: since this is a small, MIT-licensed package with essentially no downstream users, treat the classes as copy-pasteable source. Forking an extension into app/Twig/ is often cheaper than waiting for upstream fixes.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource