Introducing Laravel Blade with WordPress - Ultimate Guide for Beginners
In this article, on the example using Laravel Blade and WordPress, I'll explore the reasons why the concept of templating engines in PHP is worth trying, and how it can improve the way you build applications.
In the dynamically changing webdev world, the need for structured and efficient coding practices is a key to success in the long run. One powerful concept that addresses these demands in PHP projects is using templating engines to organize visual layers.
If you build WordPress solutions like custom themes or plugins, or you search for ways to learn something new maybe even outside the WordPress world, I insist you check out this article and make your first steps in the Laravel world 👋
What is Laravel Blade and how does it work?
Blade is the simple, yet powerful templating engine included with Laravel. It is designed to simplify and enhance the way developers create views for web applications, making it easier to manage and display dynamic content in a structured and organized manner.
Blade templates are defined in the blade.php
files and consist of typical HTML mark-up boosted up with placeholders used for displaying dynamic data, directives that can be used for extending layouts, and directives that are shortcuts for common PHP control structures. How it can be used for defining views in WordPress-based applications?
Most web apps utilize the same general layout across various pages and maintaining them would be hard if I had to repeat the entire HTML in every view I create. Of course, WordPress has functions that help avoid this, but, let's give it a try and check how it can be achieved in a more structured manner.
<!doctype html>
<html {!! language_attributes() !!}>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
{!! wp_head() !!}
</head>
<body {!! body_class() !!}>
{!! do_action('wp_body_open') !!}
{!! do_action('get_header') !!}
<div class="app">
@section('content')
<main class="app__content">
{!! the_content() !!}
</main>
@show
@yield('sidebar')
</div>
{!! do_action('get_footer') !!}
{!! do_action('wp_footer') !!}
</body>
</html>
General layout of my application in Blade consists of typical HTML markup with more clear syntax for displaying the data {{ }}
. However, take note of the @section
and @yield
directives which can be used for defining slots to fill by child templates.
@section
Defines slot that can be overwritten and displays it using@show
.@yield
Defines slot that can be filled with content and displayed immediately.
I mostly use only @yield
directives, because I don't need the default structure to be set. I just want to display slots content, but there is full freedom when it comes to using it.
It's time to create the first index.blade.php
template that will be equivalent to the default index.php
file used in WordPress themes. The structure there will be simple - for all the default templates in my theme I just need to show the_content
results in the main content and a simple widget with external links in the sidebar.
@extends('base')
@section('sidebar')
<sidebar class="app__sidebar">
{!! do_action('get_sidebar') !!}
</sidebar>
@endsection
So I just need to extend the base template using @extend('base')
directive at the beginning and fill the sidebar slot defined by @yield('sidebar')
with content using @section('content')
and @endsection
. The engine will render template using general layout and custom structure set in slot. It already looks great to me 🤩
While working with WordPress I mostly build more than one view so let's add single.blade.php
which will be equivalent to single.php
in the default template hierarchy. The layout should include the post title and content without a sidebar.
@extends('base')
@section('content')
<main class="app__content">
<h1>
{!! the_title() !!}
</h1>
{!! the_content() !!}
</main>
@endsection
To achieve the required results I just need to overwrite the default structure defined with @section('content')
directive and add the title there. When it comes to the sidebar, I don't need to do anything because the sidebar slot is empty by default.
Now, it would be great to have some header across the whole application. The best way to do this is to modify the base.blade.php
layout that is already inherited by other templates and inject the header using the @include
directive. I don't need to specify the full path to the partial that needs to be included. I rather pass a template name which is something like a path chain. Template located in the resources/views/partials/header.blade.php
will have partials.header
key.
(...)
<div class="app">
@section('header')
@include('partials.header')
@show
@section('content')
@include('partials.content')
@show
@yield('sidebar')
</div>
(...)
As the last step, during the render process, the engine compiles Blade templates to plain PHP code, caches them and serves them when requested. The cached results used by the theme look as follows:
<?php $__env->startSection('content'); ?>
<main class="app__content">
<h1>
<?php echo the_title(); ?>
</h1>
<?php echo the_content(); ?>
</main>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('base', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?
Why to use Laravel Blade in WordPress?
Blade does not restrict from using plain PHP in the templates. In fact, all Blade templates are compiled into plain PHP code and cached until they are modified meaning Blade adds essentially zero overhead to the application which combined with new learning opportunities (Laravel) is enough argument for giving it a try, at least for me 👌
Let's check what problems it might solve in the WordPress application.
#1 Separation of Concerns: Tackling Spaghetti Code
Blade forces to think more about the Separation of Concerns concept, which in terms of templating emphasizes a clear division between the business logic and the presentation layer. Developers are encouraged to structure their code in a more organized manner.
Speaking in simple words, it just helps avoid spaghetti code, which by the way is one of the biggest problems in the whole WordPress ecosystem for me. It's not hard to find code with mixed logic and presentation, with hard-to-read and not clear structure even in the WordPress core, making maintenance and collaboration a nightmare in some cases.
Such separation streamlines development and allows different teams to work on various aspects of the project without interfering with each other. Front-end developers can focus on designing and perfecting the user interface without worrying about the underlying PHP code, while back-end developers can implement the logic without being entangled in the presentation layer intricacies.
#2 Templating: Enhancing Code Reusability
Blade takes a different approach to template inheritance. Developers can easily define parent layouts that establish the overall structure of a page using @yield
and @section
directives which indicate where the child views will inject their content.
This powerful mechanism allows developers to provide specific content for each page without altering the parent layout's core structure. It reduces potential duplication, improves readability and makes maintenance over time easier. It's like applying some SOLID rules to templating.
#3 Readability: Clean and Intuitive Syntax
Blade stands out for its clean and easy-to-read syntax. Building on familiar constructs like curly braces and directive tags, Blade templates remain intuitive for both PHP developers and front-end developers. This clarity leads to better code comprehension and reduces the learning curve for new team members.
For PHP developers accustomed to writing inline PHP within HTML, Blade provides a refreshing change. Instead of embedding PHP code within HTML tags, Blade lets developers use double curly braces to echo variables or employ directives like @if
, @foreach
, and @include
, making the code more legible and maintainable.
How to use Laravel Blade in WordPress?
Some developers would probably say "Just install the plugin!", but If you follow me for a longer period, you know that I don’t use such an approach by default, especially when it comes to such simple things. Also, my mission is to inspire you to learn how exactly WordPress works, so I'll integrate Blade from scratch with a few simple steps, without plugins. Once done, can be used in all projects.
#1 Installing Laravel Blade Component
Blade is a part of the Laravel framework, but fortunately, it can be used standalone, just as any other tool. So as a first step, I install illuminate/view
component from Laravel.
composer install illuminate/view
#2 Initializing Laravel Blade Engine
Now, I need to initialize the engine which will take care of compiling templates. In the Laravel application, it's available out of the box, but once I use Blade outside its context I need to do it manually using the view Factory
, which as the name suggests, produces output for Blade template.
namespace FM\Templates;
use Illuminate\Events\Dispatcher;
use Illuminate\View\Factory;
use Illuminate\View\FileViewFinder;
use Illuminate\View\Compilers\BladeCompiler;
use Illuminate\View\Engines\EngineResolver;
use Illuminate\View\Engines\CompilerEngine;
class Provider
{
private ?Factory $factory = null;
public function __construct()
{
add_action('after_setup_theme', fn() => $this->init());
}
public function render(string $template, array $data = []): void
{
echo $this->generate($template, $data);
}
public function generate(string $template, array $data = []): string
{
return fm()->filesystem()->exists($template)
? $this->factory->file($template, $data)->render()
: $this->factory->make($template, $data)->render();
}
private function init(): void
{
$compiler = new BladeCompiler(fm()->filesystem(), fm()->config()->get('cache.path'));
$resolver = new EngineResolver();
$finder = new FileViewFinder(fm()->filesystem(), [fm()->config()->get('views.path')]);
$dispatcher = new Dispatcher();
$resolver->register('blade', fn() => new CompilerEngine($compiler));
$this->factory = new Factory($resolver, $finder, $dispatcher);
}
}
I do this in the after_setup_theme
action and make sure that the object is stored as a private property to prevent usage outside the scope. The only way to use it is just by generate
and render
functions which can be used for rendering output based on the template path or name and the data that should be injected. Encapsulation rulez! 😈
If you're interested in more detailed information about this object, how it is created, and what happens in
init()
function I insist you to check out the .
The template provider is ready to use so now, I need to make it available in the application. I create a new Templating
module, initialize Provider
there, add a render
shortcut to reduce chain length, and inject the module into the app facade.
namespace FM\Templates;
use FM\Templates\Provider;
class Templates
{
private Provider $provider;
public function __construct()
{
$this->provider = \FM\App::init(new Provider());
}
public function render(string $template, array $data = []): void
{
$this->provider->render($template, $data);
}
}
If you don’t get what happens here, I insist you check out material I’ve created about structuring application logic using Singleton and facades 👋
#3 Rendering Blade Templates
To render a specific template you can use the render
function and specify the template key. For instance, to render the resources/views/single.blade.php
template you can use:
fm()->templates()->render('single');
If you need more flexibility, you can provide a full path to the Blade template that you wish to render. In this case, the template doesn't need to be placed in the resources/views
.
fm()->templates()->render(ABSPATH . '/wp-content/themes/footmate/example.blade.php');
If you develop plugins, you can end up here, because you render views manually, but If you develop themes, an additional step needs to be done for everything to make sense.
How to use Laravel Blade with Templates?
The template hierarchy algorithm reduces the work needed for developing themes by resolving proper PHP files based on the current view. It simply checks what template is available in a specific hierarchy, and renders it when found. I don’t want to break this when using Blade so I need to integrate both with Resolver
class.
namespace FM\Templates;
class Resolver
{
/**
* @filter 404_template_hierarchy
* @filter archive_template_hierarchy
* @filter attachment_template_hierarchy
* @filter author_template_hierarchy
* @filter category_template_hierarchy
* @filter date_template_hierarchy
* @filter embed_template_hierarchy
* @filter frontpage_template_hierarchy
* @filter home_template_hierarchy
* @filter index_template_hierarchy
* @filter page_template_hierarchy
* @filter paged_template_hierarchy
* @filter privacypolicy_template_hierarchy
* @filter search_template_hierarchy
* @filter single_template_hierarchy
* @filter singular_template_hierarchy
* @filter tag_template_hierarchy
* @filter taxonomy_template_hierarchy
*
* @see https://github.com/WordPress/WordPress/blob/master/wp-includes/template.php#L30-L62
*/
public function relocate(array $templates): array
{
$templates = array_map(fn($item) => preg_replace('/^[^\/]+\/|(\.blade)?\.php$/', '', $item), $templates);
$templates = array_map(fn($item) => fm()->config()->get('views.path') . '/' . $item . '.blade.php', $templates);
$templates = array_map(fn($item) => str_replace(fm()->config()->get('resources.path') . '/', '', $item), $templates);
return $templates;
}
/**
* @filter template_include
*/
public function render(string $template): string
{
fm()->templates()->render($template, []);
return fm()->config()->get('resources.path') . '/index.php';
}
}
I need to inform WordPress that it should search for templates in another location which now is resources/views
and with another extension which is blade.php
. Those processes are done by hooking some filters to relocate
function [5-33]
.
Then I need to force WordPress to use Blade templates instead of native one using previously created render
function. I do this by hooking into template_include
filter which provides a path to the template as a parameter. Thanks to the previous step it already includes blade.php
file so I just need to use the render
function and return the path to an empty index.php
file to not change native flow [35-43]
.
/**
* @filter template_include
*/
public function handle(string $template): string
{
$this->render($template, []);
return fm()->config()->get('path') . '/index.php';
}
And that's all! The native WordPress templating system currently supports writing templates in Blade. Once I create a new template based on the native hierarchy, it will be automatically loaded.
What does the Community think about this?
What others think about this topic? Here, you'll find a chorus of voices, each adding their unique hue to the canvas of discussion. Check out them as well as and explanations in the following threads 🔥
Unless you’re building quite complex layouts in a huge codebase, most of the benefits it offers can just be remedied by good coding practices.
— Charaf Mrah (@charafmrah) August 7, 2023
And I’m saying that as someone that hates PHP syntax 😂 Blade’s syntax is definitely great imo
While WP doesn't have a templating engine it's extensible enough, that we can use either Blade (via @rootswp Sage) or Twig (via @TimberWP).
— Maciek Palmowski (@palmiak_fp) August 15, 2023
Personally I think that using templating engines makes the process easier.
And I'm not the only one - @przemekhernik wrote this great… https://t.co/SQO6hanF2F
In conclusion, adopting Laravel Blade within WordPress offers many benefits. From improving code organization, to enhancing readability and maintainability with its clean syntax, and finally, promoting code reusability through template inheritance - Blade takes development to new level.
Whether you are a backend developer valuing the structured approach or a frontend developer appreciating the power of template inheritance, Laravel Blade brings something valuable to the table for everyone. Embracing this templating engine empowers WordPress developers to build sophisticated, efficient, and collaborative projects that will for sure have an impact for your success.
Looking for a developer who
truly cares about your business?
My team and I provide expert consultations, top-notch coding, and comprehensive audits to elevate your success.
Feedback
How satisfied you are after reading this article?