DEV Community

Eka
Eka

Posted on

Keep your templates short and tidy with Laravel Blade custom conditional directives

The Laravel Blade templating engine provides us with a number of conditional directives, namely @if, @unless, @isset, @empty, and even directives for checking common use cases such as user authentication and environment name.

Some examples:

@if (count($records) === 1)
    I have one record!
@elseif (count($records) > 1)
    I have multiple records!
@else
    I don't have any records!
@endif
@auth
    // The user is authenticated...
@endauth

@guest
    // The user is not authenticated...
@endguest

See the complete list of Blade directives in the official documentation.

Problem

Useful as they are, we may need custom conditionals not covered by the directives provided out of the box.

Some scenarios where we may end up with long conditionals:

  • Although internationalisation and localisation are ideally managed outside view templates, we may need conditionals based on the active language, for instance to add CSS styles.
  • Our website/app is published to several markets with slightly different requirements but otherwise share the same codebase. Thus we may deal with environments like market-a-production, market-a-staging, market-b-production, market-b-staging.
    • The env names might even be irregular, for instance production, staging, market-b-production, and market-b-staging.
  • ... and other product-specific cases

When we need to write this kind of conditional multiple times, it makes our template files messy and increases typo risk.

Solution

Enter the Blade::if method. We can make as many as we want in the boot method of our AppServiceProvider.

Example from the official documentation:

// app/Providers/AppServiceProvider.php

use Illuminate\Support\Facades\Blade;

class AppServiceProvider extends ServiceProvider
{
  public function boot() {
    // Start custom conditional
    Blade::if('cloud', function ($provider) {
      return config('filesystems.default') === $provider;
    });
    // end
  }
}
  • The custom conditional directive is called cloud (we can use any name we want).
  • The function takes the passed value as argument. If the $provider value passed in the template equals the value of config('filesystems.default'), it returns true.

Then we can use it like this.

// resources/views/your_template_file.blade.php
@cloud('digitalocean')
    // The application is using the digitalocean cloud provider...
@elsecloud('aws')
    // The application is using the aws provider...
@else
    // The application is not using the digitalocean or aws environment...
@endcloud

More examples

Say our website is available in multiple languages, both left-to-right (such as English) and right-to-left (such as Arabic and Hebrew). We may need to apply different CSS styles or markup based on the language direction. We can configure a custom conditional to accommodate this.

// app/Providers/AppServiceProvider.php

$RTL_LANG = ['ar', 'he']; // One place to modify if we add more RTL languages

Blade::if('langrtl', function () {
  return in_array($app()->getLocale(), $RTL_LANG) ? true : false;
});
// resources/views/your_template_file.blade.php

// BEFORE: Long conditional 😫
@if (app()->getLocale() === 'ar' || app()->getLocale() === 'he')
  // RTL language stuff...
@endif

// AFTER: More concise πŸ˜ƒ
@langrtl()
  // RTL language stuff...
@endlangrtl

As another example, we add a conditional that targets multiple environments. β€œMarket A” website uses the environments production and staging, while β€œMarket B” website uses market-b-production and market-b-staging.

// app/Providers/AppServiceProvider.php
Blade::if('envmarket', function ($market) {
  if ($market === 'a') {
    return $this->app->environment() === 'staging' || $this->app->environment() === 'production';
  } elseif ($market === 'b') {
    return $this->app->environment() === 'market-b-staging' || $this->app->environment() === 'market-b-production';
  }
});
// resources/views/your_template_file.blade.php

// BEFORE: Long conditional 😫
@if (in_array(App::environment(), ['staging', 'production']))
  // Market A stuff...
@if (in_array(App::environment(), ['market-b-staging', 'market-b-production']))
  // Market B stuff...
@endif

// AFTER: More concise πŸ˜ƒ
@envmarket('a')
  // Market A stuff...
@elseenvmarket('b')
  // Market B stuff...
@endenvmarket

Conclusion

Ideally, we should have as little logic as possible in our view templates and delegate it to controllers, services, and helper functions instead. In reality, it's not always 100% possible and we may need to add custom conditionals to our view template files. The Blade::if method helps us abstract away frequently-used custom conditionals, and thus keeping our template files tidy.

Top comments (0)