Installation:
composer require roots/acorn
Follow the official installation guide to scaffold a new project or integrate into an existing WordPress project using Bedrock.
First Use Case:
Replace a WordPress template file (e.g., page.php) with a Blade template in resources/views/page.blade.php. Use Laravel’s Blade syntax:
<h1>{{ $post->post_title }}</h1>
<div>{{ $post->post_content }}</div>
Register the template in app/Providers/AppServiceProvider.php:
use Roots\Acorn\View\ViewServiceProvider;
public function boot()
{
ViewServiceProvider::registerTemplate('page', 'page');
}
Key Files to Explore:
app/Providers/ – Service providers for Laravel integrations.resources/views/ – Blade templates.routes/web.php – Laravel routes (coexist with WordPress)..env – Environment variables (shared between Laravel and WordPress).Hybrid Routing:
// routes/web.php
Route::get('/api/data', function () {
return response()->json(['data' => 'Hello from Laravel!']);
});
Service Integration:
spatie/laravel-permission for user roles):
composer require spatie/laravel-permission
Configure in config/acorn.php:
'providers' => [
Spatie\Permission\PermissionServiceProvider::class,
],
Blade in WordPress:
// app/Providers/ViewServiceProvider.php
public function boot()
{
ViewServiceProvider::registerTemplate('single', 'posts.single');
}
$post, $wp_query, etc., in Blade:
<article>
<h1>{{ $post->post_title }}</h1>
<p>{{ $post->post_content }}</p>
</article>
Database Abstraction:
// app/Models/Post.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $table = 'wp_posts';
}
$posts = Post::where('post_status', 'publish')->get();
Events and Listeners:
// app/Providers/EventServiceProvider.php
protected $listen = [
'eloquent.created: App\Models\Post' => [
'App\Listeners\LogPostCreation',
],
];
Artisan Commands:
php artisan make:command SyncPosts
Register in routes/console.php:
$this->commands([
\App\Console\Commands\SyncPosts::class,
]);
Caching:
Cache::put('key', 'value', $seconds);
Validation:
use Illuminate\Support\Facades\Validator;
$validator = Validator::make($data, [
'email' => 'required|email',
]);
resources/views/partials/ for reusable Blade components. Include them in WordPress templates:
@include('partials.header')
config/acorn.php to isolate cache/session per site:
'multisite' => [
'enabled' => true,
'cache_prefix' => 'wp_{site_id}_',
],
vite.config.js:
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
plugins: [
laravel({
input: ['resources/js/app.js'],
refresh: true,
}),
],
});
Access assets in Blade:
<script type="module" src="{{ vite('resources/js/app.js') }}"></script>
Request Handling:
config/acorn.php:
'wordpress_request_handler' => [
'enabled' => true,
'priority' => 10,
],
Superglobals:
$post, $wp_query) are not automatically available in Laravel contexts. Access them via:
global $post, $wp_query;
Or bind them in service providers:
View::share('post', $post);
Database Connections:
wp_ tables are not automatically mapped to Eloquent. Define custom tables:
class Post extends Model
{
protected $table = 'wp_posts';
public $timestamps = false; // WordPress uses `post_date` instead of `created_at`
}
Session Flash Data:
session()->flash('success', '...')) may not persist across WordPress template requests. Use middleware to re-flash:
// app/Http/Middleware/FlashSession.php
public function handle($request, Closure $next)
{
if (session()->has('flash')) {
foreach (session('flash') as $key => $message) {
session()->flash($key, $message);
}
session()->forget('flash');
}
return $next($request);
}
Middleware Conflicts:
WP_Rewrite and Laravel’s routing may conflict. Use Acorn’s RouteServiceProvider to merge rules:
public function boot()
{
parent::boot();
$this->mergeWordPressRules();
}
Asset Paths:
get_template_directory_uri(), while Laravel uses asset(). Configure aliases in config/acorn.php:
'aliases' => [
'asset' => function () {
return get_template_directory_uri() . '/dist';
},
],
Queue Workers:
php artisan queue:work --daemon
Multisite Cache Isolation:
'multisite' => [
'cache_prefix' => 'wp_{site_id}_',
],
config/logging.php to write to WordPress’s debug log:
'channels' => [
'single' => [
'driver' => 'single',
'path' => WP_CONTENT_DIR . '/debug.log',
'level' => 'debug',
],
],
WP_DEBUG and Acorn’s --verbose flag:
WP_DEBUG=1 acorn about --verbose
php artisan route:list
Or in Blade:
@dd(\Illuminate\Support\Facades\Route::getRoutes()->getRoutes())
Custom Providers:
Extend Laravel’s service container in app/Providers/AppServiceProvider:
public function register()
{
$this->app->bind('custom.service', function () {
return new CustomService();
});
}
WordPress Hooks as Events:
Convert WordPress hooks to Laravel events in app/Providers/EventServiceProvider:
add_action('wp_loaded', function () {
event(new \App\Events\WordPressLoaded);
});
Custom Artisan Commands: Extend WP-CLI with:
php artisan make:command CustomCommand
How can I help you explore Laravel packages today?