Custom blade directives in Laravel 5

Roughly a 4 minute read by Chris Willerton

Anyone who uses Laravel as a framework day to day already knows how great Laravel’s blade syntax is, and it’s been made even more powerful recently with Laravel 5 due to the addition of custom blade directives.

You might be already familiar with existing blade directives such as @section and @foreach but the scope for adding your own means you can have powerful and simple functionality that feels right at home. Let's take a look at some examples.

Note: This post was written with Laravel 5.2 in mind. In Laravel 5.3 Blade directives have changed slightly (specifically the format of the $expression variable). Review the 5.2 to 5.3 upgrade guide in the Laravel docs for more info.

To start simply, let’s imagine you want to output some HTML when you use the @customHtml directive. This particular example can just be achieved using @include, but let’s just imagine we’re not doing it that way.

We want to use this:

@customHtml

To generate this:

<p>Some custom HTML</p>

To get this to work you need to add the below into your AppServiceProvider, in the boot method. Essentially you are hooking into the default blade templater and adding in your own functionality.

Blade::directive(‘customHtml’, function($expression)
{
    return "<p>Some custom HTML</p>";
});

Note: Remember to import the Blade class in your service provider ("use Blade").

This example is a bit needless, and is mainly to demonstrate how custom blade directives work. It should start to get you thinking about what you can achieve with this sort of functionality though. Let’s look at a more complicated example.

Imagine you have a system where you want to include the same bit of HTML on multiple pages; this might be a CMS with various field types: inputs, textareas etc. You could use the @include directive to include the same bit of input HTML on each page that needs it, which is perfectly fine. But, you could use a blade directive and neaten this process, especially if your input view is hidden away in multiple subdirectories. Essentially you are trying to simplify something that is either complicated or hard to remember. With this in mind, you can convert this:

@include(‘cms.content.forms.fields.input’)

Into this:

@input

Again, you can register the below directive in your AppServiceProvider, in the boot method.

Blade::directive('input', function($expression)
{
    $view = ‘cms.content.forms.fields.input’; // Path to your view

    if (!$expression)
    {
        $expression = '([])';
    }

    return "<?php echo \$__env->make('{$view}', array_except(get_defined_vars(), ['__data', '__path']))->with{$expression}->render(); ?>";
});

This directive is a little bit more involved. At it’s simplest it’s just a shortcut which mimics the @include directive. It’s a bit more complicated though because you need to ensure any data passed into the directive is available on the view when it is rendered. The return statement above will take care of this for you though. It will make the below work as you’d expect:

@input([‘name’ => ‘slug’])

Now in our input view we’d have access to a $name variable, but we’d also have access to any other data that we had access to in the parent view.

To summarise:

  • You can extend blade with your own custom directives.
  • Directives follow the @nameOfYourDirective format and can be passed an expression in brackets following the directive name.
  • The directive calls a closure where you can return a string which will be treated as PHP; this massively increases the usefulness of the feature.
  • Custom directives are mainly for simplifying things that are complicated or hard to remember.
  • One thing to bear in mind is that Laravel caches views, so be careful about what you do in the directive closure as it might not work as you expect. If you do something "dynamic" in the closure then this won't work because the closure won't be called if the view is cached.

Imagine what else you can achieve with custom directives. As with anything, there is a time and a place to use this functionality, but it’s another tool in Laravel designed to make your development life easier.

For more information you can read the Laravel docs or simply Google “laravel custom blade directives”.