# Roots Acorn Acorn is a framework that brings the full Laravel ecosystem into WordPress projects. It wraps and extends Laravel's application container, configuration, service providers, routing, view system (Blade), caching, queuing, events, validation, and more — all bootstrapped inside a running WordPress installation. Rather than replacing WordPress, Acorn layers on top of it, so plugin and theme authors can write modern, testable PHP using Laravel patterns while still interoperating with WordPress hooks, templates, and the WP-CLI. The core of Acorn is a custom `Application` class that extends Laravel's `Illuminate\Foundation\Application`, adding WordPress-aware bootstrapping (HTTP, WP-CLI, and console boot paths), a smarter `PackageManifest` that discovers Composer packages from themes and active plugins, WordPress-integrated path resolution (falling back to `WP_CONTENT_DIR/cache/acorn` when no `storage/` directory exists), and a resilient provider system that silently skips broken service providers rather than crashing the entire WordPress request. Acorn also ships its own asset pipeline (`Manifest`, `Bundle`, `Manager`) that understands Bud, Vite, and Laravel Mix manifest formats, a `Composer` base class for passing typed data to Blade views, and a `Sage` integration layer that filters WordPress template selection to use Blade. --- ## `Application::configure()` — Bootstrap the Acorn application The fluent entry point for creating and configuring an Acorn application. Automatically infers the base path from the active WordPress theme, `ACORN_BASEPATH`, or `APP_BASE_PATH` env var. Returns an `ApplicationBuilder` that can be chained to register routing, middleware, providers, and exceptions before calling `boot()` or `create()`. ```php // bootstrap/app.php (inside a Sage theme or WordPress plugin) withRouting( web: __DIR__ . '/../routes/web.php', api: __DIR__ . '/../routes/api.php', wordpress: true, // pass WordPress-rendered responses through Laravel's HTTP kernel ) ->withMiddleware(function (\Roots\Acorn\Configuration\Middleware $middleware) { $middleware->web(append: [ \App\Http\Middleware\HandleWordPressSession::class, ]); }) ->withExceptions(function (\Roots\Acorn\Configuration\Exceptions $exceptions) { $exceptions->report(function (\Illuminate\Validation\ValidationException $e) { // custom reporting for validation failures }); }) ->withProviders([ \App\Providers\AppServiceProvider::class, \App\Providers\AuthServiceProvider::class, ]) ->boot(); // Expected: returns the booted Roots\Acorn\Application instance ``` --- ## `Application::usePaths()` — Override application directory paths Allows the developer to remap any of the nine application directories (`app`, `bootstrap`, `config`, `database`, `lang`, `public`, `resources`, `storage`, `environment`) to absolute paths. Binds all paths into the container and re-resolves `lang` relative to `resources` when appropriate. ```php create(); // Redirect storage to a writable location outside the theme $app->usePaths([ 'storage' => WP_CONTENT_DIR . '/uploads/my-theme/storage', 'resources' => get_template_directory() . '/resources', 'config' => get_template_directory() . '/config', 'public' => get_template_directory() . '/public', ]); // All path helpers now reflect the overrides: // storage_path('framework/views') → .../uploads/my-theme/storage/framework/views // resource_path('views') → .../my-theme/resources/views echo $app->storagePath('logs'); // /var/www/html/wp-content/uploads/my-theme/storage/logs ``` --- ## `ApplicationBuilder::withPaths()` — Configure paths during boot fluently Part of the fluent builder chain returned by `Application::configure()`. Accepts individual named path arguments; unspecified paths fall back to `ACORN_*_PATH` env vars, `ACORN_*_PATH` PHP constants, theme file paths, or sensible defaults. ```php withPaths( storage: WP_CONTENT_DIR . '/cache/my-plugin', config: __DIR__ . '/../config', resources: __DIR__ . '/../resources', public: __DIR__ . '/../public', ) ->withKernels() ->boot(); ``` --- ## `ApplicationBuilder::withRouting()` — Register application routes Extends Laravel's `withRouting()` with a `wordpress: true` flag that registers a catch-all route processed through Laravel's middleware stack, enabling Acorn to intercept, modify, or wrap any WordPress-rendered response using middleware. ```php 'Hello from Acorn']); }); Route::middleware(['auth'])->group(function () { Route::get('/dashboard', [\App\Http\Controllers\DashboardController::class, 'index']); }); // bootstrap/app.php return \Roots\Acorn\Application::configure(basePath: dirname(__DIR__)) ->withRouting( web: __DIR__ . '/../routes/web.php', wordpress: true, // WordPress pages also pass through the HTTP kernel ) ->boot(); ``` --- ## `Roots\view()` — Render a Blade view Global helper (and `Roots\Acorn\View\Component::view()` instance method) that resolves a Blade view by name or falls back to rendering a raw file path. Transparently replaces the standard `view()` Laravel helper, using Acorn's `FileViewFinder` which searches both the theme directory and registered view paths. ```php get_the_title(), 'subtitle' => get_field('subtitle'), // ACF example ]); // Conditionally pass extra data $data = [ 'posts' => get_posts(['post_type' => 'product', 'numberposts' => 6]), 'categories' => get_terms('product_cat'), ]; return \Roots\view('woocommerce.archive', $data); // Expected output: rendered HTML from the Blade template ``` --- ## `Roots\asset()` / `\asset()` — Resolve a versioned asset URL Looks up an asset key in the active `Manifest` (default: `theme`) and returns an `Asset` object whose `__toString()` produces the versioned/cache-busted public URL. Falls back to the raw key if not found in the manifest. The global `asset()` function is available in WordPress templates; the `\Roots\asset()` function is the canonical namespaced version. ```php uri(); // returns the full URI string ``` --- ## `Roots\bundle()` — Enqueue a Bud/Vite/Mix bundle Retrieves a `Bundle` object from the named entrypoint in `entrypoints.json` (Bud) or the equivalent manifest format. `Bundle` exposes `css()` and `js()` collection methods, and an `enqueue()` helper that calls `wp_enqueue_script` / `wp_enqueue_style` directly. ```php enqueue(); // Manual iteration — register each file individually \Roots\bundle('editor')->css(function (string $handle, string $src) { wp_enqueue_style($handle, $src, [], null); }); \Roots\bundle('editor')->js(function (string $handle, string $src, array $deps) { wp_enqueue_script($handle, $src, $deps, null, true); }); // Inline the webpack runtime to avoid extra HTTP requests if ($runtime = \Roots\bundle('app')->runtimeSource()) { wp_add_inline_script('app/app', $runtime, 'before'); } }); ``` --- ## `Composer` — Bind PHP data to Blade views Abstract base class for View Composers. Subclass it inside `app/View/Composers/` and declare which views it serves via the static `$views` property (or rely on auto-detection from the class name). Public properties and public methods are automatically extracted and passed to the view. Override `with()` for explicit data and `override()` to force-overwrite existing view data. ```php 'post', 'numberposts' => 3, 'meta_key' => '_featured', 'meta_value' => '1', ]); } // Override parent's with() for explicit control protected function with(): array { return [ 'posts' => $this->posts(), 'heading' => $this->heading, ]; } // override() data takes precedence over anything the view already has protected function override(): array { return [ 'bodyClass' => 'featured-posts-layout', ]; } } // Register in AppServiceProvider::boot(): // $this->app->make('view')->composer(FeaturedPosts::views(), FeaturedPosts::class); // // In resources/views/partials/featured-posts.blade.php: //