From a3e123a2ebaec74017a741d43f1768fc23412db9 Mon Sep 17 00:00:00 2001 From: Olivier Gorzalka Date: Fri, 2 Oct 2026 17:13:17 +0200 Subject: [PATCH 1/2] docs: the skeleton answers 404 for content directories --- server-configuration.md | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/server-configuration.md b/server-configuration.md index 6448bc5..662e828 100644 --- a/server-configuration.md +++ b/server-configuration.md @@ -47,34 +47,21 @@ The fix is to ensure your web server **never resolves `DirectoryIndex`** for the ### Apache Configuration -The default `.htaccess` shipped with Pollora includes `Options -Indexes` to disable directory listing. To also prevent blank 200 responses from `index.php` files inside directories, add the following rule **before** the "Send Requests To Front Controller" block: +Since v13.34.1, the `.htaccess` shipped with the skeleton (`public/.htaccess`) sends these requests to the front controller, which answers with your site's own 404 page. A project created before that can add the same rule, **before** the "Redirect Trailing Slashes" block: ```apache - - Options -MultiViews -Indexes - - RewriteEngine On - - # Block direct directory browsing. - # All directory requests go through the framework (returns 404), - # except wp-admin which needs DirectoryIndex for its own index.php. - RewriteCond %{REQUEST_FILENAME} -d - RewriteCond %{REQUEST_URI} !^/cms/wp-admin - RewriteCond %{REQUEST_URI} !^/$ - RewriteRule ^ index.php [L] - - # Send Requests To Front Controller... - RewriteCond %{REQUEST_FILENAME} !-d - RewriteCond %{REQUEST_FILENAME} !-f - RewriteRule ^ index.php [L] - + # WordPress Content Directories Are Not Pages... + RewriteCond %{REQUEST_FILENAME} -d [OR] + RewriteCond %{REQUEST_FILENAME} /index\.php$ + RewriteRule ^(cms/wp-content|content)(/|$) index.php [L] ``` This ensures that: -- **Files** (CSS, JS, images, fonts) are served directly by Apache -- **Directories** are routed through the framework, which returns 404 -- **`/cms/wp-admin`** is excluded so WordPress admin works normally -- **`/`** (root) is excluded so the front controller's `index.php` is resolved +- **Directories** under `/cms/wp-content/` and `/content/` — and the empty `index.php` WordPress ships in some of them — answer your site's 404 instead of a blank 200 or a 403 +- **Files** in them (plugin CSS and JS, uploads, fonts) are served directly by Apache, as before +- **The rest of the site** is untouched: `/cms/wp-admin/` and the front controller keep their `index.php` + +`Options -Indexes`, also in the shipped `.htaccess`, keeps directory listing off everywhere else. ### Nginx Configuration From ee2cc64e478d2e1d3c7918520f9a2beca2cf1340 Mon Sep 17 00:00:00 2001 From: Olivier Gorzalka Date: Fri, 2 Oct 2026 18:15:08 +0200 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20v13.34.1=20=E2=80=94=20template=20e?= =?UTF-8?q?nhancement=20middleware,=20current=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dashboard.md | 8 ++++---- getting-started.md | 4 ++-- middleware.md | 15 +++++++++++++++ modules.md | 4 ++-- routing.md | 1 + 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/dashboard.md b/dashboard.md index 21322d1..87f012c 100644 --- a/dashboard.md +++ b/dashboard.md @@ -43,7 +43,7 @@ php artisan pollora:status Example output: ``` -Pollora v13.34.0 (latest: v13.34.0) ✓ +Pollora v13.34.1 (latest: v13.34.1) ✓ PHP 8.4.12 | Laravel 13.34 | WordPress 7.1 @@ -86,8 +86,8 @@ This outputs the complete system information as a JSON object: ```json { "framework": { - "current": "13.34.0", - "latest": "13.34.0", + "current": "13.34.1", + "latest": "13.34.1", "update_available": false, "development": false }, @@ -122,7 +122,7 @@ This outputs the complete system information as a JSON object: When running a dev branch (`dev-develop`, `13.x-dev`, etc.), the command adapts its output: ``` -Pollora dev-develop (latest stable: v13.34.0) +Pollora dev-develop (latest stable: v13.34.1) ``` No misleading "update available" warning is shown for development installations: `development` is `true` in the JSON output, and Site Health reports a development build instead of comparing it with releases. diff --git a/getting-started.md b/getting-started.md index 3648984..6a3e874 100644 --- a/getting-started.md +++ b/getting-started.md @@ -22,7 +22,7 @@ number in its `composer.lock` — which is what `create-project` installs from, whatever constraint the `composer.json` carries. So one version number describes an install completely. -The current release is **v13.34.0**, a stable release: a plain +The current release is **v13.34.1**, a stable release: a plain `composer create-project pollora/pollora` installs it. ## Installation Methods @@ -67,7 +67,7 @@ With `--ddev`, the CLI configures DDEV (WordPress project type, PHP 8.4, MariaDB | `--ver=VERSION` | Install a specific version or constraint (e.g. `13.34.0`, `^13.34`) | | `--stable` | Install the latest stable release instead of the latest pre-release | -`pollora new` installs the latest release **including pre-releases**: today that is the stable v13.34.0, and a beta published after it would be picked up. Pass `--stable` to never get a pre-release, or `--ver` to pin an exact version. +`pollora new` installs the latest release **including pre-releases**: today that is the stable v13.34.1, and a beta published after it would be picked up. Pass `--stable` to never get a pre-release, or `--ver` to pin an exact version. ### 2. Composer create-project diff --git a/middleware.md b/middleware.md index 2f8baa7..76ad421 100644 --- a/middleware.md +++ b/middleware.md @@ -38,6 +38,21 @@ A route WordPress answers — `Route::wp()` and the template-hierarchy fallback Ensures WordPress shutdown hooks (`shutdown` action, output buffer flushing) are properly executed after the Laravel response is sent. +### WordPressTemplateEnhancement + +Gives a Blade page what WordPress gives a template it includes: its **template enhancement output buffer**. WordPress 7 relies on it for classic themes — block styles load on demand, are printed at `wp_footer` once the page's blocks are known, then are moved back into the `` with `global-styles` through the `wp_template_enhancement_output_buffer` filter. Without it, those styles end up at the bottom of the page, after the content they style. + +The middleware fires `wp_template_enhancement_output_buffer_started` before the view renders, then runs the filter and the `wp_finalized_template_enhancement_output_buffer` action on the HTML of the response. Any plugin built on that filter sees Pollora's pages too. JSON, redirects and streamed responses are left alone, and a site that opted out through `wp_should_output_buffer_template_for_enhancement` keeps its responses as they are. Since v13.34.1. + +A plain Laravel route does not get it. If its view prints `wp_head()` and `wp_footer()`, add the middleware yourself: + +```php +use Pollora\Route\Infrastructure\Middleware\WordPressTemplateEnhancement; + +Route::get('/dashboard', DashboardController::class) + ->middleware(WordPressTemplateEnhancement::class); +``` + ## Creating Custom Middleware Use Artisan to generate a new middleware: diff --git a/modules.md b/modules.md index fe155b1..4479cc4 100644 --- a/modules.md +++ b/modules.md @@ -87,7 +87,7 @@ Each module can have its own dependencies defined in `composer.json`, but actual This approach ensures coherent, centralized package management while maintaining modular flexibility. -A module's `require` is merged; its `require-dev` is not (`merge-dev: false`). A module installed with Composer is merged too, and its development tools (PHPUnit, Rector…) would otherwise become requirements of the project: the next `composer install` then removed WordPress core from `public/cms`. Development dependencies belong in the project's own `require-dev`. The skeleton sets it after v13.34.0; an older project adds it to `extra.merge-plugin`. +A module's `require` is merged; its `require-dev` is not (`merge-dev: false`). A module installed with Composer is merged too, and its development tools (PHPUnit, Rector…) would otherwise become requirements of the project: the next `composer install` then removed WordPress core from `public/cms`. Development dependencies belong in the project's own `require-dev`. The skeleton sets it since v13.34.1; an older project adds it to `extra.merge-plugin`. ## Installing a Module with Composer @@ -112,7 +112,7 @@ The skeleton routes it there with one `installer-paths` rule, handled by `compos - **The rule must come last.** `composer/installers` applies the first rule that matches, and a `vendor:` rule ignores the package type: placed first, it would also send Pollora's WordPress plugins (`pollora/mcp-connector`, `pollora/ai-visibility`) to `Modules/`. Last, it only catches what the rules above did not, which are the `pollora/*` modules of type `laravel-library`; Pollora's other packages (`library`, `project`) are not handled by `composer/installers` and stay in `vendor/`. - **A module from another vendor needs its own line**, for instance `"Modules/{$name}/": ["vendor:pollora", "vendor:acme"]`. The rule does not target `type:laravel-library` alone: dozens of ordinary Laravel packages declare that type and would land in `Modules/`. -- The skeleton ships this rule after v13.34.0. A project created from v13.34.0 or earlier adds it to its `composer.json`, last, and `"merge-dev": false` to `extra.merge-plugin` (see Dependency Management). +- The skeleton ships this rule since v13.34.1. A project created from v13.34.0 or earlier adds it to its `composer.json`, last, and `"merge-dev": false` to `extra.merge-plugin` (see Dependency Management). ### Publishing a module diff --git a/routing.md b/routing.md index 0c955b5..693c432 100644 --- a/routing.md +++ b/routing.md @@ -104,6 +104,7 @@ There are two main methods to define routes in your application: - `WordPressBindings`: Adds WordPress objects (post, query) to the route - `WordPressHeaders`: Manages HTTP headers for WordPress responses - `WordPressShutdown`: Runs WordPress's shutdown hooks before the response is sent + - `WordPressTemplateEnhancement`: Runs WordPress's template enhancement filter on the page, which moves block styles into the `` - WordPress's body classes and `is_404()` are left as WordPress resolved them; only routes WordPress does not answer are adjusted (see [Middleware](middleware.md#body-classes-on-laravel-routes)) - They are processed through WordPress's conditional logic - `Route::wp()` accepts all HTTP verbs