Skip to content

Modern PHP, zero compromise

v13.39.3 3.3k installs / month

The Laravel framework
for WordPress.

WordPress runs inside a Laravel app: routing, controllers, Blade and Eloquent on the front end, the admin and plugins untouched. PHP 8 attributes and auto-discovery do the registering.

Up and running in one command

Install the CLI, scaffold a project, start building. WordPress + Laravel, ready in under two minutes.

Terminal
$ composer global require pollora/cli && pollora new example-app

What Pollora does

What ships in the box.

pollora/mediaNew in 13.37

Your media library, on any disk.

Sizes declared in PHP. Files stored on S3, R2 or whatever Laravel can reach. WordPress never notices.

pollora/mediaNew in 13.37

Your media library, on any disk.

Sizes declared in PHP. Files stored on S3, R2 or whatever Laravel can reach. WordPress never notices.

01  Declare and sign

Say which sizes you use. Not how to make them.

The URL, the width, the height and the srcset are worked out from the image’s metadata, and rendering a page never touches the disk. The file name carries an HMAC of the original and of the size: change a size, the name changes, and no cache ever holds an old file.

ImageSize::add('card')->cover(600, 400)->webp(75);
ImageSize::add('hero')
    ->scale(width: 1920)->webp(70)
    ->widths([640, 1024, 1440]);
ImageSize::add('thumb')->cover(150, 150)->eager();

WebP by default, AVIF with ->avif(). GD and Imagick write WebP; AVIF depends on the server.

02  Store and serve

One disk. Made on first request, or by a service.

Local, S3, R2, Scaleway, MinIO: WordPress keeps using its own file functions, so Gutenberg, ACF and WooCommerce follow without any adaptation. A size is made the first time its URL is asked for, then served as a plain file for a year. For a huge library, let Bunny or imgproxy do it with signed URLs.

MEDIA_DISK=media
MEDIA_URL=https://media.client.fr

03  Control

Crop where it counts. Lock what is private. Move without fear.

Nine anchors for a cover. Private media get signed URLs that expire, on every size and every srcset source. Moving disks is a dry run until you say --execute.

ImageSize::add('portrait')
    ->cover(400, 500, Anchor::Top);

$ php artisan pollora:media:migrate \
    --from=uploads --to=media --execute

pollora/abilitiesSince 13.34

Your site, operable by AI.

Declare what your site can do. Claude or any MCP client discovers it and calls it, and WordPress still decides who is allowed.

pollora/abilitiesSince 13.34

Your site, operable by AI.

Declare what your site can do. Claude or any MCP client discovers it and calls it, and WordPress still decides who is allowed.

Registered abilities are published over the Model Context Protocol by the MCP Adapter plugin, and by core at /wp-json/wp-abilities/v1/abilities. Permission checks default to refusing: an ability that forgets one is inert, not open.

#[Ability(
    name: 'acme/create-post',
    description: 'Creates a post from a title and a status.',
    category: 'acme-content',
    behaviour: Behaviour::Creates,
)]
final class CreatePost implements AbilityHandler

The difference, line by line

Watch what disappears.

Watch the same post type lose everything that was only glue.

The difference, line by line

Watch what disappears.

Watch the same post type lose everything that was only glue.

The same post type, written for WordPress and written for Pollora: sixteen lines against eight, imports included. Most of the WordPress version carries no decision. Pollora generates the labels from the class name and finds the class on its own: no function, no add_action. What stays is what you decided.

use Pollora\Attributes\PostType;
use Pollora\Attributes\PostType\{HasArchive, PublicPostType, ShowInRest, Supports};

#[PostType('book')]
#[PublicPostType]
#[HasArchive]
#[ShowInRest]
#[Supports(['title', 'editor', 'thumbnail'])]
class Book {}

Blade blocksSince 13.34

One template. Two views.

Dynamic Gutenberg blocks written once, in Blade. The editor previews the real render, and editors write inside it.

Blade blocksSince 13.34

One template. Two views.

Dynamic Gutenberg blocks written once, in Blade. The editor previews the real render, and editors write inside it.

