Repository navigation
v13.32.0-beta.7
Pre-release
Pre-release
·
223 commits
to main
since this release
Fixed
pollora:make:blockrefuses a theme or plugin that cannot build a block, and says why. A plugin made without assets has neitherpackage.jsonnorvite.config.js: the block was written anyway, could not be built, and thenpm installthe command advised walked up to the site's ownpackage.jsonand installed there. It now stops before writing anything and names the missing filespollora:make:plugin --assetincludes the asset files. The option takes a value, so the bare flag read as null, which the defaults applied without a terminal turned intofalse:--assetalone left the assets out.--asset=falsestill leaves them out, and the other options keep their defaults- A block title holding a quote (
--title="Owner's Hero") no longer breaks the JavaScriptpollora:make:blockwrites.render.blade.phpescaped it;edit.jsxandsave.jsxprinted it raw inside a single-quoted string, so the block failed to build - A block's editor script depends on every WordPress script its code imports.
BlockRegistrargave each editor script a fixed list —wp-blocks,wp-element,wp-block-editor,wp-i18n— while@roots/vite-pluginturns every@wordpress/*import into a global and records the matching handles ineditor.deps.json. A block importing@wordpress/componentsor@wordpress/server-side-renderworked only when something else happened to load that script. The handles in the build'seditor.deps.jsonare now added to the defaults; in dev mode, which has no build, the defaults stand - Blocks shipped by themes, plugins and modules exist in the block editor, on the page and in the REST API. They were registered by a
BlocksServiceProviderof the module's own, and over HTTP no shape of that provider works: WordPress is loaded, andinithas fired, before theme and plugin providers boot, so the providerpollora:make:blockwrote — hookinginitfromboot()— was never called, and a REST request is answered before those providers boot at all. Blocks existed in WP-CLI only, which is where they had been checked. Measured on a fresh install: theme-default'sheroandcall-to-actionwere missing from the editor and from/wp/v2/block-types. The framework now registers every module'sresources/views/blocks(and the formerresources/blocks) itself oninit, from a hook set while it boots — before WordPress loads — and creates the asset container of a Laravel module that ships blocks.pollora:make:blockno longer writes a provider. ABlocksServiceProviderkept from an earlier release is harmless: a block WordPress already holds is skipped. Covered by browser tests that insert each block in the editor, reload it, and find it on the published page - Themes and plugins keep working on a site whose autoloader was dumped with
--classmap-authoritative. Their namespaces (Theme\…,Plugin\…) were added at runtime to Composer's root loader, and an authoritative loader answers from its classmap alone: it never looked at them, so every front-end page answered 404 (Class "Theme\Apiary\Walkers\MenuPrimary" not found) whilewp-login.phpstill worked. Module namespaces now live in a class loader of their own, registered after Composer's, and shared by the theme and plugin autoloaders under theModuleAutoloader::CLASS_LOADERcontainer key. It has no vendor directory, so it stays out ofClassLoader::getRegisteredLoaders()and cannot moveApplication::inferBasePath(). Measured on a live site in both modes: pages, the PHPUnit and HTTP suites, and the theme sweep all pass. The root loader is no longer bound toComposer\Autoload\ClassLoaderin the container as a side effect php artisan test, and anything else that asks Laravel for its base path, no longer resolves it to a plugin's directory.ModuleAutoloader::register()registered the root Composer loader again although it was already active, and Composer answers that by moving it to the end ofClassLoader::getRegisteredLoaders()— behind the loader of any plugin shipping its ownvendor/, such as Query Monitor.Application::inferBasePath()reads the first entry of that list, so on such a site 38 of 40 of its PHPUnit tests failed openingplugins/query-monitor/bootstrap/app.php. Composer'sInstalledVersions::getRootPackage()read the same list and reported the plugin as the root package, over HTTP, in artisan and in WP-CLI. Namespaces added withaddPsr4()take effect on an active loader, so the loader is now only registered when it is not already. The bug dates back to June 2025 and shipped in v13.4.4patches/mockery-php84-nullable.patchis back onmain, byte for byte as v13.4.4 shipped it. The v13.4.x line declares that patch by the URLrefs/heads/main/patches/mockery-php84-nullable.patch, and a releasedcomposer.jsoncannot change; removing the file frommainon 2026-09-17 made the URL answer 404, and composer-patches v1 skips a patch it cannot fetch with only a warning — so every v13.4.x install since went without it. Nothing on the 13.32 line references the file: its patch URLs are pinned to commits- The patches this package asks its consumers to apply are pinned to the commit that produced them, instead of being served from
refs/heads/main. A releasedcomposer.jsoncannot be changed, so a branch URL moves under every version already published: removingmockery-php84-nullable.patchfrommainon 2026-09-17 turned it into a 404 for every v13.4.x install, which composer-patches v1 skips with only a warning. With composer-patches v2 a moved patch is worse — its checksum no longer matchespatches.lock.jsonand the install fails. A Patches CI job now proves each URL pins a commit in the branch's history whose file matches the working tree. Versions already released keep the URLs they shipped with - Generators write a theme's, plugin's or module's classes where its autoloader reads them. The autoloaders map a namespace onto
app/when it exists and ontosrc/otherwise — one directory, never both — while every--plugin,--themeand--modulegenerator wrote intoapp/unconditionally. On a target keeping its classes insrc/, that was worse than one misplaced file: creatingapp/flipped the autoloader and discovery over to it, and every class already insrc/stopped being loaded. They now resolve the directory with the autoloaders' own precedence, and a target with neither still getsapp/ - The
BlocksServiceProviderthe scaffolder writes registers its blocks oninit, which is when WordPress accepts block registrations at all. It calledregisterDirectory()straight fromboot(), and providers boot before WordPress has definedregister_block_type()—BlockRegistraranswers that by returning immediately, with no error and no notice, so the blocks simply never existed.theme-defaulthit this, shipped v1.4.0 with it, and fixed its own copy by hand; the stub that writes every other provider kept the broken shape, so each new theme and plugin was born with the bug pollora:make:blockwrites theBlocksServiceProviderwhen the target has none. A blocks directory that is not empty was taken as proof that the infrastructure was in place, and it usually is — but blocks registered by something else live there too, and none of them needs the provider that registers Vite-built blocks. In a target liketheme-apiary, whose only shipped block is an ACF one, every block ever scaffolded was written to disk, built by Vite, and registered by nobody: nothing failed, nothing reached the log, and the block simply never appeared in the editor — permanently, since the directory only gets less empty. Measured on a live site, then pinned end to end in the theme's CI. Only the provider is created; the npm dependencies and the initial Vite patch still belong to a genuinely first blockcomposer installandcomposer updateno longer fail on a Pollora site that has no terminal.pollora:env:setupruns from composer'spost-autoload-dumphook, so it fires inside container builds, deployments and CI; when the database was not reachable it reached for Laravel Prompts, which throws where there is nothing to prompt, and composer exited 1 reporting a prompting problem rather than a database one. Nothing in that command is a gate —pollora:installis what refuses to continue without a database — so with no terminal it now names what is wrong, names the command to run once the database is up, and lets composer finish
Changed
- The block editor shows what the page shows for a block made by
pollora:make:block. A dynamic block'sedit.jsxrendersrender.blade.phpthroughServerSideRenderfor the block's current attributes, and a static block's mirrors the markupsave.jsxwrites; both used to show a placeholder ("… – Block Editor") the page never displayed. A block with--inner-blockskeeps theInnerBlockseditor, which a server render cannot provide.@wordpress/server-side-renderjoins the npm dependencies added with a first block. Checked in a browser: the preview holds the rendered text, and the old stub fails the same test cweagans/composer-patchesmoves from^1.7to^2.0. It is the plugin that applies the WordPress l10n patch — renaming WordPress's__()to__wp()so Laravel's helper can have the name — on every Pollora site. Measured before merging: on a fresh install, v2 resolves the framework's patch as a dependency patch and applies it, and the skeleton's check that WordPress core carries it passes. Two things change for a project. v2 writes apatches.lock.jsonrecording each patch's sha256, and on a machine without the patch cached it downloads the patch again and fails withHashMismatchExceptionwhen the file no longer matches — so a patch served from a moving URL can break fresh installs of a project that locked an earlier version. And the skeleton'senable-patchingoption is no longer read: v1.7.3 checked it and defaulted to off, v2 resolves dependency patches unconditionally- The commit-hook tooling is declared where it belongs.
@commitlint/cli,@commitlint/config-conventional,husky,lint-stagedandprettiersat underdependenciesrather thandevDependencies, so every advisory in their tree was reported against this repository at runtime scope — ten high-severity alerts describing packages no Pollora site has ever loaded. Nothing installs differently:npm ciinstalls devDependencies by default, and the commit hook was checked after the move - Every open npm advisory clears:
fast-urimoves to 3.1.8 andjs-yamlto 4.3.2, past the 3.1.6 and 4.3.2 that patch them.npm auditgoes from 2 high-severity vulnerabilities to 0 - The contribution guide documents the pull request title convention. CI validates the title of every pull request against the conventional commit format, and rejected one said only that the check had failed — a rule enforced on a first contribution and published nowhere. The allowed types are listed, along with the fact that Validate Changelog only runs on release pull requests into
mainand never concerns a contribution todevelop