eqxdev / wordpress-blade
Use the Laravel Blade templating engine in WordPress plugins and themes.
Requires
- php: ^8.2
- illuminate/events: ^11.0|^12.0
- illuminate/view: ^11.0|^12.0
Requires (Dev)
- laravel/pint: ^1.18
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
README
Use the Laravel Blade templating engine in WordPress plugins and themes.
Requirements
- PHP 8.2 or higher
- Laravel/Illuminate 11.x or 12.x
Installation
composer require eqxdev/wordpress-blade
Usage
<?php require 'vendor/autoload.php'; use EqxDev\Blade\Blade; $viewsPath = __DIR__ . '/views'; $cachePath = __DIR__ . '/cache'; $blade = new Blade($viewsPath, $cachePath); // Render a view echo $blade->view()->make('hello', ['name' => 'World'])->render();
Multiple View Directories
You can pass an array of directories to search for views:
$blade = new Blade([__DIR__ . '/views', __DIR__ . '/shared-views'], $cachePath);
Custom Event Dispatcher
If you need to provide your own event dispatcher (for example, to listen to view events):
use Illuminate\Events\Dispatcher; $events = new Dispatcher; $blade = new Blade($viewsPath, $cachePath, $events);
Accessing the Blade Compiler
Register custom directives by accessing the compiler directly:
$blade->getCompiler()->directive('datetime', function (string $expression): string { return "<?php echo ($expression)->format('Y-m-d H:i'); ?>"; });
Clearing the Compiled View Cache
Remove all compiled view files from the cache directory:
$blade->clearCache();
Using All Blade Features
This package supports all Blade features as described in the Laravel documentation: https://laravel.com/docs/12.x/blade
WordPress Integration
This package works as a Composer dependency for WordPress plugin and theme development.
Setup
use EqxDev\Blade\Blade; use EqxDev\Blade\WordPressDirectives; $blade = new Blade( get_template_directory() . '/views', wp_upload_dir()['basedir'] . '/blade-cache', ); WordPressDirectives::register($blade->getCompiler());
For child themes, pass both the child and parent view directories:
$blade = new Blade( [get_stylesheet_directory() . '/views', get_template_directory() . '/views'], wp_upload_dir()['basedir'] . '/blade-cache', );
Cache Directory
Use a dedicated path outside wp-content/cache/ to avoid WordPress caching plugins (WP Rocket, LiteSpeed Cache, WP Super Cache) from purging your compiled Blade templates:
// Good - dedicated directory wp_upload_dir()['basedir'] . '/blade-cache' WP_CONTENT_DIR . '/blade-cache' // Bad - inside the cache directory managed by WP caching plugins WP_CONTENT_DIR . '/cache/blade'
Cache Invalidation
Hook into WordPress events to clear compiled views when templates may have changed:
// Clear on theme switch and plugin/theme updates add_action('after_switch_theme', fn () => $blade->clearCache()); add_action('upgrader_process_complete', fn () => $blade->clearCache()); // Hook into popular caching plugins add_action('wp_cache_cleared', fn () => $blade->clearCache()); // WP Super Cache add_action('rocket_after_clean_cache_busting', fn () => $blade->clearCache()); // WP Rocket add_action('litespeed_purged_all', fn () => $blade->clearCache()); // LiteSpeed Cache
WordPress Directives
The WordPressDirectives class registers Blade directives for common WordPress functions that echo output directly (and therefore can't be used with {{ }}).
Output
| Directive | Equivalent |
|---|---|
@wphead |
<?php wp_head(); ?> |
@wpfooter |
<?php wp_footer(); ?> |
@wpbodyclass |
<?php body_class(); ?> |
@wpbodyclass('extra') |
<?php body_class('extra'); ?> |
@wptitle |
<?php the_title(); ?> |
@thecontent |
<?php the_content(); ?> |
@theexcerpt |
<?php the_excerpt(); ?> |
The WordPress Loop
@wploop <article> <h2>{{ get_the_title() }}</h2> @thecontent </article> @wpempty <p>No posts found.</p> @endwploop
Custom WP_Query
Automatically calls wp_reset_postdata() when the loop ends:
@wpquery(['post_type' => 'page', 'posts_per_page' => 5]) <h2>{{ get_the_title() }}</h2> @wpempty <p>No pages found.</p> @endwpquery
Authentication
| Directive | Checks |
|---|---|
@wpauth / @endwpauth |
is_user_logged_in() |
@wpguest / @endwpguest |
! is_user_logged_in() |
@wprole('capability') / @endwprole |
current_user_can('capability') |
@wpauth <p>Welcome, {{ wp_get_current_user()->display_name }}!</p> @endwpauth @wprole('manage_options') <a href="{{ admin_url() }}">Dashboard</a> @endwprole
Hooks, Sidebars, and Shortcodes
| Directive | Equivalent |
|---|---|
@wpaction('hook_name') |
<?php do_action('hook_name'); ?> |
@wpfilter('hook', $value) |
<?php echo apply_filters('hook', $value); ?> |
@wpsidebar('sidebar-id') |
<?php dynamic_sidebar('sidebar-id'); ?> |
@wpshortcode('[gallery]') |
<?php echo do_shortcode('[gallery]'); ?> |
Example Template
<!DOCTYPE html> <html> <head> @wphead </head> <body @wpbodyclass> @wpauth <p>Welcome back, {{ wp_get_current_user()->display_name }}!</p> @endwpauth @wploop <article> <h2>{{ get_the_title() }}</h2> @thecontent </article> @wpempty <p>No posts found.</p> @endwploop @wpsidebar('footer-widgets') @wpfooter </body> </html>
Development
# Run tests composer test # Run static analysis composer analyse # Check code style composer lint # Fix code style composer fix
License
MIT