A custom block usually means two renderings of the same markup: a React component for the editor, a PHP template for the page. They drift apart. Pollora renders dynamic blocks with Blade, and where the inner blocks go you write <InnerBlocks />, the tag ACF users already know.

<article {!! get_block_wrapper_attributes(['class' => 'card']) !!}>
    <h3 class="card__title">{{ $attributes['title'] ?? '' }}</h3>

    <InnerBlocks class="card__body" />
</article>

One command scaffolds it: php artisan pollora:make:block card --theme --inner-blocks. The editor view is one line, window.pollora.blocks.bladeEdit(metadata).

Asynchronous actionsSince 13.35.2

Slow work, after the response.

Move a WordPress action to a Laravel queue, Action Scheduler or WP-Cron, with delays and retries.

Asynchronous actionsSince 13.35.2

Slow work, after the response.

Move a WordPress action to a Laravel queue, Action Scheduler or WP-Cron, with delays and retries.

The handler runs after the request. Its arguments travel with the job: a WP_Post, a WP_User or an Eloquent model goes by ID and is reloaded when the handler runs. Remove the attribute and it is synchronous again.

#[Action('save_post_event', priority: 20)]
#[Async(tries: 3, unique: true)]
public function handle(int $postId, CrmClient $crm): void

The default driver, auto, uses the Laravel queue once a connection names a worker, then Action Scheduler, then WP-Cron. pollora:doctor flags what fails silently.

Declare it.
Pollora does the rest.

Everything you need to build WordPress sites with the tooling you already know and love.

All features
PHP 8 Attributes

Declare, don't register

Post types, taxonomies, hooks, REST endpoints, WP-CLI commands, schedules: a class and an attribute. Pollora finds them and registers them for you. No more register_post_type() calls.

#[PostType('product')]#[HasArchive]#[ShowInRest]class Product {}

registered, nothing to call

Post types with attributes
New in 13.37
Fluent roles

Roles, in one chain

Who can do what, written where you read it. A mistake is refused with the call that caused it.

Role::make('event_manager')    ->inherits('author')    ->grantsPostType(Event::class)    ->without('publish_posts');
Roles
Async actions

Slow work, after the response

One call moves a WordPress action to a Laravel queue, Action Scheduler or WP-Cron, with delays and retries.

Action::add('save_post', $handler)
    ->async()
    ->tries(3);
Asynchronous actions
Hybrid Routing

Laravel routes + WordPress fallback

Route::wp() maps WordPress conditions to controllers. Custom routes take priority; the template hierarchy handles the rest.

Route::wp('single', [PostController::class, 'show']);
Route::wp('page', 'contact', [ContactController::class, 'index']);
WordPress routes
Blade + Vite

WordPress data, Laravel syntax, instant reload

Themes in Blade with directives like @posts, @title and @content. Assets through Vite with hot reload and Tailwind CSS v4, no enqueue headaches.

pollora:doctor

Not what is there. Whether it works.

Things that fail silently get named, with the command that fixes them: an ignored attribute, a disk that refuses a file, a binding with no value.

$ php artisan pollora:doctor

  • media disk takes a file
  • asynchronous actions
  • block bindings
  • role declarations
Dashboard and doctor
Block Bindings

Fill core blocks with values computed on the server, from a class.

#[BlockBinding('acme/event',
    label: 'Event', postTypes: 'event')]
final class EventBinding
Block Bindings
Typed meta

A meta is a typed PHP property. Registration, sanitization and the REST schema follow.

#[Meta(showInRest: true)]
public int $capacity = 0;
Typed meta

How it compares

Roots and Corcel opened the way for Laravel in WordPress, and Pollora builds on their work: @roots/vite-plugin, the Bedrock layout, Sage Directives, and a fork of Corcel for its models. What Pollora adds is the inverse arrangement: WordPress running inside a full Laravel application.

