Weave Code
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

Inky Extra Laravel Package

twig/inky-extra

Twig extension that adds the inky_to_html filter, converting Zurb Inky email templates into HTML. Useful for building responsive email markup within Twig templates in Symfony and other Twig-based apps.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install Dependencies:
    composer require twig/twig twig/inky-extra
    
  2. Configure Twig for Emails: Register a dedicated Twig\Environment in a service provider (e.g., App\Providers\EmailServiceProvider):
    use Twig\Environment;
    use Twig\Loader\FilesystemLoader;
    
    public function register()
    {
        $loader = new FilesystemLoader(__DIR__.'/../resources/views/emails');
        $this->app->singleton('twig.email', function () use ($loader) {
            return new Environment($loader, [
                'cache' => storage_path('twig/email'),
            ]);
        });
    }
    
  3. Create an Inky Template: Save a template at resources/views/emails/welcome.inky.twig:
    {# resources/views/emails/welcome.inky.twig #}
    <inky:message>
        <inky:header>
            <inky:title>Welcome!</inky:title>
        </inky:header>
        <inky:body>
            <inky:section>
                <h1>Hello, {{ name }}!</h1>
                <p>Thanks for joining.</p>
            </inky:section>
        </inky:body>
    </inky:message>
    
  4. Render in a Mailable: Extend Laravel’s Mailable and use the inky_to_html filter:
    use Illuminate\Bus\Queueable;
    use Illuminate\Mail\Mailable;
    use Illuminate\Queue\SerializesModels;
    
    class WelcomeEmail extends Mailable
    {
        use Queueable, SerializesModels;
    
        public function build()
        {
            return $this->markdown('emails.welcome')
                        ->with([
                            'name' => $this->user->name,
                        ])
                        ->withTwig(['name' => $this->user->name])
                        ->withInkyFilter();
        }
    
        protected function withInkyFilter()
        {
            $twig = app('twig.email');
            $html = $twig->getLoader()->getSource('welcome.inky.twig');
            $content = $twig->createTemplate($html)->render([
                'name' => $this->user->name,
            ]);
            return $this->subject('Welcome!')
                        ->html($content);
        }
    }
    

First Use Case: Transactional Email

Replace a static HTML email template with a dynamic Inky + Twig template for password resets:

  1. Move resources/views/emails/password_reset.blade.php to resources/views/emails/password_reset.inky.twig.
  2. Update the template to use Inky’s responsive components:
    <inky:message>
        <inky:header>
            <inky:title>Reset Your Password</inky:title>
        </inky:header>
        <inky:body>
            <inky:section>
                <h1>Hi {{ user.name }},</h1>
                <p>Click the link below to reset your password:</p>
                <inky:button href="{{ reset_url }}">Reset Password</inky:button>
            </inky:section>
        </inky:body>
    </inky:message>
    
  3. Update the ResetPassword Mailable to use the new template:
    public function build()
    {
        return $this->markdown('emails.password_reset')
                    ->with([
                        'user' => $this->user,
                        'reset_url' => $this->resetUrl,
                    ])
                    ->withInkyFilter();
    }
    

Implementation Patterns

Workflow: Dynamic Email Templates

  1. Template Structure: Organize templates by type (e.g., resources/views/emails/transactional/, resources/views/emails/marketing/). Example:

    resources/views/emails/
    ├── transactional/
    │   ├── password_reset.inky.twig
    │   ├── order_confirmation.inky.twig
    ├── marketing/
    │   ├── welcome_series/
    │   │   ├── welcome.inky.twig
    │   │   ├── welcome_part2.inky.twig
    
  2. Reusable Components: Create partials for shared elements (e.g., headers, footers) in resources/views/emails/_partials/.

    {# resources/views/emails/_partials/footer.inky.twig #}
    <inky:footer>
        <inky:section>
            <p>&copy; {{ year }} {{ company_name }}. All rights reserved.</p>
        </inky:section>
    </inky:footer>
    

    Include in templates:

    {% include '_partials/footer.inky.twig' %}
    
  3. Conditional Logic: Use Twig’s {% if %} to handle dynamic content (e.g., premium user features):

    <inky:section>
        <h2>Your Account</h2>
        {% if user.premium %}
            <p>Enjoy premium features like advanced analytics.</p>
        {% else %}
            <inky:button href="{{ upgrade_url }}">Upgrade Now</inky:button>
        {% endif %}
    </inky:section>
    
  4. Loops for Lists: Render dynamic lists (e.g., order items) with Twig loops:

    <inky:section>
        <h2>Order #{{ order.id }}</h2>
        <table>
            <thead>
                <tr><th>Item</th><th>Price</th></tr>
            </thead>
            <tbody>
                {% for item in order.items %}
                    <tr>
                        <td>{{ item.name }}</td>
                        <td>{{ item.price|currency }}</td>
                    </tr>
                {% endfor %}
            </tbody>
        </table>
    </inky:section>
    

Integration with Laravel Mailables

  1. Base Mailable Class: Create a reusable InkyMailable class to avoid boilerplate:

    abstract class InkyMailable extends Mailable
    {
        protected $twigData = [];
    
        public function withTwig(array $data)
        {
            $this->twigData = array_merge($this->twigData, $data);
            return $this;
        }
    
        protected function applyInkyFilter(string $template)
        {
            $twig = app('twig.email');
            $html = $twig->getLoader()->getSource($template);
            $content = $twig->createTemplate($html)->render($this->twigData);
            return $this->html($content);
        }
    }
    

    Extend in child classes:

    class WelcomeEmail extends InkyMailable
    {
        public function build()
        {
            return $this->withTwig(['name' => $this->user->name])
                        ->applyInkyFilter('emails.welcome');
        }
    }
    
  2. Asset Management: Inline critical CSS/JS for email clients that block external resources:

    use Illuminate\Support\Facades\Asset;
    
    protected function applyInkyFilter(string $template)
    {
        $twig = app('twig.email');
        $html = $twig->getLoader()->getSource($template);
        $content = $twig->createTemplate($html)->render($this->twigData);
    
        // Inline CSS if needed (e.g., for Gmail)
        if ($this->shouldInlineCss()) {
            $content = $this->inlineCss($content);
        }
        return $this->html($content);
    }
    
    protected function inlineCss(string $html): string
    {
        // Use a package like `php-css-inliner` or custom logic
        return preg_replace('/<style[^>]*>(.*?)<\/style>/is', '', $html);
    }
    
  3. Testing: Use Laravel’s Mailable testing helpers to verify Inky output:

    public function test_welcome_email()
    {
        $user = User::factory()->create();
        $email = new WelcomeEmail($user);
    
        $this->assertEquals('Welcome!', $email->subject);
        $this->assertStringContainsString('Hello, '.$user->name, $email->render());
    }
    

    For Inky-specific validation, add custom assertions:

    public function assertInkyValid(string $html)
    {
        $this->assertStringContainsString('<inky:message>', $html);
        $this->assertStringContainsString('<inky:header>', $html);
        // Add more Inky-specific checks
    }
    

Advanced Patterns

  1. A/B Testing: Use Twig conditionals to serve different variants:
    {# resources/views/emails/marketing/campaign.inky.twig #}
    {% if campaign.variant == 'A' %}
        {% include 'campaign_variant_a.inky.twig' %}
    {% elseif campaign.v
    
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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle