Pollora is a framework that runs WordPress inside a Laravel application. Laravel boots first and handles front-end requests with its router, controllers, and Blade, while the WordPress admin, database, and plugins keep working.
Here's what the framework gives you:
- WordPress-aware routing: Laravel routes on conditional tags, with the template hierarchy as a fallback
- Attribute registration: post types, taxonomies, hooks, and REST routes declared as PHP attributes
- Blade themes and blocks: Blade views, Vite assets, and Gutenberg blocks rendered with Blade
- Eloquent models: WordPress data through Colt, a fork of Corcel
- Media storage: the media library on any Laravel disk, including S3 and R2
- Agent tooling: Pollora guidelines and MCP tools through Laravel Boost
How Pollora Runs WordPress
Composer installs WordPress core into public/cms, and Pollora loads it while Laravel boots, using your Laravel config and database connection. WordPress still parses each request, so conditional tags like is_single() work as usual, but Laravel renders the response. The admin dashboard at /cms/wp-admin/ works like it does on any WordPress site.
Because both frameworks run together, every web request boots WordPress and its plugins. WordPress core updates go through Composer instead of the dashboard.
Routing on WordPress Conditional Tags
Pollora adds Route::wp() and Route::wpMatch() to the router. They match a request against a WordPress conditional tag such as is_page() or is_single(), and you can use either the function name or a short alias like page:
use App\Http\Controllers\FormController;use App\Models\Feature;use Illuminate\Support\Facades\Route; Route::wp('single', function () { return view('post');}); Route::wp('template', 'landing', function () { return view('page.landing', [ 'features' => Feature::all(), ]);}); Route::wpMatch(['GET', 'POST'], 'page', ['contact', 'request-a-quote'], [FormController::class, 'index']);
You don't need a route for every page. When nothing matches, Pollora follows the WordPress template hierarchy and renders the matching Blade view, so an "About" page uses page-about.blade.php if it exists and falls back to page.blade.php.
Post Types and Hooks as PHP Attributes
Instead of calling register_post_type() in functions.php, you declare a post type as a class. Pollora discovers it and generates the slug and labels from the class name:
namespace App\Cms\PostTypes; use Pollora\Attributes\PostType;use Pollora\Attributes\PostType\HasArchive;use Pollora\Attributes\PostType\MenuIcon;use Pollora\Attributes\PostType\PubliclyQueryable;use Pollora\Attributes\PostType\Supports; #[PostType]#[PubliclyQueryable]#[HasArchive]#[Supports(['title', 'editor', 'thumbnail'])]#[MenuIcon('dashicons-calendar')]class Event{}
Actions and filters work the same way, and a method can listen to more than one hook:
namespace App\Cms\Hooks; use Pollora\Attributes\Action;use Pollora\Attributes\Filter; class ContentHooks{ #[Action('init', priority: 10)] #[Action('wp_loaded', priority: 15)] public function setup(): void { // ... } #[Filter('the_content', priority: 10)] public function filterContent(string $content): string { return str_replace('ugly', 'shiny', $content); }}
Artisan commands like pollora:make:post-type and pollora:make:action generate these classes for you.
Gutenberg Blocks Rendered with Blade
The pollora:make:block command scaffolds a Gutenberg block with a block.json, JSX editor files, and a Blade template:
php artisan pollora:make:block hero-banner --theme
The Blade template renders the block on every request, so a markup change updates every page that uses it. The editor preview comes from the same template, and Pollora builds the block's assets with Vite.
Media on Laravel Storage Disks
Pollora can keep the WordPress media library on any disk in config/filesystems.php. Define the disk, then point Pollora at it in .env:
MEDIA_DISK=mediaMEDIA_URL=https://media.example.com
WordPress keeps using its own upload functions, so plugins like ACF and WooCommerce work without changes. If you're new to S3 disks in Laravel, see using AWS S3 for Laravel storage.
How It Compares
Earlier projects combined Laravel and WordPress in other ways, such as the Themosis framework and Corcel, which reads WordPress tables from a Laravel app. Pollora publishes its own comparison with Acorn, Sage, Radicle, and Corcel:
| Pollora | Acorn | Sage | Radicle | |
|---|---|---|---|---|
| What it is | A Laravel application that runs WordPress | A package that brings Laravel components into WordPress | A WordPress starter theme | A WordPress starter built on the Roots stack |
| Boot order | Laravel first, WordPress inside it | WordPress first, Acorn booted from a theme or plugin | Loaded by WordPress as a theme | WordPress first, with Acorn |
| Post types and hooks | PHP attributes | Theme or plugin code | Theme code | config/post-types.php |
| License and price | MIT, free | MIT, free | MIT, free | One-time purchase |
The comparison suggests Sage for a theme on a standard WordPress install, Acorn for adding Laravel components to an existing site, and Corcel for a Laravel app that only reads WordPress data. It also describes Pollora as a young project, while Acorn and Sage have many more installs.
Installation
You can create a new project with Composer:
composer create-project pollora/pollora my-project
The installation guide covers the requirements, setup, the Pollora CLI, and DDEV. For coding agents, the Nectar package adds Pollora guidelines and MCP tools to Laravel Boost.
Pollora is MIT licensed. You can find the documentation at pollora.dev and the source in the Pollora repository on GitHub.