Pollora Framework Acorn + Sage Theme toolkit Radicle Starter kit
Approach WordPress inside a Laravel app Laravel components inside WordPress Roots stack starter, Laravel-powered
Post types & hooks PHP 8 attributes, auto-discovered #[PostType('book')] Theme or plugin code Configuration file
Media & images Any Laravel disk, image sizes declared in PHP WordPress uploads and image sizes WordPress uploads and image sizes
Price Free, MIT Free, MIT One-time purchase
  • Pollora Framework
    Approach
    WordPress inside a Laravel app
    Post types & hooks
    PHP 8 attributes, auto-discovered #[PostType('book')]
    Media & images
    Any Laravel disk, image sizes declared in PHP
    Price
    Free, MIT
  • Acorn + Sage Theme toolkit
    Approach
    Laravel components inside WordPress
    Post types & hooks
    Theme or plugin code
    Media & images
    WordPress uploads and image sizes
    Price
    Free, MIT
  • Radicle Starter kit
    Approach
    Roots stack starter, Laravel-powered
    Post types & hooks
    Configuration file
    Media & images
    WordPress uploads and image sizes
    Price
    One-time purchase
Read the full comparison

pollora/nectar

AI-native development

Nectar gives AI coding agents deep context about your Pollora project. Built on Laravel Boost, it provides live introspection via MCP and domain-specific skills for every framework feature. And before you even install, the docs are an MCP server too: your assistant searches and reads them while it answers.

10

MCP tools for live introspection of WordPress, routes, hooks, and components

12

Agent skills for post types, typed meta, hooks, blocks, roles, and more

Compatible with
Claude Code
Cursor
Windsurf
Any MCP-compatible agent
# Your project, live
php artisan nectar:mcp
# The docs, from anywhere
https://pollora.dev/mcp

Three themes, three purposes

Start from a clean Blade default, a conversion-ready WooCommerce storefront, or a magazine built for the Site Editor. pollora:make:theme offers all three.

The default theme's home page: a dark hero, a gradient headline and feature cards

Default Theme

Blade templates, Vite with HMR, Tailwind CSS v4, theme-specific service providers and configuration. The right starting point for any project.

pollora:make:theme my-theme
The Apiary theme's home page: product search, a category menu and a grid of products with sale badges

Apiary WooCommerce

Sticky add-to-cart, search autocomplete, Alpine.js interactivity, responsive product grids, and full checkout override. Built for conversion.

--repository=pollora/theme-apiary
The Buzz theme's home page: a large serif nameplate and a journal index of articles set in Playfair Display

Buzz Full Site Editing

A typographic magazine and a true block theme: templates, parts and patterns edited in the Site Editor, ink-on-paper palette, Playfair Display and Source Serif.

--repository=pollora/theme-buzz

A complete ecosystem

Modular packages that work on their own or together. The core packages power the framework, and work in any WordPress project.

  • Core 17 packages
  • Tool CLI and AI
  • Plugin ready to install

Blog

News from the hive

All posts
Release

Pollora 13.39: WooCommerce and WP Rocket become packages

The framework no longer ships its WooCommerce and WP Rocket integrations: pollora/woocommerce and pollora/wp-rocket carry them. A project that runs either plugin has one command to run, and pollora:doctor tells you when it is missing.

Need a hand?

Work with the team behind Pollora

Pollora is built and maintained by AmphiBee, a WordPress agency that ships WordPress and Laravel projects every day. Bring us a new site, a migration or the plugin your project is missing.

WordPress experts
22
Shipping since
2018
Open-source packages
22
  • New projects A site built on Pollora from day one, from design to production.
  • Migrations From a classic theme, Sage or Acorn to a Laravel application.
  • Plugins and integrations Custom plugins, and WordPress connected to your CRM, ERP or APIs.
  • E-commerce WooCommerce stores built to convert, on the Apiary theme or your own.
Pollora documentation mascot

Documentation

Everything you need, explained

From installation to advanced plugin development — comprehensive guides, API references, and real code examples. Searchable, and AI-ready: llms.txt, a Markdown copy of every page, and an MCP server for your assistant.

Also: FAQ · How it works · Changelog

Start building with Pollora

One command to install. Laravel conventions from day one. WordPress power underneath.

Found a bug? Have an idea?

Open an issue on GitHub. Every report, question and feature request helps shape Pollora.