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

Twital Bundle Laravel Package

goetas/twital-bundle

A Symfony bundle that integrates Twital, an HTML-syntax extension for Twig. It lets you write templates using familiar HTML-like tags and attributes while keeping Twig’s features, and wires Twital into Symfony configuration and templating.

View on GitHub
Deep Wiki
Context7

Getting Started

First, the important framing: goetas/twital-bundle is a Symfony bundle, not a Laravel package. It wires the goetas/twital templating engine (Twig syntax plus TAL-style attributes and macro/slot composition) into Symfony's templating service. There is no service provider, no Blade integration, no php artisan hook — and with 0 dependents and ~20 stars, there is no community glue to lean on. If your project is a pure Laravel app, this package is not something you composer require and start using.

What changed in 1.6.0: a single compatibility PR (hason, #15) bringing the bundle in line with Symfony 3, 4 and 5. No new features, no deprecations, no API changes. The practical signal is the supported floor and ceiling: the bundle is maintained against the Symfony 3–5 line, so treat Symfony 6/7 as unverified territory rather than the default assumption.

Where it is relevant for a Laravel developer day-to-day:

  1. You work across a Symfony/Laravel estate and need to touch a Symfony service that already uses Twital (legacy TAL-style templates for email, PDFs, or CMS fragments).
  2. You want TAL semantics inside a Laravel app — in which case you skip the bundle entirely and use the underlying goetas/twital library directly.

Getting started on the Symfony side (confirm your Symfony version first — see Gotchas):

composer require goetas/twital-bundle:^1.6
// config/bundles.php
return [
    // ...
    Goetas\TwitalBundle\GoetasTwitalBundle::class => ['all' => true],
];
# config/packages/twital.yaml
twital: ~

Then confirm the engine is registered: bin/console debug:container twital (the exact service id and option keys live in the bundle's DependencyInjection/Configuration.php; check that file rather than trusting blog posts).

Getting started on the Laravel-adjacent side (standalone, no bundle):

composer require goetas/twital

Bind the engine as a singleton in a service provider, point it at storage_path('framework/views/twital'), and wrap ->render('view.twital', $vars) behind a small façade. That is basically the same wiring the Symfony bundle does — you are reimplementing it, because nothing ships for Laravel.

First use case: a template where repeating/conditioning lives as attributes rather than blocks:

<ul>
  <li t:repeat="item items" t:content="item.name"></li>
</ul>

Implementation Patterns

Symfony: inject the engine service, don't reach into the container.

use Goetas\TwitalBundle\Twital\Engine;

final class InvoiceMailer
{
    public function __construct(private Engine $twital) {}

    public function render(array $data): string
    {
        return $this->twital->render('@App/invoice.twital', $data);
    }
}

Template layout convention. Put .twital files in templates/ and resolve them by relative path from the bundle/root; Twital's own loader handles the extension. Don't mix .twig and .twital in the same folder — Twital is not Twig, and Twig filters/functions will silently not exist.

Composition with macros/slots (the main thing Twital gives you over Twig). Use metal:use-macro and t:block-style slots for layout inheritance instead of Twig's {% extends %}:

<!-- layout.twital -->
<html>
  <body>
    <div metal:define-macro="content"></div>
  </body>
</html>
<!-- page.twital -->
<div metal:use-macro="layout.twital/content">
  <h1 t:content="title"></h1>
</div>

This gives server-rendered fragment composition with clean override points — genuinely useful for email templates and PDF layouts where you'd otherwise litter @include with conditional variables.

Integration tip for Laravel-only environments. If you adopt Twital standalone, register it as a view engine rather than calling it ad-hoc:

// AppServiceProvider::boot()
$this->app->singleton('twital', fn () => new \Goetas\Twital\Twital(
    storage_path('framework/views/twital'),
    config('twital.options', [])
));

\View::addExtension('twital', 'twital', function ($app) {
    return new TwitalViewEngine($app['twital']);
});

Then view('mail.invoice.twital', $data) works and you keep the rest of your Blade world untouched. This is the only realistic "day-to-day" story for a Laravel developer.

Cache invalidation. Both paths have an on-disk compiled cache. Wire php artisan view:clear (or your own command) to rm -rf storage/framework/views/twital, otherwise you will spend an hour chasing "why did my template change not appear."

Gotchas and Tips

  • Do not composer require the bundle in a Laravel app. It declares a Symfony\Bundle dependency and provides no ServiceProvider; auto-discovery will do nothing and you'll get confusing container errors or nothing installed at all.
  • Symfony 6/7 are not covered by 1.6.0. The release explicitly targets Symfony 3, 4 and 5. If you're on 6.x/7.x, you are running against untested constraints — pin with composer why-not goetas/twital-bundle ^1.6 and read the composer.json requirements before wiring anything in. This is the single most important thing the new release tells you.
  • 1.6.0 is a maintenance release, not a feature release. Nothing to migrate to, nothing to refactor around. If you're already on 1.5.0 and Symfony 3–5, the upgrade is a version bump; if you're on Symfony 6/7, 1.6.0 does not solve your problem.
  • Twital ≠ Twig. {{ ... }}-style syntax lives inside attribute values, not at the top level. {% for %}, {% extends %}, and most Twig extensions are unavailable. Any Twig filter you rely on must be re-imported into the Twital environment, or expressed with TAL semantics.
  • Configuration is YAML-first. The bundle's prepend/Configuration class controls cache dir, debug flag, and possibly template extension. Read vendor/goetas/twital-bundle/DependencyInjection/Configuration.php and the TwitalExtension before assuming a key exists.
  • Symfony profiler. Older versions of the bundle exposed a Twital panel in the web profiler; treat that as best-effort on any Symfony line and verify. If templates look stale in dev, toggle the debug flag rather than guessing.
  • Version churn / maintenance signal. 1.6.0 is a compatibility patch on a repo with essentially no dependents. Constraints span Symfony 3 through 5 and the PHP floor is correspondingly loose — don't assume modern PHP idioms or Symfony 6 deprecation-free code inside. Check the actual composer.json rather than any release-note summary.
  • Zero dependents means no safety net. Expect edge-case bugs in attribute parsing for unusual HTML, and expect no Stack Overflow answers. Budget time to read goetas/twital source (the Parser, Visitor, and attribute handlers) — that's where the real behaviour lives, and the bundle release cadence won't help you there.
  • Extension points. The right place to add custom syntax is Twital's attribute handler/dialect system, not subclassing the bundle. In Symfony, tag your handler services; in standalone, register them on the engine. This is how you add project-specific TAL attributes (e.g., t:translate wrapping your Laravel translator).
  • Debugging tip. When a template silently renders unchanged, drop into the compiled cache directory and read the generated PHP. Twital compiles to PHP classes; the output is far more informative than the runtime stack trace. Then set Xdebug to step through the generated file — you'll see exactly which attribute handler fired.
  • Escaping. TAL t:content escapes by default; use the explicit structure/unescaped variants deliberately. Mixing raw HTML into t:content is the single most common bug when porting from Blade, and it fails open (you'll get escaped tags in the page, not an error).

Verdict for a Laravel developer: unchanged by 1.6.0. This was a Symfony-compatibility housekeeping release with no Laravel surface area whatsoever — unless you're forced into it by an existing Symfony 3/4/5 service, the day-to-day leverage is low. The realistic use remains goetas/twital (not the bundle) as a niche view engine for email/PDF fragment composition where TAL's slot semantics beat Blade @include gymnastics. Budget one afternoon of reading the underlying library; the bundle itself is effectively irrelevant to you.

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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect